mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-10-15 07:22:46 +00:00
SD/MMC patches
- Convert legacy SD host controller to the SDBus API - Move legacy API to a separate "sdcard_legacy.h" header - Introduce methods to access multiple bytes on SDBus data lines - Fix 'switch function' group location - Fix SDSC maximum card size (2GB) CI jobs result: https://gitlab.com/philmd/qemu/-/pipelines/180605963 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl9ABBYACgkQ4+MsLN6t wN4vng/8DEiJcb6RyjXXRbY6dY+k1mPRbUCCdkkSL/20OUF7edu8FXVO/YtTemky /rUbG8xa/WqxLXg5TqHkmJAHbQYjPu3YfakMTaNKAQfmAukepsqaWO4T2ROKtBNf Muj5X0idTnMSHYNLyJ9O59FiaGMmXN/1eWYkd6QcGl5IVyQQws1Sn/2Mwm4sXinU jkLzYSiibho/y9Y18MzvgD22/Z4dcRmdyCenHYaVAZVOJ1DNKNpJg0nem13lva8/ 9kZbtjV0WuGX+QkNd5KUSpJQEjemRuABsPSwu+MIA/1AWDhoowAITUbMba5GpRmT uIylUiVpVyJAD545UB5rVMlBb86hBEp/4cpxpZ8J05qd1L8Ko/F3ECUj1WrteqK7 Wf6p4ZtF+unGELwk/7tu9o9MiEIU5Lb8IN2cr68gQ2p50rxR1ABkJo4K7FqR9Lvk QkmfqAJRl/dSvh9ChDE/xRMewYm69FE7MGpg4JaeW6KZ4CTX0JwWy9LSpdjQf5AG uhHqGTjiZkn9kzIGMIYaRuKDqYQcnslQpKxd0lRKNMw775LI/0L3MBIc1zfLA/Sb uUHdADDUibQaXaTHVgkyJDU96i3STkehEhbTejo36i+Qevd6bE8j3yDu483Kt2aV AStMJpW+8Iuq7T2hIRaggqhcuwCIsknKU3yhvV7rwAgHxnwy4Nc= =Pefc -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/sd-next-20200821' into staging SD/MMC patches - Convert legacy SD host controller to the SDBus API - Move legacy API to a separate "sdcard_legacy.h" header - Introduce methods to access multiple bytes on SDBus data lines - Fix 'switch function' group location - Fix SDSC maximum card size (2GB) CI jobs result: https://gitlab.com/philmd/qemu/-/pipelines/180605963 # gpg: Signature made Fri 21 Aug 2020 18:27:50 BST # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/sd-next-20200821: (23 commits) hw/sd: Correct the maximum size of a Standard Capacity SD Memory Card hw/sd: Fix incorrect populated function switch status data structure hw/sd: Use sdbus_read_data() instead of sdbus_read_byte() when possible hw/sd: Add sdbus_read_data() to read multiples bytes on the data line hw/sd: Use sdbus_write_data() instead of sdbus_write_byte when possible hw/sd: Add sdbus_write_data() to write multiples bytes on the data line hw/sd: Rename sdbus_read_data() as sdbus_read_byte() hw/sd: Rename sdbus_write_data() as sdbus_write_byte() hw/sd: Rename read/write_data() as read/write_byte() hw/sd: Move sdcard legacy API to 'hw/sd/sdcard_legacy.h' hw/sd/sdcard: Make sd_data_ready() static hw/sd/pl181: Replace disabled fprintf()s by trace events hw/sd/pl181: Do not create SD card within the SD host controller hw/sd/pl181: Expose a SDBus and connect the SDCard to it hw/sd/pl181: Use named GPIOs hw/sd/pl181: Add TODO to use Fifo32 API hw/sd/pl181: Rename pl181_send_command() as pl181_do_command() hw/sd/pl181: Replace fprintf(stderr, "*\n") with error_report() hw/sd/milkymist: Do not create SD card within the SD host controller hw/sd/milkymist: Create the SDBus at init() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d7df0ceee0
|
@ -25,6 +25,7 @@
|
||||||
#include "hw/char/pl011.h"
|
#include "hw/char/pl011.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
|
|
||||||
#define TYPE_INTEGRATOR_CM "integrator_core"
|
#define TYPE_INTEGRATOR_CM "integrator_core"
|
||||||
#define INTEGRATOR_CM(obj) \
|
#define INTEGRATOR_CM(obj) \
|
||||||
|
@ -595,6 +596,7 @@ static void integratorcp_init(MachineState *machine)
|
||||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||||
qemu_irq pic[32];
|
qemu_irq pic[32];
|
||||||
DeviceState *dev, *sic, *icp;
|
DeviceState *dev, *sic, *icp;
|
||||||
|
DriveInfo *dinfo;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
cpuobj = object_new(machine->cpu_type);
|
cpuobj = object_new(machine->cpu_type);
|
||||||
|
@ -645,10 +647,21 @@ static void integratorcp_init(MachineState *machine)
|
||||||
sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
|
sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
|
||||||
|
|
||||||
dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
|
dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
|
||||||
qdev_connect_gpio_out(dev, 0,
|
qdev_connect_gpio_out_named(dev, "card-read-only", 0,
|
||||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
|
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
|
||||||
qdev_connect_gpio_out(dev, 1,
|
qdev_connect_gpio_out_named(dev, "card-inserted", 0,
|
||||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
|
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
|
||||||
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
sysbus_create_varargs("pl041", 0x1d000000, pic[25], NULL);
|
sysbus_create_varargs("pl041", 0x1d000000, pic[25], NULL);
|
||||||
|
|
||||||
if (nd_table[0].used)
|
if (nd_table[0].used)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "hw/ssi/ssi.h"
|
#include "hw/ssi/ssi.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
#include "chardev/char-fe.h"
|
#include "chardev/char-fe.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "sysemu/qtest.h"
|
#include "sysemu/qtest.h"
|
||||||
|
@ -2136,15 +2137,24 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||||
|
|
||||||
s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
|
s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
|
||||||
|
|
||||||
dinfo = drive_get(IF_SD, 0, 0);
|
|
||||||
if (!dinfo && !qtest_enabled()) {
|
|
||||||
warn_report("missing SecureDigital device");
|
|
||||||
}
|
|
||||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
||||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
|
||||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
||||||
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
||||||
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
||||||
|
dinfo = drive_get(IF_SD, 0, 0);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *carddev;
|
||||||
|
|
||||||
|
/* Create and plug in the sd card */
|
||||||
|
carddev = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(carddev, "drive",
|
||||||
|
blk_by_legacy_dinfo(dinfo), &error_fatal);
|
||||||
|
qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
|
||||||
|
"sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
} else if (!qtest_enabled()) {
|
||||||
|
warn_report("missing SecureDigital device");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; pxa270_serial[i].io_base; i++) {
|
for (i = 0; pxa270_serial[i].io_base; i++) {
|
||||||
if (serial_hd(i)) {
|
if (serial_hd(i)) {
|
||||||
|
@ -2260,15 +2270,24 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
||||||
|
|
||||||
s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
|
s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
|
||||||
|
|
||||||
dinfo = drive_get(IF_SD, 0, 0);
|
|
||||||
if (!dinfo && !qtest_enabled()) {
|
|
||||||
warn_report("missing SecureDigital device");
|
|
||||||
}
|
|
||||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
||||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
|
||||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
||||||
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
||||||
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
||||||
|
dinfo = drive_get(IF_SD, 0, 0);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *carddev;
|
||||||
|
|
||||||
|
/* Create and plug in the sd card */
|
||||||
|
carddev = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(carddev, "drive",
|
||||||
|
blk_by_legacy_dinfo(dinfo), &error_fatal);
|
||||||
|
qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
|
||||||
|
"sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
} else if (!qtest_enabled()) {
|
||||||
|
warn_report("missing SecureDigital device");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; pxa255_serial[i].io_base; i++) {
|
for (i = 0; pxa255_serial[i].io_base; i++) {
|
||||||
if (serial_hd(i)) {
|
if (serial_hd(i)) {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "hw/intc/realview_gic.h"
|
#include "hw/intc/realview_gic.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/i2c/arm_sbcon_i2c.h"
|
#include "hw/i2c/arm_sbcon_i2c.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
|
|
||||||
#define SMP_BOOT_ADDR 0xe0000000
|
#define SMP_BOOT_ADDR 0xe0000000
|
||||||
#define SMP_BOOTREG_ADDR 0x10000030
|
#define SMP_BOOTREG_ADDR 0x10000030
|
||||||
|
@ -69,6 +70,7 @@ static void realview_init(MachineState *machine,
|
||||||
qemu_irq mmc_irq[2];
|
qemu_irq mmc_irq[2];
|
||||||
PCIBus *pci_bus = NULL;
|
PCIBus *pci_bus = NULL;
|
||||||
NICInfo *nd;
|
NICInfo *nd;
|
||||||
|
DriveInfo *dinfo;
|
||||||
I2CBus *i2c;
|
I2CBus *i2c;
|
||||||
int n;
|
int n;
|
||||||
unsigned int smp_cpus = machine->smp.cpus;
|
unsigned int smp_cpus = machine->smp.cpus;
|
||||||
|
@ -234,8 +236,18 @@ static void realview_init(MachineState *machine,
|
||||||
mmc_irq[1] = qemu_irq_split(
|
mmc_irq[1] = qemu_irq_split(
|
||||||
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
|
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
|
||||||
qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
|
qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
|
||||||
qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
|
qdev_connect_gpio_out_named(dev, "card-read-only", 0, mmc_irq[0]);
|
||||||
qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
|
qdev_connect_gpio_out_named(dev, "card-inserted", 0, mmc_irq[1]);
|
||||||
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
sysbus_create_simple("pl031", 0x10017000, pic[10]);
|
sysbus_create_simple("pl031", 0x10017000, pic[10]);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "hw/block/flash.h"
|
#include "hw/block/flash.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/char/pl011.h"
|
#include "hw/char/pl011.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
|
|
||||||
#define VERSATILE_FLASH_ADDR 0x34000000
|
#define VERSATILE_FLASH_ADDR 0x34000000
|
||||||
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
||||||
|
@ -309,8 +310,29 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||||
/* Wire up the mux control signals from the SYS_CLCD register */
|
/* Wire up the mux control signals from the SYS_CLCD register */
|
||||||
qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
|
qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
|
||||||
|
|
||||||
sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
|
dev = sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
|
||||||
sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
|
||||||
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add PL031 Real Time Clock. */
|
/* Add PL031 Real Time Clock. */
|
||||||
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
|
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "hw/cpu/a9mpcore.h"
|
#include "hw/cpu/a9mpcore.h"
|
||||||
#include "hw/cpu/a15mpcore.h"
|
#include "hw/cpu/a15mpcore.h"
|
||||||
#include "hw/i2c/arm_sbcon_i2c.h"
|
#include "hw/i2c/arm_sbcon_i2c.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
|
|
||||||
#define VEXPRESS_BOARD_ID 0x8e0
|
#define VEXPRESS_BOARD_ID 0x8e0
|
||||||
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
|
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
|
||||||
|
@ -624,10 +625,20 @@ static void vexpress_common_init(MachineState *machine)
|
||||||
|
|
||||||
dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
|
dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
|
||||||
/* Wire up MMC card detect and read-only signals */
|
/* Wire up MMC card detect and read-only signals */
|
||||||
qdev_connect_gpio_out(dev, 0,
|
qdev_connect_gpio_out_named(dev, "card-read-only", 0,
|
||||||
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
|
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
|
||||||
qdev_connect_gpio_out(dev, 1,
|
qdev_connect_gpio_out_named(dev, "card-inserted", 0,
|
||||||
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
|
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
|
||||||
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
|
sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
|
||||||
sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
|
sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
|
||||||
|
|
|
@ -31,17 +31,6 @@ static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline DeviceState *milkymist_memcard_create(hwaddr base)
|
|
||||||
{
|
|
||||||
DeviceState *dev;
|
|
||||||
|
|
||||||
dev = qdev_new("milkymist-memcard");
|
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
|
||||||
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline DeviceState *milkymist_vgafb_create(hwaddr base,
|
static inline DeviceState *milkymist_vgafb_create(hwaddr base,
|
||||||
uint32_t fb_offset, uint32_t fb_mask)
|
uint32_t fb_offset, uint32_t fb_mask)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "milkymist-hw.h"
|
#include "milkymist-hw.h"
|
||||||
#include "hw/display/milkymist_tmu2.h"
|
#include "hw/display/milkymist_tmu2.h"
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
#include "lm32.h"
|
#include "lm32.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
|
@ -80,6 +81,29 @@ static void main_cpu_reset(void *opaque)
|
||||||
env->deba = reset_info->flash_base;
|
env->deba = reset_info->flash_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DeviceState *milkymist_memcard_create(hwaddr base)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
DriveInfo *dinfo;
|
||||||
|
|
||||||
|
dev = qdev_new("milkymist-memcard");
|
||||||
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||||
|
|
||||||
|
dinfo = drive_get_next(IF_SD);
|
||||||
|
if (dinfo) {
|
||||||
|
DeviceState *card;
|
||||||
|
|
||||||
|
card = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
milkymist_init(MachineState *machine)
|
milkymist_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
|
|
|
@ -333,16 +333,11 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
cpu_physical_memory_read((desc->addr & DESC_SIZE_MASK) + num_done,
|
cpu_physical_memory_read((desc->addr & DESC_SIZE_MASK) + num_done,
|
||||||
buf, buf_bytes);
|
buf, buf_bytes);
|
||||||
|
sdbus_write_data(&s->sdbus, buf, buf_bytes);
|
||||||
for (uint32_t i = 0; i < buf_bytes; i++) {
|
|
||||||
sdbus_write_data(&s->sdbus, buf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read from SD bus */
|
/* Read from SD bus */
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 0; i < buf_bytes; i++) {
|
sdbus_read_data(&s->sdbus, buf, buf_bytes);
|
||||||
buf[i] = sdbus_read_data(&s->sdbus);
|
|
||||||
}
|
|
||||||
cpu_physical_memory_write((desc->addr & DESC_SIZE_MASK) + num_done,
|
cpu_physical_memory_write((desc->addr & DESC_SIZE_MASK) + num_done,
|
||||||
buf, buf_bytes);
|
buf, buf_bytes);
|
||||||
}
|
}
|
||||||
|
@ -521,10 +516,8 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
|
||||||
break;
|
break;
|
||||||
case REG_SD_FIFO: /* Read/Write FIFO */
|
case REG_SD_FIFO: /* Read/Write FIFO */
|
||||||
if (sdbus_data_ready(&s->sdbus)) {
|
if (sdbus_data_ready(&s->sdbus)) {
|
||||||
res = sdbus_read_data(&s->sdbus);
|
sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t));
|
||||||
res |= sdbus_read_data(&s->sdbus) << 8;
|
le32_to_cpus(&res);
|
||||||
res |= sdbus_read_data(&s->sdbus) << 16;
|
|
||||||
res |= sdbus_read_data(&s->sdbus) << 24;
|
|
||||||
allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t));
|
allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t));
|
||||||
allwinner_sdhost_auto_stop(s);
|
allwinner_sdhost_auto_stop(s);
|
||||||
allwinner_sdhost_update_irq(s);
|
allwinner_sdhost_update_irq(s);
|
||||||
|
@ -548,6 +541,7 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
AwSdHostState *s = AW_SDHOST(opaque);
|
AwSdHostState *s = AW_SDHOST(opaque);
|
||||||
|
uint32_t u32;
|
||||||
|
|
||||||
trace_allwinner_sdhost_write(offset, value, size);
|
trace_allwinner_sdhost_write(offset, value, size);
|
||||||
|
|
||||||
|
@ -654,11 +648,9 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
|
||||||
s->startbit_detect = value;
|
s->startbit_detect = value;
|
||||||
break;
|
break;
|
||||||
case REG_SD_FIFO: /* Read/Write FIFO */
|
case REG_SD_FIFO: /* Read/Write FIFO */
|
||||||
sdbus_write_data(&s->sdbus, value & 0xff);
|
u32 = cpu_to_le32(value);
|
||||||
sdbus_write_data(&s->sdbus, (value >> 8) & 0xff);
|
sdbus_write_data(&s->sdbus, &u32, sizeof(u32));
|
||||||
sdbus_write_data(&s->sdbus, (value >> 16) & 0xff);
|
allwinner_sdhost_update_transfer_cnt(s, sizeof(u32));
|
||||||
sdbus_write_data(&s->sdbus, (value >> 24) & 0xff);
|
|
||||||
allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t));
|
|
||||||
allwinner_sdhost_auto_stop(s);
|
allwinner_sdhost_auto_stop(s);
|
||||||
allwinner_sdhost_update_irq(s);
|
allwinner_sdhost_update_irq(s);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -190,7 +190,7 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s)
|
||||||
if (is_read) {
|
if (is_read) {
|
||||||
n = 0;
|
n = 0;
|
||||||
while (s->datacnt && s->fifo_len < BCM2835_SDHOST_FIFO_LEN) {
|
while (s->datacnt && s->fifo_len < BCM2835_SDHOST_FIFO_LEN) {
|
||||||
value |= (uint32_t)sdbus_read_data(&s->sdbus) << (n * 8);
|
value |= (uint32_t)sdbus_read_byte(&s->sdbus) << (n * 8);
|
||||||
s->datacnt--;
|
s->datacnt--;
|
||||||
n++;
|
n++;
|
||||||
if (n == 4) {
|
if (n == 4) {
|
||||||
|
@ -223,7 +223,7 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s)
|
||||||
}
|
}
|
||||||
n--;
|
n--;
|
||||||
s->datacnt--;
|
s->datacnt--;
|
||||||
sdbus_write_data(&s->sdbus, value & 0xff);
|
sdbus_write_byte(&s->sdbus, value & 0xff);
|
||||||
value >>= 8;
|
value >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
38
hw/sd/core.c
38
hw/sd/core.c
|
@ -102,7 +102,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdbus_write_data(SDBus *sdbus, uint8_t value)
|
void sdbus_write_byte(SDBus *sdbus, uint8_t value)
|
||||||
{
|
{
|
||||||
SDState *card = get_card(sdbus);
|
SDState *card = get_card(sdbus);
|
||||||
|
|
||||||
|
@ -110,11 +110,26 @@ void sdbus_write_data(SDBus *sdbus, uint8_t value)
|
||||||
if (card) {
|
if (card) {
|
||||||
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
||||||
|
|
||||||
sc->write_data(card, value);
|
sc->write_byte(card, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sdbus_read_data(SDBus *sdbus)
|
void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length)
|
||||||
|
{
|
||||||
|
SDState *card = get_card(sdbus);
|
||||||
|
const uint8_t *data = buf;
|
||||||
|
|
||||||
|
if (card) {
|
||||||
|
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
trace_sdbus_write(sdbus_name(sdbus), data[i]);
|
||||||
|
sc->write_byte(card, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sdbus_read_byte(SDBus *sdbus)
|
||||||
{
|
{
|
||||||
SDState *card = get_card(sdbus);
|
SDState *card = get_card(sdbus);
|
||||||
uint8_t value = 0;
|
uint8_t value = 0;
|
||||||
|
@ -122,13 +137,28 @@ uint8_t sdbus_read_data(SDBus *sdbus)
|
||||||
if (card) {
|
if (card) {
|
||||||
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
||||||
|
|
||||||
value = sc->read_data(card);
|
value = sc->read_byte(card);
|
||||||
}
|
}
|
||||||
trace_sdbus_read(sdbus_name(sdbus), value);
|
trace_sdbus_read(sdbus_name(sdbus), value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
|
||||||
|
{
|
||||||
|
SDState *card = get_card(sdbus);
|
||||||
|
uint8_t *data = buf;
|
||||||
|
|
||||||
|
if (card) {
|
||||||
|
SDCardClass *sc = SD_CARD_GET_CLASS(card);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
data[i] = sc->read_byte(card);
|
||||||
|
trace_sdbus_read(sdbus_name(sdbus), data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool sdbus_data_ready(SDBus *sdbus)
|
bool sdbus_data_ready(SDBus *sdbus)
|
||||||
{
|
{
|
||||||
SDState *card = get_card(sdbus);
|
SDState *card = get_card(sdbus);
|
||||||
|
|
|
@ -66,6 +66,8 @@ enum {
|
||||||
#define MILKYMIST_MEMCARD(obj) \
|
#define MILKYMIST_MEMCARD(obj) \
|
||||||
OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD)
|
OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD)
|
||||||
|
|
||||||
|
#define TYPE_MILKYMIST_SDBUS "milkymist-sdbus"
|
||||||
|
|
||||||
struct MilkymistMemcardState {
|
struct MilkymistMemcardState {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
|
@ -149,11 +151,8 @@ static uint64_t memcard_read(void *opaque, hwaddr addr,
|
||||||
if (!s->enabled) {
|
if (!s->enabled) {
|
||||||
r = 0xffffffff;
|
r = 0xffffffff;
|
||||||
} else {
|
} else {
|
||||||
r = 0;
|
sdbus_read_data(&s->sdbus, &r, sizeof(r));
|
||||||
r |= sdbus_read_data(&s->sdbus) << 24;
|
be32_to_cpus(&r);
|
||||||
r |= sdbus_read_data(&s->sdbus) << 16;
|
|
||||||
r |= sdbus_read_data(&s->sdbus) << 8;
|
|
||||||
r |= sdbus_read_data(&s->sdbus);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R_CLK2XDIV:
|
case R_CLK2XDIV:
|
||||||
|
@ -179,6 +178,7 @@ static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
MilkymistMemcardState *s = opaque;
|
MilkymistMemcardState *s = opaque;
|
||||||
|
uint32_t val32;
|
||||||
|
|
||||||
trace_milkymist_memcard_memory_write(addr, value);
|
trace_milkymist_memcard_memory_write(addr, value);
|
||||||
|
|
||||||
|
@ -207,10 +207,8 @@ static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
|
||||||
if (!s->enabled) {
|
if (!s->enabled) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sdbus_write_data(&s->sdbus, (value >> 24) & 0xff);
|
val32 = cpu_to_be32(value);
|
||||||
sdbus_write_data(&s->sdbus, (value >> 16) & 0xff);
|
sdbus_write_data(&s->sdbus, &val32, sizeof(val32));
|
||||||
sdbus_write_data(&s->sdbus, (value >> 8) & 0xff);
|
|
||||||
sdbus_write_data(&s->sdbus, value & 0xff);
|
|
||||||
break;
|
break;
|
||||||
case R_ENABLE:
|
case R_ENABLE:
|
||||||
s->regs[addr] = value;
|
s->regs[addr] = value;
|
||||||
|
@ -253,6 +251,19 @@ static void milkymist_memcard_reset(DeviceState *d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void milkymist_memcard_set_readonly(DeviceState *dev, bool level)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"milkymist_memcard: read-only mode not supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void milkymist_memcard_set_inserted(DeviceState *dev, bool level)
|
||||||
|
{
|
||||||
|
MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
|
||||||
|
|
||||||
|
s->enabled = !!level;
|
||||||
|
}
|
||||||
|
|
||||||
static void milkymist_memcard_init(Object *obj)
|
static void milkymist_memcard_init(Object *obj)
|
||||||
{
|
{
|
||||||
MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
|
MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
|
||||||
|
@ -261,30 +272,9 @@ static void milkymist_memcard_init(Object *obj)
|
||||||
memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
|
memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
|
||||||
"milkymist-memcard", R_MAX * 4);
|
"milkymist-memcard", R_MAX * 4);
|
||||||
sysbus_init_mmio(dev, &s->regs_region);
|
sysbus_init_mmio(dev, &s->regs_region);
|
||||||
}
|
|
||||||
|
|
||||||
static void milkymist_memcard_realize(DeviceState *dev, Error **errp)
|
|
||||||
{
|
|
||||||
MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
|
|
||||||
DeviceState *carddev;
|
|
||||||
BlockBackend *blk;
|
|
||||||
DriveInfo *dinfo;
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
|
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
|
||||||
dev, "sd-bus");
|
DEVICE(obj), "sd-bus");
|
||||||
|
|
||||||
/* Create and plug in the sd card */
|
|
||||||
/* FIXME use a qdev drive property instead of drive_get_next() */
|
|
||||||
dinfo = drive_get_next(IF_SD);
|
|
||||||
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
|
|
||||||
carddev = qdev_new(TYPE_SD_CARD);
|
|
||||||
qdev_prop_set_drive(carddev, "drive", blk);
|
|
||||||
if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) {
|
|
||||||
error_propagate_prepend(errp, err, "failed to init SD card");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s->enabled = blk && blk_is_inserted(blk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_milkymist_memcard = {
|
static const VMStateDescription vmstate_milkymist_memcard = {
|
||||||
|
@ -308,10 +298,9 @@ static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = milkymist_memcard_realize;
|
|
||||||
dc->reset = milkymist_memcard_reset;
|
dc->reset = milkymist_memcard_reset;
|
||||||
dc->vmsd = &vmstate_milkymist_memcard;
|
dc->vmsd = &vmstate_milkymist_memcard;
|
||||||
/* Reason: init() method uses drive_get_next() */
|
/* Reason: output IRQs should be wired up */
|
||||||
dc->user_creatable = false;
|
dc->user_creatable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,9 +312,25 @@ static const TypeInfo milkymist_memcard_info = {
|
||||||
.class_init = milkymist_memcard_class_init,
|
.class_init = milkymist_memcard_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void milkymist_sdbus_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
SDBusClass *sbc = SD_BUS_CLASS(klass);
|
||||||
|
|
||||||
|
sbc->set_inserted = milkymist_memcard_set_inserted;
|
||||||
|
sbc->set_readonly = milkymist_memcard_set_readonly;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo milkymist_sdbus_info = {
|
||||||
|
.name = TYPE_MILKYMIST_SDBUS,
|
||||||
|
.parent = TYPE_SD_BUS,
|
||||||
|
.instance_size = sizeof(SDBus),
|
||||||
|
.class_init = milkymist_sdbus_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void milkymist_memcard_register_types(void)
|
static void milkymist_memcard_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&milkymist_memcard_info);
|
type_register_static(&milkymist_memcard_info);
|
||||||
|
type_register_static(&milkymist_sdbus_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(milkymist_memcard_register_types)
|
type_init(milkymist_memcard_register_types)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/arm/omap.h"
|
#include "hw/arm/omap.h"
|
||||||
#include "hw/sd/sd.h"
|
#include "hw/sd/sdcard_legacy.h"
|
||||||
|
|
||||||
struct omap_mmc_s {
|
struct omap_mmc_s {
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
|
@ -232,10 +232,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
|
||||||
if (host->fifo_len > host->af_level)
|
if (host->fifo_len > host->af_level)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
value = sd_read_data(host->card);
|
value = sd_read_byte(host->card);
|
||||||
host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
|
host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
|
||||||
if (-- host->blen_counter) {
|
if (-- host->blen_counter) {
|
||||||
value = sd_read_data(host->card);
|
value = sd_read_byte(host->card);
|
||||||
host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
|
host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
|
||||||
value << 8;
|
value << 8;
|
||||||
host->blen_counter --;
|
host->blen_counter --;
|
||||||
|
@ -247,10 +247,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
value = host->fifo[host->fifo_start] & 0xff;
|
value = host->fifo[host->fifo_start] & 0xff;
|
||||||
sd_write_data(host->card, value);
|
sd_write_byte(host->card, value);
|
||||||
if (-- host->blen_counter) {
|
if (-- host->blen_counter) {
|
||||||
value = host->fifo[host->fifo_start] >> 8;
|
value = host->fifo[host->fifo_start] >> 8;
|
||||||
sd_write_data(host->card, value);
|
sd_write_byte(host->card, value);
|
||||||
host->blen_counter --;
|
host->blen_counter --;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
111
hw/sd/pl181.c
111
hw/sd/pl181.c
|
@ -15,27 +15,22 @@
|
||||||
#include "hw/sd/sd.h"
|
#include "hw/sd/sd.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "trace.h"
|
||||||
//#define DEBUG_PL181 1
|
|
||||||
|
|
||||||
#ifdef DEBUG_PL181
|
|
||||||
#define DPRINTF(fmt, ...) \
|
|
||||||
do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
|
|
||||||
#else
|
|
||||||
#define DPRINTF(fmt, ...) do {} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PL181_FIFO_LEN 16
|
#define PL181_FIFO_LEN 16
|
||||||
|
|
||||||
#define TYPE_PL181 "pl181"
|
#define TYPE_PL181 "pl181"
|
||||||
#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181)
|
#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181)
|
||||||
|
|
||||||
|
#define TYPE_PL181_BUS "pl181-bus"
|
||||||
|
|
||||||
typedef struct PL181State {
|
typedef struct PL181State {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
SDState *card;
|
SDBus sdbus;
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
uint32_t power;
|
uint32_t power;
|
||||||
uint32_t cmdarg;
|
uint32_t cmdarg;
|
||||||
|
@ -56,10 +51,11 @@ typedef struct PL181State {
|
||||||
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
|
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
|
||||||
*/
|
*/
|
||||||
int32_t linux_hack;
|
int32_t linux_hack;
|
||||||
uint32_t fifo[PL181_FIFO_LEN];
|
uint32_t fifo[PL181_FIFO_LEN]; /* TODO use Fifo32 */
|
||||||
qemu_irq irq[2];
|
qemu_irq irq[2];
|
||||||
/* GPIO outputs for 'card is readonly' and 'card inserted' */
|
/* GPIO outputs for 'card is readonly' and 'card inserted' */
|
||||||
qemu_irq cardstatus[2];
|
qemu_irq card_readonly;
|
||||||
|
qemu_irq card_inserted;
|
||||||
} PL181State;
|
} PL181State;
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pl181 = {
|
static const VMStateDescription vmstate_pl181 = {
|
||||||
|
@ -148,13 +144,13 @@ static void pl181_fifo_push(PL181State *s, uint32_t value)
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (s->fifo_len == PL181_FIFO_LEN) {
|
if (s->fifo_len == PL181_FIFO_LEN) {
|
||||||
fprintf(stderr, "pl181: FIFO overflow\n");
|
error_report("%s: FIFO overflow", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
|
n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
|
||||||
s->fifo_len++;
|
s->fifo_len++;
|
||||||
s->fifo[n] = value;
|
s->fifo[n] = value;
|
||||||
DPRINTF("FIFO push %08x\n", (int)value);
|
trace_pl181_fifo_push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t pl181_fifo_pop(PL181State *s)
|
static uint32_t pl181_fifo_pop(PL181State *s)
|
||||||
|
@ -162,17 +158,17 @@ static uint32_t pl181_fifo_pop(PL181State *s)
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
if (s->fifo_len == 0) {
|
if (s->fifo_len == 0) {
|
||||||
fprintf(stderr, "pl181: FIFO underflow\n");
|
error_report("%s: FIFO underflow", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
value = s->fifo[s->fifo_pos];
|
value = s->fifo[s->fifo_pos];
|
||||||
s->fifo_len--;
|
s->fifo_len--;
|
||||||
s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
|
s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
|
||||||
DPRINTF("FIFO pop %08x\n", (int)value);
|
trace_pl181_fifo_pop(value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl181_send_command(PL181State *s)
|
static void pl181_do_command(PL181State *s)
|
||||||
{
|
{
|
||||||
SDRequest request;
|
SDRequest request;
|
||||||
uint8_t response[16];
|
uint8_t response[16];
|
||||||
|
@ -180,8 +176,8 @@ static void pl181_send_command(PL181State *s)
|
||||||
|
|
||||||
request.cmd = s->cmd & PL181_CMD_INDEX;
|
request.cmd = s->cmd & PL181_CMD_INDEX;
|
||||||
request.arg = s->cmdarg;
|
request.arg = s->cmdarg;
|
||||||
DPRINTF("Command %d %08x\n", request.cmd, request.arg);
|
trace_pl181_command_send(request.cmd, request.arg);
|
||||||
rlen = sd_do_command(s->card, &request, response);
|
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||||
if (rlen < 0)
|
if (rlen < 0)
|
||||||
goto error;
|
goto error;
|
||||||
if (s->cmd & PL181_CMD_RESPONSE) {
|
if (s->cmd & PL181_CMD_RESPONSE) {
|
||||||
|
@ -197,16 +193,16 @@ static void pl181_send_command(PL181State *s)
|
||||||
s->response[2] = ldl_be_p(&response[8]);
|
s->response[2] = ldl_be_p(&response[8]);
|
||||||
s->response[3] = ldl_be_p(&response[12]) & ~1;
|
s->response[3] = ldl_be_p(&response[12]) & ~1;
|
||||||
}
|
}
|
||||||
DPRINTF("Response received\n");
|
trace_pl181_command_response_pending();
|
||||||
s->status |= PL181_STATUS_CMDRESPEND;
|
s->status |= PL181_STATUS_CMDRESPEND;
|
||||||
} else {
|
} else {
|
||||||
DPRINTF("Command sent\n");
|
trace_pl181_command_sent();
|
||||||
s->status |= PL181_STATUS_CMDSENT;
|
s->status |= PL181_STATUS_CMDSENT;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
DPRINTF("Timeout\n");
|
trace_pl181_command_timeout();
|
||||||
s->status |= PL181_STATUS_CMDTIMEOUT;
|
s->status |= PL181_STATUS_CMDTIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,12 +218,12 @@ static void pl181_fifo_run(PL181State *s)
|
||||||
int is_read;
|
int is_read;
|
||||||
|
|
||||||
is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
|
is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
|
||||||
if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
|
if (s->datacnt != 0 && (!is_read || sdbus_data_ready(&s->sdbus))
|
||||||
&& !s->linux_hack) {
|
&& !s->linux_hack) {
|
||||||
if (is_read) {
|
if (is_read) {
|
||||||
n = 0;
|
n = 0;
|
||||||
while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
|
while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
|
||||||
value |= (uint32_t)sd_read_data(s->card) << (n * 8);
|
value |= (uint32_t)sdbus_read_byte(&s->sdbus) << (n * 8);
|
||||||
s->datacnt--;
|
s->datacnt--;
|
||||||
n++;
|
n++;
|
||||||
if (n == 4) {
|
if (n == 4) {
|
||||||
|
@ -248,7 +244,7 @@ static void pl181_fifo_run(PL181State *s)
|
||||||
}
|
}
|
||||||
n--;
|
n--;
|
||||||
s->datacnt--;
|
s->datacnt--;
|
||||||
sd_write_data(s->card, value & 0xff);
|
sdbus_write_byte(&s->sdbus, value & 0xff);
|
||||||
value >>= 8;
|
value >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,11 +254,11 @@ static void pl181_fifo_run(PL181State *s)
|
||||||
s->status |= PL181_STATUS_DATAEND;
|
s->status |= PL181_STATUS_DATAEND;
|
||||||
/* HACK: */
|
/* HACK: */
|
||||||
s->status |= PL181_STATUS_DATABLOCKEND;
|
s->status |= PL181_STATUS_DATABLOCKEND;
|
||||||
DPRINTF("Transfer Complete\n");
|
trace_pl181_fifo_transfer_complete();
|
||||||
}
|
}
|
||||||
if (s->datacnt == 0 && s->fifo_len == 0) {
|
if (s->datacnt == 0 && s->fifo_len == 0) {
|
||||||
s->datactrl &= ~PL181_DATA_ENABLE;
|
s->datactrl &= ~PL181_DATA_ENABLE;
|
||||||
DPRINTF("Data engine idle\n");
|
trace_pl181_data_engine_idle();
|
||||||
} else {
|
} else {
|
||||||
/* Update FIFO bits. */
|
/* Update FIFO bits. */
|
||||||
bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
|
bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
|
||||||
|
@ -401,7 +397,7 @@ static void pl181_write(void *opaque, hwaddr offset,
|
||||||
qemu_log_mask(LOG_UNIMP,
|
qemu_log_mask(LOG_UNIMP,
|
||||||
"pl181: Pending commands not implemented\n");
|
"pl181: Pending commands not implemented\n");
|
||||||
} else {
|
} else {
|
||||||
pl181_send_command(s);
|
pl181_do_command(s);
|
||||||
pl181_fifo_run(s);
|
pl181_fifo_run(s);
|
||||||
}
|
}
|
||||||
/* The command has completed one way or the other. */
|
/* The command has completed one way or the other. */
|
||||||
|
@ -454,6 +450,20 @@ static const MemoryRegionOps pl181_ops = {
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pl181_set_readonly(DeviceState *dev, bool level)
|
||||||
|
{
|
||||||
|
PL181State *s = (PL181State *)dev;
|
||||||
|
|
||||||
|
qemu_set_irq(s->card_readonly, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pl181_set_inserted(DeviceState *dev, bool level)
|
||||||
|
{
|
||||||
|
PL181State *s = (PL181State *)dev;
|
||||||
|
|
||||||
|
qemu_set_irq(s->card_inserted, level);
|
||||||
|
}
|
||||||
|
|
||||||
static void pl181_reset(DeviceState *d)
|
static void pl181_reset(DeviceState *d)
|
||||||
{
|
{
|
||||||
PL181State *s = PL181(d);
|
PL181State *s = PL181(d);
|
||||||
|
@ -477,12 +487,9 @@ static void pl181_reset(DeviceState *d)
|
||||||
s->mask[0] = 0;
|
s->mask[0] = 0;
|
||||||
s->mask[1] = 0;
|
s->mask[1] = 0;
|
||||||
|
|
||||||
/* We can assume our GPIO outputs have been wired up now */
|
/* Reset other state based on current card insertion/readonly status */
|
||||||
sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
|
pl181_set_inserted(DEVICE(s), sdbus_get_inserted(&s->sdbus));
|
||||||
/* Since we're still using the legacy SD API the card is not plugged
|
pl181_set_readonly(DEVICE(s), sdbus_get_readonly(&s->sdbus));
|
||||||
* into any bus, and we must reset it manually.
|
|
||||||
*/
|
|
||||||
device_legacy_reset(DEVICE(s->card));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl181_init(Object *obj)
|
static void pl181_init(Object *obj)
|
||||||
|
@ -495,20 +502,11 @@ static void pl181_init(Object *obj)
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
sysbus_init_irq(sbd, &s->irq[0]);
|
sysbus_init_irq(sbd, &s->irq[0]);
|
||||||
sysbus_init_irq(sbd, &s->irq[1]);
|
sysbus_init_irq(sbd, &s->irq[1]);
|
||||||
qdev_init_gpio_out(dev, s->cardstatus, 2);
|
qdev_init_gpio_out_named(dev, &s->card_readonly, "card-read-only", 1);
|
||||||
}
|
qdev_init_gpio_out_named(dev, &s->card_inserted, "card-inserted", 1);
|
||||||
|
|
||||||
static void pl181_realize(DeviceState *dev, Error **errp)
|
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
|
||||||
{
|
TYPE_PL181_BUS, dev, "sd-bus");
|
||||||
PL181State *s = PL181(dev);
|
|
||||||
DriveInfo *dinfo;
|
|
||||||
|
|
||||||
/* FIXME use a qdev drive property instead of drive_get_next() */
|
|
||||||
dinfo = drive_get_next(IF_SD);
|
|
||||||
s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false);
|
|
||||||
if (s->card == NULL) {
|
|
||||||
error_setg(errp, "sd_init failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl181_class_init(ObjectClass *klass, void *data)
|
static void pl181_class_init(ObjectClass *klass, void *data)
|
||||||
|
@ -517,9 +515,8 @@ static void pl181_class_init(ObjectClass *klass, void *data)
|
||||||
|
|
||||||
k->vmsd = &vmstate_pl181;
|
k->vmsd = &vmstate_pl181;
|
||||||
k->reset = pl181_reset;
|
k->reset = pl181_reset;
|
||||||
/* Reason: init() method uses drive_get_next() */
|
/* Reason: output IRQs should be wired up */
|
||||||
k->user_creatable = false;
|
k->user_creatable = false;
|
||||||
k->realize = pl181_realize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo pl181_info = {
|
static const TypeInfo pl181_info = {
|
||||||
|
@ -530,9 +527,25 @@ static const TypeInfo pl181_info = {
|
||||||
.class_init = pl181_class_init,
|
.class_init = pl181_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pl181_bus_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
SDBusClass *sbc = SD_BUS_CLASS(klass);
|
||||||
|
|
||||||
|
sbc->set_inserted = pl181_set_inserted;
|
||||||
|
sbc->set_readonly = pl181_set_readonly;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo pl181_bus_info = {
|
||||||
|
.name = TYPE_PL181_BUS,
|
||||||
|
.parent = TYPE_SD_BUS,
|
||||||
|
.instance_size = sizeof(SDBus),
|
||||||
|
.class_init = pl181_bus_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void pl181_register_types(void)
|
static void pl181_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&pl181_info);
|
type_register_static(&pl181_info);
|
||||||
|
type_register_static(&pl181_bus_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(pl181_register_types)
|
type_init(pl181_register_types)
|
||||||
|
|
|
@ -184,7 +184,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
|
||||||
|
|
||||||
if (s->cmdat & CMDAT_WR_RD) {
|
if (s->cmdat & CMDAT_WR_RD) {
|
||||||
while (s->bytesleft && s->tx_len) {
|
while (s->bytesleft && s->tx_len) {
|
||||||
sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]);
|
sdbus_write_byte(&s->sdbus, s->tx_fifo[s->tx_start++]);
|
||||||
s->tx_start &= 0x1f;
|
s->tx_start &= 0x1f;
|
||||||
s->tx_len --;
|
s->tx_len --;
|
||||||
s->bytesleft --;
|
s->bytesleft --;
|
||||||
|
@ -194,7 +194,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
|
||||||
} else
|
} else
|
||||||
while (s->bytesleft && s->rx_len < 32) {
|
while (s->bytesleft && s->rx_len < 32) {
|
||||||
s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
|
s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
|
||||||
sdbus_read_data(&s->sdbus);
|
sdbus_read_byte(&s->sdbus);
|
||||||
s->bytesleft --;
|
s->bytesleft --;
|
||||||
s->intreq |= INT_RXFIFO_REQ;
|
s->intreq |= INT_RXFIFO_REQ;
|
||||||
}
|
}
|
||||||
|
@ -476,15 +476,12 @@ static const MemoryRegionOps pxa2xx_mmci_ops = {
|
||||||
|
|
||||||
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
||||||
hwaddr base,
|
hwaddr base,
|
||||||
BlockBackend *blk, qemu_irq irq,
|
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
|
||||||
qemu_irq rx_dma, qemu_irq tx_dma)
|
|
||||||
{
|
{
|
||||||
DeviceState *dev, *carddev;
|
DeviceState *dev;
|
||||||
SysBusDevice *sbd;
|
SysBusDevice *sbd;
|
||||||
PXA2xxMMCIState *s;
|
|
||||||
|
|
||||||
dev = qdev_new(TYPE_PXA2XX_MMCI);
|
dev = qdev_new(TYPE_PXA2XX_MMCI);
|
||||||
s = PXA2XX_MMCI(dev);
|
|
||||||
sbd = SYS_BUS_DEVICE(dev);
|
sbd = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_mmio_map(sbd, 0, base);
|
sysbus_mmio_map(sbd, 0, base);
|
||||||
sysbus_connect_irq(sbd, 0, irq);
|
sysbus_connect_irq(sbd, 0, irq);
|
||||||
|
@ -492,13 +489,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
||||||
qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
|
qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
|
||||||
sysbus_realize_and_unref(sbd, &error_fatal);
|
sysbus_realize_and_unref(sbd, &error_fatal);
|
||||||
|
|
||||||
/* Create and plug in the sd card */
|
return PXA2XX_MMCI(dev);
|
||||||
carddev = qdev_new(TYPE_SD_CARD);
|
|
||||||
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
|
|
||||||
qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
|
|
||||||
&error_fatal);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
|
static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
|
||||||
|
|
28
hw/sd/sd.c
28
hw/sd/sd.c
|
@ -37,6 +37,7 @@
|
||||||
#include "hw/registerfields.h"
|
#include "hw/registerfields.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "hw/sd/sd.h"
|
#include "hw/sd/sd.h"
|
||||||
|
#include "hw/sd/sdcard_legacy.h"
|
||||||
#include "migration/vmstate.h"
|
#include "migration/vmstate.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/bitmap.h"
|
#include "qemu/bitmap.h"
|
||||||
|
@ -50,6 +51,8 @@
|
||||||
|
|
||||||
//#define DEBUG_SD 1
|
//#define DEBUG_SD 1
|
||||||
|
|
||||||
|
#define SDSC_MAX_CAPACITY (2 * GiB)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
sd_r0 = 0, /* no response */
|
sd_r0 = 0, /* no response */
|
||||||
sd_r1, /* normal response command */
|
sd_r1, /* normal response command */
|
||||||
|
@ -313,7 +316,7 @@ static void sd_ocr_powerup(void *opaque)
|
||||||
/* card power-up OK */
|
/* card power-up OK */
|
||||||
sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1);
|
sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1);
|
||||||
|
|
||||||
if (sd->size > 1 * GiB) {
|
if (sd->size > SDSC_MAX_CAPACITY) {
|
||||||
sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1);
|
sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_CAPACITY, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +388,7 @@ static void sd_set_csd(SDState *sd, uint64_t size)
|
||||||
uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
|
uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
|
||||||
uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
|
uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
|
||||||
|
|
||||||
if (size <= 1 * GiB) { /* Standard Capacity SD */
|
if (size <= SDSC_MAX_CAPACITY) { /* Standard Capacity SD */
|
||||||
sd->csd[0] = 0x00; /* CSD structure */
|
sd->csd[0] = 0x00; /* CSD structure */
|
||||||
sd->csd[1] = 0x26; /* Data read access-time-1 */
|
sd->csd[1] = 0x26; /* Data read access-time-1 */
|
||||||
sd->csd[2] = 0x00; /* Data read access-time-2 */
|
sd->csd[2] = 0x00; /* Data read access-time-2 */
|
||||||
|
@ -806,11 +809,12 @@ static void sd_function_switch(SDState *sd, uint32_t arg)
|
||||||
sd->data[11] = 0x43;
|
sd->data[11] = 0x43;
|
||||||
sd->data[12] = 0x80; /* Supported group 1 functions */
|
sd->data[12] = 0x80; /* Supported group 1 functions */
|
||||||
sd->data[13] = 0x03;
|
sd->data[13] = 0x03;
|
||||||
|
|
||||||
for (i = 0; i < 6; i ++) {
|
for (i = 0; i < 6; i ++) {
|
||||||
new_func = (arg >> (i * 4)) & 0x0f;
|
new_func = (arg >> (i * 4)) & 0x0f;
|
||||||
if (mode && new_func != 0x0f)
|
if (mode && new_func != 0x0f)
|
||||||
sd->function_group[i] = new_func;
|
sd->function_group[i] = new_func;
|
||||||
sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
|
sd->data[16 - (i >> 1)] |= new_func << ((i % 2) * 4);
|
||||||
}
|
}
|
||||||
memset(&sd->data[17], 0, 47);
|
memset(&sd->data[17], 0, 47);
|
||||||
stw_be_p(sd->data + 64, sd_crc16(sd->data, 64));
|
stw_be_p(sd->data + 64, sd_crc16(sd->data, 64));
|
||||||
|
@ -1808,7 +1812,7 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
|
||||||
#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
|
#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
|
||||||
#define APP_WRITE_BLOCK(a, len)
|
#define APP_WRITE_BLOCK(a, len)
|
||||||
|
|
||||||
void sd_write_data(SDState *sd, uint8_t value)
|
void sd_write_byte(SDState *sd, uint8_t value)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1817,7 +1821,7 @@ void sd_write_data(SDState *sd, uint8_t value)
|
||||||
|
|
||||||
if (sd->state != sd_receivingdata_state) {
|
if (sd->state != sd_receivingdata_state) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"sd_write_data: not in Receiving-Data state\n");
|
"%s: not in Receiving-Data state\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1939,7 +1943,7 @@ void sd_write_data(SDState *sd, uint8_t value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n");
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1958,7 +1962,7 @@ static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = {
|
||||||
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
|
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t sd_read_data(SDState *sd)
|
uint8_t sd_read_byte(SDState *sd)
|
||||||
{
|
{
|
||||||
/* TODO: Append CRCs */
|
/* TODO: Append CRCs */
|
||||||
uint8_t ret;
|
uint8_t ret;
|
||||||
|
@ -1969,7 +1973,7 @@ uint8_t sd_read_data(SDState *sd)
|
||||||
|
|
||||||
if (sd->state != sd_sendingdata_state) {
|
if (sd->state != sd_sendingdata_state) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"sd_read_data: not in Sending-Data state\n");
|
"%s: not in Sending-Data state\n", __func__);
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2075,14 +2079,14 @@ uint8_t sd_read_data(SDState *sd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n");
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown command\n", __func__);
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sd_data_ready(SDState *sd)
|
static bool sd_data_ready(SDState *sd)
|
||||||
{
|
{
|
||||||
return sd->state == sd_sendingdata_state;
|
return sd->state == sd_sendingdata_state;
|
||||||
}
|
}
|
||||||
|
@ -2191,8 +2195,8 @@ static void sd_class_init(ObjectClass *klass, void *data)
|
||||||
sc->get_dat_lines = sd_get_dat_lines;
|
sc->get_dat_lines = sd_get_dat_lines;
|
||||||
sc->get_cmd_line = sd_get_cmd_line;
|
sc->get_cmd_line = sd_get_cmd_line;
|
||||||
sc->do_command = sd_do_command;
|
sc->do_command = sd_do_command;
|
||||||
sc->write_data = sd_write_data;
|
sc->write_byte = sd_write_byte;
|
||||||
sc->read_data = sd_read_data;
|
sc->read_byte = sd_read_byte;
|
||||||
sc->data_ready = sd_data_ready;
|
sc->data_ready = sd_data_ready;
|
||||||
sc->enable = sd_enable;
|
sc->enable = sd_enable;
|
||||||
sc->get_inserted = sd_get_inserted;
|
sc->get_inserted = sd_get_inserted;
|
||||||
|
|
|
@ -399,8 +399,6 @@ static void sdhci_end_transfer(SDHCIState *s)
|
||||||
/* Fill host controller's read buffer with BLKSIZE bytes of data from card */
|
/* Fill host controller's read buffer with BLKSIZE bytes of data from card */
|
||||||
static void sdhci_read_block_from_card(SDHCIState *s)
|
static void sdhci_read_block_from_card(SDHCIState *s)
|
||||||
{
|
{
|
||||||
int index = 0;
|
|
||||||
uint8_t data;
|
|
||||||
const uint16_t blk_size = s->blksize & BLOCK_SIZE_MASK;
|
const uint16_t blk_size = s->blksize & BLOCK_SIZE_MASK;
|
||||||
|
|
||||||
if ((s->trnmod & SDHC_TRNS_MULTI) &&
|
if ((s->trnmod & SDHC_TRNS_MULTI) &&
|
||||||
|
@ -408,12 +406,9 @@ static void sdhci_read_block_from_card(SDHCIState *s)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0; index < blk_size; index++) {
|
if (!FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) {
|
||||||
data = sdbus_read_data(&s->sdbus);
|
/* Device is not in tuning */
|
||||||
if (!FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) {
|
sdbus_read_data(&s->sdbus, s->fifo_buffer, blk_size);
|
||||||
/* Device is not in tuning */
|
|
||||||
s->fifo_buffer[index] = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) {
|
if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) {
|
||||||
|
@ -496,8 +491,6 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
|
||||||
/* Write data from host controller FIFO to card */
|
/* Write data from host controller FIFO to card */
|
||||||
static void sdhci_write_block_to_card(SDHCIState *s)
|
static void sdhci_write_block_to_card(SDHCIState *s)
|
||||||
{
|
{
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
if (s->prnsts & SDHC_SPACE_AVAILABLE) {
|
if (s->prnsts & SDHC_SPACE_AVAILABLE) {
|
||||||
if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
|
if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
|
||||||
s->norintsts |= SDHC_NIS_WBUFRDY;
|
s->norintsts |= SDHC_NIS_WBUFRDY;
|
||||||
|
@ -514,9 +507,7 @@ static void sdhci_write_block_to_card(SDHCIState *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0; index < (s->blksize & BLOCK_SIZE_MASK); index++) {
|
sdbus_write_data(&s->sdbus, s->fifo_buffer, s->blksize & BLOCK_SIZE_MASK);
|
||||||
sdbus_write_data(&s->sdbus, s->fifo_buffer[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next data can be written through BUFFER DATORT register */
|
/* Next data can be written through BUFFER DATORT register */
|
||||||
s->prnsts |= SDHC_SPACE_AVAILABLE;
|
s->prnsts |= SDHC_SPACE_AVAILABLE;
|
||||||
|
@ -578,7 +569,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
|
||||||
static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||||
{
|
{
|
||||||
bool page_aligned = false;
|
bool page_aligned = false;
|
||||||
unsigned int n, begin;
|
unsigned int begin;
|
||||||
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
|
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
|
||||||
uint32_t boundary_chk = 1 << (((s->blksize & ~BLOCK_SIZE_MASK) >> 12) + 12);
|
uint32_t boundary_chk = 1 << (((s->blksize & ~BLOCK_SIZE_MASK) >> 12) + 12);
|
||||||
uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
|
uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
|
||||||
|
@ -600,9 +591,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||||
SDHC_DAT_LINE_ACTIVE;
|
SDHC_DAT_LINE_ACTIVE;
|
||||||
while (s->blkcnt) {
|
while (s->blkcnt) {
|
||||||
if (s->data_count == 0) {
|
if (s->data_count == 0) {
|
||||||
for (n = 0; n < block_size; n++) {
|
sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size);
|
||||||
s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
begin = s->data_count;
|
begin = s->data_count;
|
||||||
if (((boundary_count + begin) < block_size) && page_aligned) {
|
if (((boundary_count + begin) < block_size) && page_aligned) {
|
||||||
|
@ -641,9 +630,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||||
&s->fifo_buffer[begin], s->data_count - begin);
|
&s->fifo_buffer[begin], s->data_count - begin);
|
||||||
s->sdmasysad += s->data_count - begin;
|
s->sdmasysad += s->data_count - begin;
|
||||||
if (s->data_count == block_size) {
|
if (s->data_count == block_size) {
|
||||||
for (n = 0; n < block_size; n++) {
|
sdbus_write_data(&s->sdbus, s->fifo_buffer, block_size);
|
||||||
sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
|
|
||||||
}
|
|
||||||
s->data_count = 0;
|
s->data_count = 0;
|
||||||
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
|
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
|
||||||
s->blkcnt--;
|
s->blkcnt--;
|
||||||
|
@ -668,19 +655,14 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||||
/* single block SDMA transfer */
|
/* single block SDMA transfer */
|
||||||
static void sdhci_sdma_transfer_single_block(SDHCIState *s)
|
static void sdhci_sdma_transfer_single_block(SDHCIState *s)
|
||||||
{
|
{
|
||||||
int n;
|
|
||||||
uint32_t datacnt = s->blksize & BLOCK_SIZE_MASK;
|
uint32_t datacnt = s->blksize & BLOCK_SIZE_MASK;
|
||||||
|
|
||||||
if (s->trnmod & SDHC_TRNS_READ) {
|
if (s->trnmod & SDHC_TRNS_READ) {
|
||||||
for (n = 0; n < datacnt; n++) {
|
sdbus_read_data(&s->sdbus, s->fifo_buffer, datacnt);
|
||||||
s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
|
|
||||||
}
|
|
||||||
dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt);
|
dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt);
|
||||||
} else {
|
} else {
|
||||||
dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt);
|
dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt);
|
||||||
for (n = 0; n < datacnt; n++) {
|
sdbus_write_data(&s->sdbus, s->fifo_buffer, datacnt);
|
||||||
sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
s->blkcnt--;
|
s->blkcnt--;
|
||||||
|
|
||||||
|
@ -739,7 +721,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
|
||||||
|
|
||||||
static void sdhci_do_adma(SDHCIState *s)
|
static void sdhci_do_adma(SDHCIState *s)
|
||||||
{
|
{
|
||||||
unsigned int n, begin, length;
|
unsigned int begin, length;
|
||||||
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
|
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
|
||||||
ADMADescr dscr = {};
|
ADMADescr dscr = {};
|
||||||
int i;
|
int i;
|
||||||
|
@ -773,9 +755,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
||||||
if (s->trnmod & SDHC_TRNS_READ) {
|
if (s->trnmod & SDHC_TRNS_READ) {
|
||||||
while (length) {
|
while (length) {
|
||||||
if (s->data_count == 0) {
|
if (s->data_count == 0) {
|
||||||
for (n = 0; n < block_size; n++) {
|
sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size);
|
||||||
s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
begin = s->data_count;
|
begin = s->data_count;
|
||||||
if ((length + begin) < block_size) {
|
if ((length + begin) < block_size) {
|
||||||
|
@ -814,9 +794,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
||||||
s->data_count - begin);
|
s->data_count - begin);
|
||||||
dscr.addr += s->data_count - begin;
|
dscr.addr += s->data_count - begin;
|
||||||
if (s->data_count == block_size) {
|
if (s->data_count == block_size) {
|
||||||
for (n = 0; n < block_size; n++) {
|
sdbus_write_data(&s->sdbus, s->fifo_buffer, block_size);
|
||||||
sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
|
|
||||||
}
|
|
||||||
s->data_count = 0;
|
s->data_count = 0;
|
||||||
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
|
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
|
||||||
s->blkcnt--;
|
s->blkcnt--;
|
||||||
|
|
|
@ -190,7 +190,7 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
|
||||||
s->mode = SSI_SD_DATA_READ;
|
s->mode = SSI_SD_DATA_READ;
|
||||||
return 0xfe;
|
return 0xfe;
|
||||||
case SSI_SD_DATA_READ:
|
case SSI_SD_DATA_READ:
|
||||||
val = sdbus_read_data(&s->sdbus);
|
val = sdbus_read_byte(&s->sdbus);
|
||||||
if (!sdbus_data_ready(&s->sdbus)) {
|
if (!sdbus_data_ready(&s->sdbus)) {
|
||||||
DPRINTF("Data read end\n");
|
DPRINTF("Data read end\n");
|
||||||
s->mode = SSI_SD_CMD;
|
s->mode = SSI_SD_CMD;
|
||||||
|
|
|
@ -62,3 +62,13 @@ milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value
|
||||||
# pxa2xx_mmci.c
|
# pxa2xx_mmci.c
|
||||||
pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||||
pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||||
|
|
||||||
|
# pl181.c
|
||||||
|
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
|
||||||
|
pl181_command_sent(void) "command sent"
|
||||||
|
pl181_command_response_pending(void) "response received"
|
||||||
|
pl181_command_timeout(void) "command timeouted"
|
||||||
|
pl181_fifo_push(uint32_t data) "FIFO push 0x%08" PRIx32
|
||||||
|
pl181_fifo_pop(uint32_t data) "FIFO pop 0x%08" PRIx32
|
||||||
|
pl181_fifo_transfer_complete(void) "FIFO transfer complete"
|
||||||
|
pl181_data_engine_idle(void) "data engine idle"
|
||||||
|
|
|
@ -89,8 +89,7 @@ void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
|
||||||
typedef struct PXA2xxMMCIState PXA2xxMMCIState;
|
typedef struct PXA2xxMMCIState PXA2xxMMCIState;
|
||||||
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
||||||
hwaddr base,
|
hwaddr base,
|
||||||
BlockBackend *blk, qemu_irq irq,
|
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma);
|
||||||
qemu_irq rx_dma, qemu_irq tx_dma);
|
|
||||||
void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
|
void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
|
||||||
qemu_irq coverswitch);
|
qemu_irq coverswitch);
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,23 @@ typedef struct {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
|
int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
|
||||||
void (*write_data)(SDState *sd, uint8_t value);
|
/**
|
||||||
uint8_t (*read_data)(SDState *sd);
|
* Write a byte to a SD card.
|
||||||
|
* @sd: card
|
||||||
|
* @value: byte to write
|
||||||
|
*
|
||||||
|
* Write a byte on the data lines of a SD card.
|
||||||
|
*/
|
||||||
|
void (*write_byte)(SDState *sd, uint8_t value);
|
||||||
|
/**
|
||||||
|
* Read a byte from a SD card.
|
||||||
|
* @sd: card
|
||||||
|
*
|
||||||
|
* Read a byte from the data lines of a SD card.
|
||||||
|
*
|
||||||
|
* Return: byte value read
|
||||||
|
*/
|
||||||
|
uint8_t (*read_byte)(SDState *sd);
|
||||||
bool (*data_ready)(SDState *sd);
|
bool (*data_ready)(SDState *sd);
|
||||||
void (*set_voltage)(SDState *sd, uint16_t millivolts);
|
void (*set_voltage)(SDState *sd, uint16_t millivolts);
|
||||||
uint8_t (*get_dat_lines)(SDState *sd);
|
uint8_t (*get_dat_lines)(SDState *sd);
|
||||||
|
@ -136,23 +151,6 @@ typedef struct {
|
||||||
void (*set_readonly)(DeviceState *dev, bool readonly);
|
void (*set_readonly)(DeviceState *dev, bool readonly);
|
||||||
} SDBusClass;
|
} SDBusClass;
|
||||||
|
|
||||||
/* Legacy functions to be used only by non-qdevified callers */
|
|
||||||
SDState *sd_init(BlockBackend *bs, bool is_spi);
|
|
||||||
int sd_do_command(SDState *sd, SDRequest *req,
|
|
||||||
uint8_t *response);
|
|
||||||
void sd_write_data(SDState *sd, uint8_t value);
|
|
||||||
uint8_t sd_read_data(SDState *sd);
|
|
||||||
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
|
|
||||||
bool sd_data_ready(SDState *sd);
|
|
||||||
/* sd_enable should not be used -- it is only used on the nseries boards,
|
|
||||||
* where it is part of a broken implementation of the MMC card slot switch
|
|
||||||
* (there should be two card slots which are multiplexed to a single MMC
|
|
||||||
* controller, but instead we model it with one card and controller and
|
|
||||||
* disable the card when the second slot is selected, so it looks like the
|
|
||||||
* second slot is always empty).
|
|
||||||
*/
|
|
||||||
void sd_enable(SDState *sd, bool enable);
|
|
||||||
|
|
||||||
/* Functions to be used by qdevified callers (working via
|
/* Functions to be used by qdevified callers (working via
|
||||||
* an SDBus rather than directly with SDState)
|
* an SDBus rather than directly with SDState)
|
||||||
*/
|
*/
|
||||||
|
@ -160,8 +158,41 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts);
|
||||||
uint8_t sdbus_get_dat_lines(SDBus *sdbus);
|
uint8_t sdbus_get_dat_lines(SDBus *sdbus);
|
||||||
bool sdbus_get_cmd_line(SDBus *sdbus);
|
bool sdbus_get_cmd_line(SDBus *sdbus);
|
||||||
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
|
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
|
||||||
void sdbus_write_data(SDBus *sd, uint8_t value);
|
/**
|
||||||
uint8_t sdbus_read_data(SDBus *sd);
|
* Write a byte to a SD bus.
|
||||||
|
* @sd: bus
|
||||||
|
* @value: byte to write
|
||||||
|
*
|
||||||
|
* Write a byte on the data lines of a SD bus.
|
||||||
|
*/
|
||||||
|
void sdbus_write_byte(SDBus *sd, uint8_t value);
|
||||||
|
/**
|
||||||
|
* Read a byte from a SD bus.
|
||||||
|
* @sd: bus
|
||||||
|
*
|
||||||
|
* Read a byte from the data lines of a SD bus.
|
||||||
|
*
|
||||||
|
* Return: byte value read
|
||||||
|
*/
|
||||||
|
uint8_t sdbus_read_byte(SDBus *sd);
|
||||||
|
/**
|
||||||
|
* Write data to a SD bus.
|
||||||
|
* @sdbus: bus
|
||||||
|
* @buf: data to write
|
||||||
|
* @length: number of bytes to write
|
||||||
|
*
|
||||||
|
* Write multiple bytes of data on the data lines of a SD bus.
|
||||||
|
*/
|
||||||
|
void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length);
|
||||||
|
/**
|
||||||
|
* Read data from a SD bus.
|
||||||
|
* @sdbus: bus
|
||||||
|
* @buf: buffer to read data into
|
||||||
|
* @length: number of bytes to read
|
||||||
|
*
|
||||||
|
* Read multiple bytes of data on the data lines of a SD bus.
|
||||||
|
*/
|
||||||
|
void sdbus_read_data(SDBus *sdbus, void *buf, size_t length);
|
||||||
bool sdbus_data_ready(SDBus *sd);
|
bool sdbus_data_ready(SDBus *sd);
|
||||||
bool sdbus_get_inserted(SDBus *sd);
|
bool sdbus_get_inserted(SDBus *sd);
|
||||||
bool sdbus_get_readonly(SDBus *sd);
|
bool sdbus_get_readonly(SDBus *sd);
|
||||||
|
|
50
include/hw/sd/sdcard_legacy.h
Normal file
50
include/hw/sd/sdcard_legacy.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* SD Memory Card emulation (deprecated legacy API)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef HW_SDCARD_LEGACY_H
|
||||||
|
#define HW_SDCARD_LEGACY_H
|
||||||
|
|
||||||
|
#include "hw/sd/sd.h"
|
||||||
|
|
||||||
|
/* Legacy functions to be used only by non-qdevified callers */
|
||||||
|
SDState *sd_init(BlockBackend *blk, bool is_spi);
|
||||||
|
int sd_do_command(SDState *card, SDRequest *request, uint8_t *response);
|
||||||
|
void sd_write_byte(SDState *card, uint8_t value);
|
||||||
|
uint8_t sd_read_byte(SDState *card);
|
||||||
|
void sd_set_cb(SDState *card, qemu_irq readonly, qemu_irq insert);
|
||||||
|
|
||||||
|
/* sd_enable should not be used -- it is only used on the nseries boards,
|
||||||
|
* where it is part of a broken implementation of the MMC card slot switch
|
||||||
|
* (there should be two card slots which are multiplexed to a single MMC
|
||||||
|
* controller, but instead we model it with one card and controller and
|
||||||
|
* disable the card when the second slot is selected, so it looks like the
|
||||||
|
* second slot is always empty).
|
||||||
|
*/
|
||||||
|
void sd_enable(SDState *card, bool enable);
|
||||||
|
|
||||||
|
#endif /* HW_SDCARD_LEGACY_H */
|
Loading…
Reference in a new issue