mirror of https://gitee.com/openkylin/qemu.git
target-arm queue:
* SDHCI: cleanups and minor bug fixes * target/arm: minor refactor preparatory to fp16 support * omap_ssd, ssi-sd, pl181, milkymist-memcard: reset the SD card on controller reset (fixes migration failures) * target/arm: Handle page table walk load failures correctly * hw/arm/virt: Add virt-2.12 machine type * get_phys_addr_pmsav7: Support AP=0b111 for v7M * hw/intc/armv7m: Support byte and halfword accesses to CFSR -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJaXf8rAAoJEDwlJe0UNgzeoi4QALHpLEXjOmIrIxjcbEoN2T6B tGdR+ZyNfdKI2lgleG6c5bmdzPaFooDoqOyCIML77AvqVlRjbDGw6KIfNmLfXQ2g 16bh0D11Qyl5Yv/YBN3Lv7nDPou4/sop6TzP0MSxvDucqksEVvQARuY147bxHkmy uz5jhdSkWdePFJRtmIJtm9G1PpOhS6IjCVKR/upWDJkpBqUdIxtPNx8fEgrcK7mb MdSU9LVl0p4J4zYjzFCUF8qMIrtbiqlAAVEt894BeZJk+tDYbq245S3oj1psc3XP sGRriXNxQnsczkrkyEAq2BHjswyLLd12jG+vtWkj0A0tIlB4jHgB26juZJbqk8Ui GzJoJQ7kCA4qsQxm4goONUkUJdmBtgCCQekWc0a87ELhdzd9pus8bDe9ivFmxCOW 1+i/ZX773GfLyDp5b1HwN5TU6u8J2bg+C4604hGIJ/h8r4Wu+iqH5/LfEum304rS Oqx5XQhU3a1dw+4w897CLbBscfVjNsPmgrCOXq4SYGZZ3NjTwyBMOedtB5HF279i mI5NZqVBiLoKC+oDjDe7k7oW6FdeEKfuDsOsxeLpIIe/66YwSpgk1bAsbvipcbRG 4sUIqMEk6/2TQmVY9lnYg5msQK3QGFtPDSzrFnz3T+DswaCto/SFa89yeocAOXqv qEcQXDkndUFrEuo6S4/+ =G4xE -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180116' into staging target-arm queue: * SDHCI: cleanups and minor bug fixes * target/arm: minor refactor preparatory to fp16 support * omap_ssd, ssi-sd, pl181, milkymist-memcard: reset the SD card on controller reset (fixes migration failures) * target/arm: Handle page table walk load failures correctly * hw/arm/virt: Add virt-2.12 machine type * get_phys_addr_pmsav7: Support AP=0b111 for v7M * hw/intc/armv7m: Support byte and halfword accesses to CFSR # gpg: Signature made Tue 16 Jan 2018 13:33:31 GMT # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20180116: (24 commits) sdhci: add a 'dma' property to the sysbus devices sdhci: fix the PCI device, using the PCI address space for DMA sdhci: Implement write method of ACMD12ERRSTS register sdhci: fix CAPAB/MAXCURR registers, both are 64bit and read-only sdhci: rename the SDHC_CAPAB register sdhci: move MASK_TRNMOD with other SDHC_TRN* defines in "sd-internal.h" sdhci: convert the DPRINT() calls into trace events sdhci: use qemu_log_mask(UNIMP) instead of fprintf() sdhci: refactor common sysbus/pci unrealize() into sdhci_common_unrealize() sdhci: refactor common sysbus/pci realize() into sdhci_common_realize() sdhci: refactor common sysbus/pci class_init() into sdhci_common_class_init() sdhci: use DEFINE_SDHCI_COMMON_PROPERTIES() for common sysbus/pci properties sdhci: remove dead code sdhci: clean up includes target/arm: Add fp16 support to vfp_expand_imm target/arm: Split out vfp_expand_imm hw/sd/omap_mmc: Reset SD card on controller reset hw/sd/ssi-sd: Reset SD card on controller reset hw/sd/milkymist-memcard: Reset SD card on controller reset hw/sd/pl181: Reset SD card on controller reset ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
aae39d24a3
|
@ -1618,7 +1618,7 @@ static void machvirt_machine_init(void)
|
|||
}
|
||||
type_init(machvirt_machine_init);
|
||||
|
||||
static void virt_2_11_instance_init(Object *obj)
|
||||
static void virt_2_12_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
|
@ -1678,10 +1678,25 @@ static void virt_2_11_instance_init(Object *obj)
|
|||
vms->irqmap = a15irqmap;
|
||||
}
|
||||
|
||||
static void virt_machine_2_11_options(MachineClass *mc)
|
||||
static void virt_machine_2_12_options(MachineClass *mc)
|
||||
{
|
||||
}
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(2, 11)
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(2, 12)
|
||||
|
||||
#define VIRT_COMPAT_2_11 \
|
||||
HW_COMPAT_2_11
|
||||
|
||||
static void virt_2_11_instance_init(Object *obj)
|
||||
{
|
||||
virt_2_12_instance_init(obj);
|
||||
}
|
||||
|
||||
static void virt_machine_2_11_options(MachineClass *mc)
|
||||
{
|
||||
virt_machine_2_12_options(mc);
|
||||
SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_11);
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(2, 11)
|
||||
|
||||
#define VIRT_COMPAT_2_10 \
|
||||
HW_COMPAT_2_10
|
||||
|
|
|
@ -896,13 +896,6 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
|||
val |= (1 << 8);
|
||||
}
|
||||
return val;
|
||||
case 0xd28: /* Configurable Fault Status. */
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy
|
||||
*/
|
||||
val = cpu->env.v7m.cfsr[attrs.secure];
|
||||
val |= cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
|
||||
return val;
|
||||
case 0xd2c: /* Hard Fault Status. */
|
||||
return cpu->env.v7m.hfsr;
|
||||
case 0xd30: /* Debug Fault Status. */
|
||||
|
@ -1280,15 +1273,6 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
|||
s->vectors[ARMV7M_EXCP_DEBUG].active = (value & (1 << 8)) != 0;
|
||||
nvic_irq_update(s);
|
||||
break;
|
||||
case 0xd28: /* Configurable Fault Status. */
|
||||
cpu->env.v7m.cfsr[attrs.secure] &= ~value; /* W1C */
|
||||
if (attrs.secure) {
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy.
|
||||
*/
|
||||
cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
|
||||
}
|
||||
break;
|
||||
case 0xd2c: /* Hard Fault Status. */
|
||||
cpu->env.v7m.hfsr &= ~value; /* W1C */
|
||||
break;
|
||||
|
@ -1667,6 +1651,14 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
|
|||
val = deposit32(val, i * 8, 8, get_prio(s, hdlidx, sbank));
|
||||
}
|
||||
break;
|
||||
case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy
|
||||
*/
|
||||
val = s->cpu->env.v7m.cfsr[attrs.secure];
|
||||
val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
|
||||
val = extract32(val, (offset - 0xd28) * 8, size * 8);
|
||||
break;
|
||||
case 0xfe0 ... 0xfff: /* ID. */
|
||||
if (offset & 3) {
|
||||
val = 0;
|
||||
|
@ -1765,6 +1757,20 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
|
|||
}
|
||||
nvic_irq_update(s);
|
||||
return MEMTX_OK;
|
||||
case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */
|
||||
/* All bits are W1C, so construct 32 bit value with 0s in
|
||||
* the parts not written by the access size
|
||||
*/
|
||||
value <<= ((offset - 0xd28) * 8);
|
||||
|
||||
s->cpu->env.v7m.cfsr[attrs.secure] &= ~value;
|
||||
if (attrs.secure) {
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy.
|
||||
*/
|
||||
s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
|
||||
}
|
||||
return MEMTX_OK;
|
||||
}
|
||||
if (size == 4) {
|
||||
nvic_writel(s, offset, value, attrs);
|
||||
|
|
|
@ -248,6 +248,10 @@ static void milkymist_memcard_reset(DeviceState *d)
|
|||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
/* Since we're still using the legacy SD API the card is not plugged
|
||||
* into any bus, and we must reset it manually.
|
||||
*/
|
||||
device_reset(DEVICE(s->card));
|
||||
}
|
||||
|
||||
static int milkymist_memcard_init(SysBusDevice *dev)
|
||||
|
|
|
@ -305,6 +305,12 @@ void omap_mmc_reset(struct omap_mmc_s *host)
|
|||
host->cdet_enable = 0;
|
||||
qemu_set_irq(host->coverswitch, host->cdet_state);
|
||||
host->clkdiv = 0;
|
||||
|
||||
/* Since we're still using the legacy SD API the card is not plugged
|
||||
* into any bus, and we must reset it manually. When omap_mmc is
|
||||
* QOMified this must move into the QOM reset function.
|
||||
*/
|
||||
device_reset(DEVICE(host->card));
|
||||
}
|
||||
|
||||
static uint64_t omap_mmc_read(void *opaque, hwaddr offset,
|
||||
|
@ -587,8 +593,6 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
|||
s->lines = 1; /* TODO: needs to be settable per-board */
|
||||
s->rev = 1;
|
||||
|
||||
omap_mmc_reset(s);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
|
@ -598,6 +602,8 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
omap_mmc_reset(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -613,8 +619,6 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
|
|||
s->lines = 4;
|
||||
s->rev = 2;
|
||||
|
||||
omap_mmc_reset(s);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &s->iomem);
|
||||
|
@ -628,6 +632,8 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
|
|||
s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
|
||||
sd_set_cb(s->card, NULL, s->cdet);
|
||||
|
||||
omap_mmc_reset(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -480,6 +480,10 @@ static void pl181_reset(DeviceState *d)
|
|||
|
||||
/* We can assume our GPIO outputs have been wired up now */
|
||||
sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
|
||||
/* Since we're still using the legacy SD API the card is not plugged
|
||||
* into any bus, and we must reset it manually.
|
||||
*/
|
||||
device_reset(DEVICE(s->card));
|
||||
}
|
||||
|
||||
static void pl181_init(Object *obj)
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#ifndef SDHCI_INTERNAL_H
|
||||
#define SDHCI_INTERNAL_H
|
||||
|
||||
#include "hw/sd/sdhci.h"
|
||||
|
||||
/* R/W SDMA System Address register 0x0 */
|
||||
#define SDHC_SYSAD 0x00
|
||||
|
||||
|
@ -45,6 +43,7 @@
|
|||
#define SDHC_TRNS_ACMD12 0x0004
|
||||
#define SDHC_TRNS_READ 0x0010
|
||||
#define SDHC_TRNS_MULTI 0x0020
|
||||
#define SDHC_TRNMOD_MASK 0x0037
|
||||
|
||||
/* R/W Command Register 0x0 */
|
||||
#define SDHC_CMDREG 0x0E
|
||||
|
@ -175,7 +174,7 @@
|
|||
#define SDHC_ACMD12ERRSTS 0x3C
|
||||
|
||||
/* HWInit Capabilities Register 0x05E80080 */
|
||||
#define SDHC_CAPAREG 0x40
|
||||
#define SDHC_CAPAB 0x40
|
||||
#define SDHC_CAN_DO_DMA 0x00400000
|
||||
#define SDHC_CAN_DO_ADMA2 0x00080000
|
||||
#define SDHC_CAN_DO_ADMA1 0x00100000
|
||||
|
@ -227,6 +226,4 @@ enum {
|
|||
sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */
|
||||
};
|
||||
|
||||
extern const VMStateDescription sdhci_vmstate;
|
||||
|
||||
#endif
|
||||
|
|
266
hw/sd/sdhci.c
266
hw/sd/sdhci.c
|
@ -23,38 +23,18 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
#include "sdhci-internal.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
/* host controller debug messages */
|
||||
#ifndef SDHC_DEBUG
|
||||
#define SDHC_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DPRINT_L1(fmt, args...) \
|
||||
do { \
|
||||
if (SDHC_DEBUG) { \
|
||||
fprintf(stderr, "QEMU SDHC: " fmt, ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DPRINT_L2(fmt, args...) \
|
||||
do { \
|
||||
if (SDHC_DEBUG > 1) { \
|
||||
fprintf(stderr, "QEMU SDHC: " fmt, ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#define ERRPRINT(fmt, args...) \
|
||||
do { \
|
||||
if (SDHC_DEBUG) { \
|
||||
fprintf(stderr, "QEMU SDHC ERROR: " fmt, ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#include "trace.h"
|
||||
|
||||
#define TYPE_SDHCI_BUS "sdhci-bus"
|
||||
#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS)
|
||||
|
@ -119,7 +99,6 @@
|
|||
(SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \
|
||||
(SDHC_CAPAB_TOCLKFREQ))
|
||||
|
||||
#define MASK_TRNMOD 0x0037
|
||||
#define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val))
|
||||
|
||||
static uint8_t sdhci_slotint(SDHCIState *s)
|
||||
|
@ -153,8 +132,8 @@ static void sdhci_raise_insertion_irq(void *opaque)
|
|||
static void sdhci_set_inserted(DeviceState *dev, bool level)
|
||||
{
|
||||
SDHCIState *s = (SDHCIState *)dev;
|
||||
DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
|
||||
|
||||
trace_sdhci_set_inserted(level ? "insert" : "eject");
|
||||
if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
|
||||
/* Give target some time to notice card ejection */
|
||||
timer_mod(s->insert_timer,
|
||||
|
@ -236,7 +215,8 @@ static void sdhci_send_command(SDHCIState *s)
|
|||
s->acmd12errsts = 0;
|
||||
request.cmd = s->cmdreg >> 8;
|
||||
request.arg = s->argument;
|
||||
DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
|
||||
|
||||
trace_sdhci_send_command(request.cmd, request.arg);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
|
||||
if (s->cmdreg & SDHC_CMD_RESPONSE) {
|
||||
|
@ -244,7 +224,7 @@ static void sdhci_send_command(SDHCIState *s)
|
|||
s->rspreg[0] = (response[0] << 24) | (response[1] << 16) |
|
||||
(response[2] << 8) | response[3];
|
||||
s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0;
|
||||
DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]);
|
||||
trace_sdhci_response4(s->rspreg[0]);
|
||||
} else if (rlen == 16) {
|
||||
s->rspreg[0] = (response[11] << 24) | (response[12] << 16) |
|
||||
(response[13] << 8) | response[14];
|
||||
|
@ -254,11 +234,10 @@ static void sdhci_send_command(SDHCIState *s)
|
|||
(response[5] << 8) | response[6];
|
||||
s->rspreg[3] = (response[0] << 16) | (response[1] << 8) |
|
||||
response[2];
|
||||
DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.."
|
||||
"64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n",
|
||||
s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]);
|
||||
trace_sdhci_response16(s->rspreg[3], s->rspreg[2],
|
||||
s->rspreg[1], s->rspreg[0]);
|
||||
} else {
|
||||
ERRPRINT("Timeout waiting for command response\n");
|
||||
trace_sdhci_error("timeout waiting for command response");
|
||||
if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) {
|
||||
s->errintsts |= SDHC_EIS_CMDTIMEOUT;
|
||||
s->norintsts |= SDHC_NIS_ERR;
|
||||
|
@ -292,7 +271,7 @@ static void sdhci_end_transfer(SDHCIState *s)
|
|||
|
||||
request.cmd = 0x0C;
|
||||
request.arg = 0;
|
||||
DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
|
||||
trace_sdhci_end_transfer(request.cmd, request.arg);
|
||||
sdbus_do_command(&s->sdbus, &request, response);
|
||||
/* Auto CMD12 response goes to the upper Response register */
|
||||
s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
|
||||
|
@ -361,7 +340,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
|
|||
|
||||
/* first check that a valid data exists in host controller input buffer */
|
||||
if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) {
|
||||
ERRPRINT("Trying to read from empty buffer\n");
|
||||
trace_sdhci_error("read from empty buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -370,8 +349,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
|
|||
s->data_count++;
|
||||
/* check if we've read all valid data (blksize bytes) from buffer */
|
||||
if ((s->data_count) >= (s->blksize & 0x0fff)) {
|
||||
DPRINT_L2("All %u bytes of data have been read from input buffer\n",
|
||||
s->data_count);
|
||||
trace_sdhci_read_dataport(s->data_count);
|
||||
s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */
|
||||
s->data_count = 0; /* next buff read must start at position [0] */
|
||||
|
||||
|
@ -454,7 +432,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
|
|||
|
||||
/* Check that there is free space left in a buffer */
|
||||
if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) {
|
||||
ERRPRINT("Can't write to data buffer: buffer full\n");
|
||||
trace_sdhci_error("Can't write to data buffer: buffer full");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -463,8 +441,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
|
|||
s->data_count++;
|
||||
value >>= 8;
|
||||
if (s->data_count >= (s->blksize & 0x0fff)) {
|
||||
DPRINT_L2("write buffer filled with %u bytes of data\n",
|
||||
s->data_count);
|
||||
trace_sdhci_write_dataport(s->data_count);
|
||||
s->data_count = 0;
|
||||
s->prnsts &= ~SDHC_SPACE_AVAILABLE;
|
||||
if (s->prnsts & SDHC_DOING_WRITE) {
|
||||
|
@ -519,7 +496,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
|||
s->blkcnt--;
|
||||
}
|
||||
}
|
||||
dma_memory_write(&address_space_memory, s->sdmasysad,
|
||||
dma_memory_write(s->dma_as, s->sdmasysad,
|
||||
&s->fifo_buffer[begin], s->data_count - begin);
|
||||
s->sdmasysad += s->data_count - begin;
|
||||
if (s->data_count == block_size) {
|
||||
|
@ -541,7 +518,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
|||
s->data_count = block_size;
|
||||
boundary_count -= block_size - begin;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, s->sdmasysad,
|
||||
dma_memory_read(s->dma_as, s->sdmasysad,
|
||||
&s->fifo_buffer[begin], s->data_count - begin);
|
||||
s->sdmasysad += s->data_count - begin;
|
||||
if (s->data_count == block_size) {
|
||||
|
@ -579,11 +556,9 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
|
|||
for (n = 0; n < datacnt; n++) {
|
||||
s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
|
||||
}
|
||||
dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer,
|
||||
datacnt);
|
||||
dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt);
|
||||
} else {
|
||||
dma_memory_read(&address_space_memory, 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[n]);
|
||||
}
|
||||
|
@ -607,7 +582,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
|
|||
hwaddr entry_addr = (hwaddr)s->admasysaddr;
|
||||
switch (SDHC_DMA_TYPE(s->hostctl)) {
|
||||
case SDHC_CTRL_ADMA2_32:
|
||||
dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma2,
|
||||
dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma2,
|
||||
sizeof(adma2));
|
||||
adma2 = le64_to_cpu(adma2);
|
||||
/* The spec does not specify endianness of descriptor table.
|
||||
|
@ -619,7 +594,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
|
|||
dscr->incr = 8;
|
||||
break;
|
||||
case SDHC_CTRL_ADMA1_32:
|
||||
dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma1,
|
||||
dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma1,
|
||||
sizeof(adma1));
|
||||
adma1 = le32_to_cpu(adma1);
|
||||
dscr->addr = (hwaddr)(adma1 & 0xFFFFF000);
|
||||
|
@ -632,12 +607,12 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
|
|||
}
|
||||
break;
|
||||
case SDHC_CTRL_ADMA2_64:
|
||||
dma_memory_read(&address_space_memory, entry_addr,
|
||||
dma_memory_read(s->dma_as, entry_addr,
|
||||
(uint8_t *)(&dscr->attr), 1);
|
||||
dma_memory_read(&address_space_memory, entry_addr + 2,
|
||||
dma_memory_read(s->dma_as, entry_addr + 2,
|
||||
(uint8_t *)(&dscr->length), 2);
|
||||
dscr->length = le16_to_cpu(dscr->length);
|
||||
dma_memory_read(&address_space_memory, entry_addr + 4,
|
||||
dma_memory_read(s->dma_as, entry_addr + 4,
|
||||
(uint8_t *)(&dscr->addr), 8);
|
||||
dscr->attr = le64_to_cpu(dscr->attr);
|
||||
dscr->attr &= 0xfffffff8;
|
||||
|
@ -652,15 +627,14 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
{
|
||||
unsigned int n, begin, length;
|
||||
const uint16_t block_size = s->blksize & 0x0fff;
|
||||
ADMADescr dscr;
|
||||
ADMADescr dscr = {};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
|
||||
s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;
|
||||
|
||||
get_adma_description(s, &dscr);
|
||||
DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n",
|
||||
dscr.addr, dscr.length, dscr.attr);
|
||||
trace_sdhci_adma_loop(dscr.addr, dscr.length, dscr.attr);
|
||||
|
||||
if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) {
|
||||
/* Indicate that error occurred in ST_FDS state */
|
||||
|
@ -697,7 +671,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
s->data_count = block_size;
|
||||
length -= block_size - begin;
|
||||
}
|
||||
dma_memory_write(&address_space_memory, dscr.addr,
|
||||
dma_memory_write(s->dma_as, dscr.addr,
|
||||
&s->fifo_buffer[begin],
|
||||
s->data_count - begin);
|
||||
dscr.addr += s->data_count - begin;
|
||||
|
@ -721,7 +695,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
s->data_count = block_size;
|
||||
length -= block_size - begin;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, dscr.addr,
|
||||
dma_memory_read(s->dma_as, dscr.addr,
|
||||
&s->fifo_buffer[begin],
|
||||
s->data_count - begin);
|
||||
dscr.addr += s->data_count - begin;
|
||||
|
@ -743,8 +717,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
break;
|
||||
case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */
|
||||
s->admasysaddr = dscr.addr;
|
||||
DPRINT_L1("ADMA link: admasysaddr=0x%" PRIx64 "\n",
|
||||
s->admasysaddr);
|
||||
trace_sdhci_adma("link", s->admasysaddr);
|
||||
break;
|
||||
default:
|
||||
s->admasysaddr += dscr.incr;
|
||||
|
@ -752,8 +725,7 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
}
|
||||
|
||||
if (dscr.attr & SDHC_ADMA_ATTR_INT) {
|
||||
DPRINT_L1("ADMA interrupt: admasysaddr=0x%" PRIx64 "\n",
|
||||
s->admasysaddr);
|
||||
trace_sdhci_adma("interrupt", s->admasysaddr);
|
||||
if (s->norintstsen & SDHC_NISEN_DMA) {
|
||||
s->norintsts |= SDHC_NIS_DMA;
|
||||
}
|
||||
|
@ -764,15 +736,15 @@ static void sdhci_do_adma(SDHCIState *s)
|
|||
/* ADMA transfer terminates if blkcnt == 0 or by END attribute */
|
||||
if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
|
||||
(s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
|
||||
DPRINT_L2("ADMA transfer completed\n");
|
||||
trace_sdhci_adma_transfer_completed();
|
||||
if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) &&
|
||||
(s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
|
||||
s->blkcnt != 0)) {
|
||||
ERRPRINT("SD/MMC host ADMA length mismatch\n");
|
||||
trace_sdhci_error("SD/MMC host ADMA length mismatch");
|
||||
s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH |
|
||||
SDHC_ADMAERR_STATE_ST_TFR;
|
||||
if (s->errintstsen & SDHC_EISEN_ADMAERR) {
|
||||
ERRPRINT("Set ADMA error flag\n");
|
||||
trace_sdhci_error("Set ADMA error flag");
|
||||
s->errintsts |= SDHC_EIS_ADMAERR;
|
||||
s->norintsts |= SDHC_NIS_ERR;
|
||||
}
|
||||
|
@ -808,7 +780,7 @@ static void sdhci_data_transfer(void *opaque)
|
|||
break;
|
||||
case SDHC_CTRL_ADMA1_32:
|
||||
if (!(s->capareg & SDHC_CAN_DO_ADMA1)) {
|
||||
ERRPRINT("ADMA1 not supported\n");
|
||||
trace_sdhci_error("ADMA1 not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -816,7 +788,7 @@ static void sdhci_data_transfer(void *opaque)
|
|||
break;
|
||||
case SDHC_CTRL_ADMA2_32:
|
||||
if (!(s->capareg & SDHC_CAN_DO_ADMA2)) {
|
||||
ERRPRINT("ADMA2 not supported\n");
|
||||
trace_sdhci_error("ADMA2 not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -825,14 +797,14 @@ static void sdhci_data_transfer(void *opaque)
|
|||
case SDHC_CTRL_ADMA2_64:
|
||||
if (!(s->capareg & SDHC_CAN_DO_ADMA2) ||
|
||||
!(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) {
|
||||
ERRPRINT("64 bit ADMA not supported\n");
|
||||
trace_sdhci_error("64 bit ADMA not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
sdhci_do_adma(s);
|
||||
break;
|
||||
default:
|
||||
ERRPRINT("Unsupported DMA type\n");
|
||||
trace_sdhci_error("Unsupported DMA type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -867,8 +839,8 @@ static inline bool
|
|||
sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
|
||||
{
|
||||
if ((s->data_count & 0x3) != byte_num) {
|
||||
ERRPRINT("Non-sequential access to Buffer Data Port register"
|
||||
"is prohibited\n");
|
||||
trace_sdhci_error("Non-sequential access to Buffer Data Port register"
|
||||
"is prohibited\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -898,8 +870,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size)
|
|||
case SDHC_BDATA:
|
||||
if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
|
||||
ret = sdhci_read_dataport(s, size);
|
||||
DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset,
|
||||
ret, ret);
|
||||
trace_sdhci_access("rd", size << 3, offset, "->", ret, ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
@ -925,11 +896,17 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size)
|
|||
case SDHC_ACMD12ERRSTS:
|
||||
ret = s->acmd12errsts;
|
||||
break;
|
||||
case SDHC_CAPAREG:
|
||||
ret = s->capareg;
|
||||
case SDHC_CAPAB:
|
||||
ret = (uint32_t)s->capareg;
|
||||
break;
|
||||
case SDHC_CAPAB + 4:
|
||||
ret = (uint32_t)(s->capareg >> 32);
|
||||
break;
|
||||
case SDHC_MAXCURR:
|
||||
ret = s->maxcurr;
|
||||
ret = (uint32_t)s->maxcurr;
|
||||
break;
|
||||
case SDHC_MAXCURR + 4:
|
||||
ret = (uint32_t)(s->maxcurr >> 32);
|
||||
break;
|
||||
case SDHC_ADMAERR:
|
||||
ret = s->admaerr;
|
||||
|
@ -944,13 +921,14 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size)
|
|||
ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s);
|
||||
break;
|
||||
default:
|
||||
ERRPRINT("bad %ub read: addr[0x%04x]\n", size, (int)offset);
|
||||
qemu_log_mask(LOG_UNIMP, "SDHC rd_%ub @0x%02" HWADDR_PRIx " "
|
||||
"not implemented\n", size, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
ret >>= (offset & 0x3) * 8;
|
||||
ret &= (1ULL << (size * 8)) - 1;
|
||||
DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, ret, ret);
|
||||
trace_sdhci_access("rd", size << 3, offset, "->", ret, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1029,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
|||
if (!(s->capareg & SDHC_CAN_DO_DMA)) {
|
||||
value &= ~SDHC_TRNS_DMA;
|
||||
}
|
||||
MASKED_WRITE(s->trnmod, mask, value & MASK_TRNMOD);
|
||||
MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK);
|
||||
MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
|
||||
|
||||
/* Writing to the upper byte of CMDREG triggers SD command generation */
|
||||
|
@ -1149,13 +1127,25 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
|||
}
|
||||
sdhci_update_irq(s);
|
||||
break;
|
||||
case SDHC_ACMD12ERRSTS:
|
||||
MASKED_WRITE(s->acmd12errsts, mask, value);
|
||||
break;
|
||||
|
||||
case SDHC_CAPAB:
|
||||
case SDHC_CAPAB + 4:
|
||||
case SDHC_MAXCURR:
|
||||
case SDHC_MAXCURR + 4:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "SDHC wr_%ub @0x%02" HWADDR_PRIx
|
||||
" <- 0x%08x read-only\n", size, offset, value >> shift);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n",
|
||||
size, (int)offset, value >> shift, value >> shift);
|
||||
qemu_log_mask(LOG_UNIMP, "SDHC wr_%ub @0x%02" HWADDR_PRIx " <- 0x%08x "
|
||||
"not implemented\n", size, offset, value >> shift);
|
||||
break;
|
||||
}
|
||||
DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n",
|
||||
size, (int)offset, value >> shift, value >> shift);
|
||||
trace_sdhci_access("wr", size << 3, offset, "<-",
|
||||
value >> shift, value >> shift);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sdhci_mmio_ops = {
|
||||
|
@ -1184,6 +1174,14 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
|
|||
}
|
||||
}
|
||||
|
||||
/* --- qdev common --- */
|
||||
|
||||
#define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \
|
||||
/* Capabilities registers provide information on supported features
|
||||
* of this specific host controller implementation */ \
|
||||
DEFINE_PROP_UINT64("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \
|
||||
DEFINE_PROP_UINT64("maxcurr", _state, maxcurr, 0)
|
||||
|
||||
static void sdhci_initfn(SDHCIState *s)
|
||||
{
|
||||
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
|
||||
|
@ -1199,13 +1197,31 @@ static void sdhci_uninitfn(SDHCIState *s)
|
|||
timer_free(s->insert_timer);
|
||||
timer_del(s->transfer_timer);
|
||||
timer_free(s->transfer_timer);
|
||||
qemu_free_irq(s->eject_cb);
|
||||
qemu_free_irq(s->ro_cb);
|
||||
|
||||
g_free(s->fifo_buffer);
|
||||
s->fifo_buffer = NULL;
|
||||
}
|
||||
|
||||
static void sdhci_common_realize(SDHCIState *s, Error **errp)
|
||||
{
|
||||
s->buf_maxsz = sdhci_get_fifolen(s);
|
||||
s->fifo_buffer = g_malloc0(s->buf_maxsz);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
|
||||
SDHC_REGISTERS_MAP_SIZE);
|
||||
}
|
||||
|
||||
static void sdhci_common_unrealize(SDHCIState *s, Error **errp)
|
||||
{
|
||||
/* This function is expected to be called only once for each class:
|
||||
* - SysBus: via DeviceClass->unrealize(),
|
||||
* - PCI: via PCIDeviceClass->exit().
|
||||
* However to avoid double-free and/or use-after-free we still nullify
|
||||
* this variable (better safe than sorry!). */
|
||||
g_free(s->fifo_buffer);
|
||||
s->fifo_buffer = NULL;
|
||||
}
|
||||
|
||||
static bool sdhci_pending_insert_vmstate_needed(void *opaque)
|
||||
{
|
||||
SDHCIState *s = opaque;
|
||||
|
@ -1265,32 +1281,44 @@ const VMStateDescription sdhci_vmstate = {
|
|||
},
|
||||
};
|
||||
|
||||
/* Capabilities registers provide information on supported features of this
|
||||
* specific host controller implementation */
|
||||
static void sdhci_common_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->vmsd = &sdhci_vmstate;
|
||||
dc->reset = sdhci_poweron_reset;
|
||||
}
|
||||
|
||||
/* --- qdev PCI --- */
|
||||
|
||||
static Property sdhci_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
|
||||
SDHC_CAPAB_REG_DEFAULT),
|
||||
DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
|
||||
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
SDHCIState *s = PCI_SDHCI(dev);
|
||||
|
||||
sdhci_initfn(s);
|
||||
sdhci_common_realize(s, errp);
|
||||
if (errp && *errp) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
|
||||
dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
|
||||
sdhci_initfn(s);
|
||||
s->buf_maxsz = sdhci_get_fifolen(s);
|
||||
s->fifo_buffer = g_malloc0(s->buf_maxsz);
|
||||
s->irq = pci_allocate_irq(dev);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
|
||||
SDHC_REGISTERS_MAP_SIZE);
|
||||
pci_register_bar(dev, 0, 0, &s->iomem);
|
||||
s->dma_as = pci_get_address_space(dev);
|
||||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem);
|
||||
}
|
||||
|
||||
static void sdhci_pci_exit(PCIDevice *dev)
|
||||
{
|
||||
SDHCIState *s = PCI_SDHCI(dev);
|
||||
|
||||
sdhci_common_unrealize(s, &error_abort);
|
||||
sdhci_uninitfn(s);
|
||||
}
|
||||
|
||||
|
@ -1304,10 +1332,9 @@ static void sdhci_pci_class_init(ObjectClass *klass, void *data)
|
|||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI;
|
||||
k->class_id = PCI_CLASS_SYSTEM_SDHCI;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->vmsd = &sdhci_vmstate;
|
||||
dc->props = sdhci_pci_properties;
|
||||
dc->reset = sdhci_poweron_reset;
|
||||
|
||||
sdhci_common_class_init(klass, data);
|
||||
}
|
||||
|
||||
static const TypeInfo sdhci_pci_info = {
|
||||
|
@ -1321,12 +1348,14 @@ static const TypeInfo sdhci_pci_info = {
|
|||
},
|
||||
};
|
||||
|
||||
/* --- qdev SysBus --- */
|
||||
|
||||
static Property sdhci_sysbus_properties[] = {
|
||||
DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
|
||||
SDHC_CAPAB_REG_DEFAULT),
|
||||
DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
|
||||
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
|
||||
DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
|
||||
false),
|
||||
DEFINE_PROP_LINK("dma", SDHCIState,
|
||||
dma_mr, TYPE_MEMORY_REGION, MemoryRegion *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -1340,6 +1369,11 @@ static void sdhci_sysbus_init(Object *obj)
|
|||
static void sdhci_sysbus_finalize(Object *obj)
|
||||
{
|
||||
SDHCIState *s = SYSBUS_SDHCI(obj);
|
||||
|
||||
if (s->dma_mr) {
|
||||
object_unparent(OBJECT(s->dma_mr));
|
||||
}
|
||||
|
||||
sdhci_uninitfn(s);
|
||||
}
|
||||
|
||||
|
@ -1348,22 +1382,42 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
|
|||
SDHCIState *s = SYSBUS_SDHCI(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->buf_maxsz = sdhci_get_fifolen(s);
|
||||
s->fifo_buffer = g_malloc0(s->buf_maxsz);
|
||||
sdhci_common_realize(s, errp);
|
||||
if (errp && *errp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->dma_mr) {
|
||||
address_space_init(s->dma_as, s->dma_mr, "sdhci-dma");
|
||||
} else {
|
||||
/* use system_memory() if property "dma" not set */
|
||||
s->dma_as = &address_space_memory;
|
||||
}
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
|
||||
SDHC_REGISTERS_MAP_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void sdhci_sysbus_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SDHCIState *s = SYSBUS_SDHCI(dev);
|
||||
|
||||
sdhci_common_unrealize(s, &error_abort);
|
||||
|
||||
if (s->dma_mr) {
|
||||
address_space_destroy(s->dma_as);
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &sdhci_vmstate;
|
||||
dc->props = sdhci_sysbus_properties;
|
||||
dc->realize = sdhci_sysbus_realize;
|
||||
dc->reset = sdhci_poweron_reset;
|
||||
dc->unrealize = sdhci_sysbus_unrealize;
|
||||
|
||||
sdhci_common_class_init(klass, data);
|
||||
}
|
||||
|
||||
static const TypeInfo sdhci_sysbus_info = {
|
||||
|
@ -1375,6 +1429,8 @@ static const TypeInfo sdhci_sysbus_info = {
|
|||
.class_init = sdhci_sysbus_class_init,
|
||||
};
|
||||
|
||||
/* --- qdev bus master --- */
|
||||
|
||||
static void sdhci_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SDBusClass *sbc = SD_BUS_CLASS(klass);
|
||||
|
|
|
@ -50,6 +50,9 @@ typedef struct {
|
|||
SDState *sd;
|
||||
} ssi_sd_state;
|
||||
|
||||
#define TYPE_SSI_SD "ssi-sd"
|
||||
#define SSI_SD(obj) OBJECT_CHECK(ssi_sd_state, (obj), TYPE_SSI_SD)
|
||||
|
||||
/* State word bits. */
|
||||
#define SSI_SDR_LOCKED 0x0001
|
||||
#define SSI_SDR_WP_ERASE 0x0002
|
||||
|
@ -241,7 +244,6 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
|
|||
ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
|
||||
DriveInfo *dinfo;
|
||||
|
||||
s->mode = SSI_SD_CMD;
|
||||
/* FIXME use a qdev drive property instead of drive_get_next() */
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true);
|
||||
|
@ -251,6 +253,24 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void ssi_sd_reset(DeviceState *dev)
|
||||
{
|
||||
ssi_sd_state *s = SSI_SD(dev);
|
||||
|
||||
s->mode = SSI_SD_CMD;
|
||||
s->cmd = 0;
|
||||
memset(s->cmdarg, 0, sizeof(s->cmdarg));
|
||||
memset(s->response, 0, sizeof(s->response));
|
||||
s->arglen = 0;
|
||||
s->response_pos = 0;
|
||||
s->stopping = 0;
|
||||
|
||||
/* Since we're still using the legacy SD API the card is not plugged
|
||||
* into any bus, and we must reset it manually.
|
||||
*/
|
||||
device_reset(DEVICE(s->sd));
|
||||
}
|
||||
|
||||
static void ssi_sd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
@ -260,10 +280,11 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
|
|||
k->transfer = ssi_sd_transfer;
|
||||
k->cs_polarity = SSI_CS_LOW;
|
||||
dc->vmsd = &vmstate_ssi_sd;
|
||||
dc->reset = ssi_sd_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo ssi_sd_info = {
|
||||
.name = "ssi-sd",
|
||||
.name = TYPE_SSI_SD,
|
||||
.parent = TYPE_SSI_SLAVE,
|
||||
.instance_size = sizeof(ssi_sd_state),
|
||||
.class_init = ssi_sd_class_init,
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# hw/sd/sdhci.c
|
||||
sdhci_set_inserted(const char *level) "card state changed: %s"
|
||||
sdhci_send_command(uint8_t cmd, uint32_t arg) "CMD%02u ARG[0x%08x]"
|
||||
sdhci_error(const char *msg) "%s"
|
||||
sdhci_response4(uint32_t r0) "RSPREG[31..0]=0x%08x"
|
||||
sdhci_response16(uint32_t r3, uint32_t r2, uint32_t r1, uint32_t r0) "RSPREG[127..96]=0x%08x, RSPREG[95..64]=0x%08x, RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x"
|
||||
sdhci_end_transfer(uint8_t cmd, uint32_t arg) "Automatically issue CMD%02u 0x%08x"
|
||||
sdhci_adma(const char *desc, uint32_t sysad) "%s: admasysaddr=0x%" PRIx32
|
||||
sdhci_adma_loop(uint64_t addr, uint16_t length, uint8_t attr) "addr=0x%08" PRIx64 ", len=%d, attr=0x%x"
|
||||
sdhci_adma_transfer_completed(void) ""
|
||||
sdhci_access(const char *access, unsigned int size, uint64_t offset, const char *dir, uint64_t val, uint64_t val2) "%s%u: addr[0x%04" PRIx64 "] %s 0x%08" PRIx64 " (%" PRIu64 ")"
|
||||
sdhci_read_dataport(uint16_t data_count) "all %u bytes of data have been read from input buffer"
|
||||
sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of data"
|
||||
|
||||
# hw/sd/milkymist-memcard.c
|
||||
milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
|
|
|
@ -26,26 +26,29 @@
|
|||
#define SDHCI_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
/* SD/MMC host controller state */
|
||||
typedef struct SDHCIState {
|
||||
/*< private >*/
|
||||
union {
|
||||
PCIDevice pcidev;
|
||||
SysBusDevice busdev;
|
||||
};
|
||||
|
||||
/*< public >*/
|
||||
SDBus sdbus;
|
||||
MemoryRegion iomem;
|
||||
AddressSpace *dma_as;
|
||||
MemoryRegion *dma_mr;
|
||||
|
||||
QEMUTimer *insert_timer; /* timer for 'changing' sd card. */
|
||||
QEMUTimer *transfer_timer;
|
||||
qemu_irq eject_cb;
|
||||
qemu_irq ro_cb;
|
||||
qemu_irq irq;
|
||||
|
||||
/* Registers cleared on reset */
|
||||
uint32_t sdmasysad; /* SDMA System Address register */
|
||||
uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */
|
||||
uint16_t blkcnt; /* Blocks count for current transfer */
|
||||
|
@ -70,19 +73,23 @@ typedef struct SDHCIState {
|
|||
uint16_t acmd12errsts; /* Auto CMD12 error status register */
|
||||
uint64_t admasysaddr; /* ADMA System Address Register */
|
||||
|
||||
uint32_t capareg; /* Capabilities Register */
|
||||
uint32_t maxcurr; /* Maximum Current Capabilities Register */
|
||||
/* Read-only registers */
|
||||
uint64_t capareg; /* Capabilities Register */
|
||||
uint64_t maxcurr; /* Maximum Current Capabilities Register */
|
||||
|
||||
uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */
|
||||
uint32_t buf_maxsz;
|
||||
uint16_t data_count; /* current element in FIFO buffer */
|
||||
uint8_t stopped_state;/* Current SDHC state */
|
||||
bool pending_insert_quirk;/* Quirk for Raspberry Pi card insert int */
|
||||
bool pending_insert_state;
|
||||
/* Buffer Data Port Register - virtual access point to R and W buffers */
|
||||
/* Software Reset Register - always reads as 0 */
|
||||
/* Force Event Auto CMD12 Error Interrupt Reg - write only */
|
||||
/* Force Event Error Interrupt Register- write only */
|
||||
/* RO Host Controller Version Register always reads as 0x2401 */
|
||||
|
||||
/* Configurable properties */
|
||||
bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */
|
||||
} SDHCIState;
|
||||
|
||||
#define TYPE_PCI_SDHCI "sdhci-pci"
|
||||
|
|
|
@ -8305,6 +8305,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
|
|||
ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa,
|
||||
&txattrs, &s2prot, &s2size, fi, NULL);
|
||||
if (ret) {
|
||||
assert(fi->type != ARMFault_None);
|
||||
fi->s2addr = addr;
|
||||
fi->stage2 = true;
|
||||
fi->s1ptw = true;
|
||||
|
@ -8328,7 +8329,9 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
|||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
MemTxAttrs attrs = {};
|
||||
MemTxResult result = MEMTX_OK;
|
||||
AddressSpace *as;
|
||||
uint32_t data;
|
||||
|
||||
attrs.secure = is_secure;
|
||||
as = arm_addressspace(cs, attrs);
|
||||
|
@ -8337,10 +8340,16 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
|||
return 0;
|
||||
}
|
||||
if (regime_translation_big_endian(env, mmu_idx)) {
|
||||
return address_space_ldl_be(as, addr, attrs, NULL);
|
||||
data = address_space_ldl_be(as, addr, attrs, &result);
|
||||
} else {
|
||||
return address_space_ldl_le(as, addr, attrs, NULL);
|
||||
data = address_space_ldl_le(as, addr, attrs, &result);
|
||||
}
|
||||
if (result == MEMTX_OK) {
|
||||
return data;
|
||||
}
|
||||
fi->type = ARMFault_SyncExternalOnWalk;
|
||||
fi->ea = arm_extabort_type(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
||||
|
@ -8349,7 +8358,9 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
|||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
MemTxAttrs attrs = {};
|
||||
MemTxResult result = MEMTX_OK;
|
||||
AddressSpace *as;
|
||||
uint32_t data;
|
||||
|
||||
attrs.secure = is_secure;
|
||||
as = arm_addressspace(cs, attrs);
|
||||
|
@ -8358,10 +8369,16 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
|||
return 0;
|
||||
}
|
||||
if (regime_translation_big_endian(env, mmu_idx)) {
|
||||
return address_space_ldq_be(as, addr, attrs, NULL);
|
||||
data = address_space_ldq_be(as, addr, attrs, &result);
|
||||
} else {
|
||||
return address_space_ldq_le(as, addr, attrs, NULL);
|
||||
data = address_space_ldq_le(as, addr, attrs, &result);
|
||||
}
|
||||
if (result == MEMTX_OK) {
|
||||
return data;
|
||||
}
|
||||
fi->type = ARMFault_SyncExternalOnWalk;
|
||||
fi->ea = arm_extabort_type(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
|
||||
|
@ -8390,6 +8407,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
|
|||
}
|
||||
desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx),
|
||||
mmu_idx, fi);
|
||||
if (fi->type != ARMFault_None) {
|
||||
goto do_fault;
|
||||
}
|
||||
type = (desc & 3);
|
||||
domain = (desc >> 5) & 0x0f;
|
||||
if (regime_el(env, mmu_idx) == 1) {
|
||||
|
@ -8426,6 +8446,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
|
|||
}
|
||||
desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx),
|
||||
mmu_idx, fi);
|
||||
if (fi->type != ARMFault_None) {
|
||||
goto do_fault;
|
||||
}
|
||||
switch (desc & 3) {
|
||||
case 0: /* Page translation fault. */
|
||||
fi->type = ARMFault_Translation;
|
||||
|
@ -8508,6 +8531,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
|
|||
}
|
||||
desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx),
|
||||
mmu_idx, fi);
|
||||
if (fi->type != ARMFault_None) {
|
||||
goto do_fault;
|
||||
}
|
||||
type = (desc & 3);
|
||||
if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) {
|
||||
/* Section translation fault, or attempt to use the encoding
|
||||
|
@ -8559,6 +8585,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
|
|||
table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
|
||||
desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx),
|
||||
mmu_idx, fi);
|
||||
if (fi->type != ARMFault_None) {
|
||||
goto do_fault;
|
||||
}
|
||||
ap = ((desc >> 4) & 3) | ((desc >> 7) & 4);
|
||||
switch (desc & 3) {
|
||||
case 0: /* Page translation fault. */
|
||||
|
@ -8964,7 +8993,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
|||
descaddr &= ~7ULL;
|
||||
nstable = extract32(tableattrs, 4, 1);
|
||||
descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi);
|
||||
if (fi->s1ptw) {
|
||||
if (fi->type != ARMFault_None) {
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
|
@ -9272,6 +9301,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
|||
case 6:
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
case 7:
|
||||
/* for v7M, same as 6; for R profile a reserved value */
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"DRACR[%d]: Bad value for AP bits: 0x%"
|
||||
|
@ -9290,6 +9326,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
|||
case 6:
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
case 7:
|
||||
/* for v7M, same as 6; for R profile a reserved value */
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
*prot |= PAGE_READ | PAGE_EXEC;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"DRACR[%d]: Bad value for AP bits: 0x%"
|
||||
|
|
|
@ -687,6 +687,16 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi)
|
|||
return fsc;
|
||||
}
|
||||
|
||||
static inline bool arm_extabort_type(MemTxResult result)
|
||||
{
|
||||
/* The EA bit in syndromes and fault status registers is an
|
||||
* IMPDEF classification of external aborts. ARM implementations
|
||||
* usually use this to indicate AXI bus Decode error (0) or
|
||||
* Slave error (1); in QEMU we follow that.
|
||||
*/
|
||||
return result != MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
/* Do a page table walk and add page to TLB if possible */
|
||||
bool arm_tlb_fill(CPUState *cpu, vaddr address,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
|
|
|
@ -220,12 +220,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
|||
/* now we have a real cpu fault */
|
||||
cpu_restore_state(cs, retaddr);
|
||||
|
||||
/* The EA bit in syndromes and fault status registers is an
|
||||
* IMPDEF classification of external aborts. ARM implementations
|
||||
* usually use this to indicate AXI bus Decode error (0) or
|
||||
* Slave error (1); in QEMU we follow that.
|
||||
*/
|
||||
fi.ea = (response != MEMTX_DECODE_ERROR);
|
||||
fi.ea = arm_extabort_type(response);
|
||||
fi.type = ARMFault_SyncExternal;
|
||||
deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
|
||||
}
|
||||
|
|
|
@ -4985,6 +4985,38 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* The imm8 encodes the sign bit, enough bits to represent an exponent in
|
||||
* the range 01....1xx to 10....0xx, and the most significant 4 bits of
|
||||
* the mantissa; see VFPExpandImm() in the v8 ARM ARM.
|
||||
*/
|
||||
static uint64_t vfp_expand_imm(int size, uint8_t imm8)
|
||||
{
|
||||
uint64_t imm;
|
||||
|
||||
switch (size) {
|
||||
case MO_64:
|
||||
imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
|
||||
(extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
|
||||
extract32(imm8, 0, 6);
|
||||
imm <<= 48;
|
||||
break;
|
||||
case MO_32:
|
||||
imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
|
||||
(extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
|
||||
(extract32(imm8, 0, 6) << 3);
|
||||
imm <<= 16;
|
||||
break;
|
||||
case MO_16:
|
||||
imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
|
||||
(extract32(imm8, 6, 1) ? 0x3000 : 0x4000) |
|
||||
(extract32(imm8, 0, 6) << 6);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return imm;
|
||||
}
|
||||
|
||||
/* Floating point immediate
|
||||
* 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------------+-------+------+------+
|
||||
|
@ -5008,22 +5040,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn)
|
|||
return;
|
||||
}
|
||||
|
||||
/* The imm8 encodes the sign bit, enough bits to represent
|
||||
* an exponent in the range 01....1xx to 10....0xx,
|
||||
* and the most significant 4 bits of the mantissa; see
|
||||
* VFPExpandImm() in the v8 ARM ARM.
|
||||
*/
|
||||
if (is_double) {
|
||||
imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
|
||||
(extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
|
||||
extract32(imm8, 0, 6);
|
||||
imm <<= 48;
|
||||
} else {
|
||||
imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
|
||||
(extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
|
||||
(extract32(imm8, 0, 6) << 3);
|
||||
imm <<= 16;
|
||||
}
|
||||
imm = vfp_expand_imm(MO_32 + is_double, imm8);
|
||||
|
||||
tcg_res = tcg_const_i64(imm);
|
||||
write_fp_dreg(s, rd, tcg_res);
|
||||
|
|
Loading…
Reference in New Issue