sdhci: add quirk property for card insert interrupt status on Raspberry Pi
This quirk is a workaround for the following hardware behaviour, on which UEFI (specifically, the bootloader for Windows on Pi2) depends: 1. at boot with an SD card present, the interrupt status/enable registers are initially zero 2. upon enabling it in the interrupt enable register, the card insert bit in the interrupt status register is immediately set 3. after a subsequent controller reset, the card insert interrupt does not fire, even if enabled in the interrupt enable register Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com> Message-id: 1456436130-7048-3-git-send-email-Andrew.Baumann@microsoft.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
							parent
							
								
									5c1bc9a234
								
							
						
					
					
						commit
						0a7ac9f9e7
					
				@ -204,6 +204,7 @@ static void sdhci_reset(SDHCIState *s)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    s->data_count = 0;
 | 
					    s->data_count = 0;
 | 
				
			||||||
    s->stopped_state = sdhc_not_stopped;
 | 
					    s->stopped_state = sdhc_not_stopped;
 | 
				
			||||||
 | 
					    s->pending_insert_state = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sdhci_data_transfer(void *opaque);
 | 
					static void sdhci_data_transfer(void *opaque);
 | 
				
			||||||
@ -1095,6 +1096,13 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            s->norintsts &= ~SDHC_NIS_ERR;
 | 
					            s->norintsts &= ~SDHC_NIS_ERR;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        /* Quirk for Raspberry Pi: pending card insert interrupt
 | 
				
			||||||
 | 
					         * appears when first enabled after power on */
 | 
				
			||||||
 | 
					        if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) {
 | 
				
			||||||
 | 
					            assert(s->pending_insert_quirk);
 | 
				
			||||||
 | 
					            s->norintsts |= SDHC_NIS_INSERT;
 | 
				
			||||||
 | 
					            s->pending_insert_state = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        sdhci_update_irq(s);
 | 
					        sdhci_update_irq(s);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SDHC_NORINTSIGEN:
 | 
					    case SDHC_NORINTSIGEN:
 | 
				
			||||||
@ -1181,6 +1189,24 @@ static void sdhci_uninitfn(SDHCIState *s)
 | 
				
			|||||||
    s->fifo_buffer = NULL;
 | 
					    s->fifo_buffer = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool sdhci_pending_insert_vmstate_needed(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SDHCIState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s->pending_insert_state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const VMStateDescription sdhci_pending_insert_vmstate = {
 | 
				
			||||||
 | 
					    .name = "sdhci/pending-insert",
 | 
				
			||||||
 | 
					    .version_id = 1,
 | 
				
			||||||
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
 | 
					    .needed = sdhci_pending_insert_vmstate_needed,
 | 
				
			||||||
 | 
					    .fields = (VMStateField[]) {
 | 
				
			||||||
 | 
					        VMSTATE_BOOL(pending_insert_state, SDHCIState),
 | 
				
			||||||
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const VMStateDescription sdhci_vmstate = {
 | 
					const VMStateDescription sdhci_vmstate = {
 | 
				
			||||||
    .name = "sdhci",
 | 
					    .name = "sdhci",
 | 
				
			||||||
    .version_id = 1,
 | 
					    .version_id = 1,
 | 
				
			||||||
@ -1215,7 +1241,11 @@ const VMStateDescription sdhci_vmstate = {
 | 
				
			|||||||
        VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
 | 
					        VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
 | 
				
			||||||
        VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
 | 
					        VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
 | 
				
			||||||
        VMSTATE_END_OF_LIST()
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
 | 
					    .subsections = (const VMStateDescription*[]) {
 | 
				
			||||||
 | 
					        &sdhci_pending_insert_vmstate,
 | 
				
			||||||
 | 
					        NULL
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Capabilities registers provide information on supported features of this
 | 
					/* Capabilities registers provide information on supported features of this
 | 
				
			||||||
@ -1273,6 +1303,8 @@ static Property sdhci_sysbus_properties[] = {
 | 
				
			|||||||
    DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
 | 
					    DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
 | 
				
			||||||
            SDHC_CAPAB_REG_DEFAULT),
 | 
					            SDHC_CAPAB_REG_DEFAULT),
 | 
				
			||||||
    DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
 | 
					    DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
 | 
				
			||||||
 | 
					    DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
 | 
				
			||||||
 | 
					                     false),
 | 
				
			||||||
    DEFINE_PROP_END_OF_LIST(),
 | 
					    DEFINE_PROP_END_OF_LIST(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1300,6 +1332,10 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
 | 
				
			|||||||
    memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
 | 
					    memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
 | 
				
			||||||
            SDHC_REGISTERS_MAP_SIZE);
 | 
					            SDHC_REGISTERS_MAP_SIZE);
 | 
				
			||||||
    sysbus_init_mmio(sbd, &s->iomem);
 | 
					    sysbus_init_mmio(sbd, &s->iomem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->pending_insert_quirk) {
 | 
				
			||||||
 | 
					        s->pending_insert_state = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
 | 
					static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
				
			|||||||
@ -76,6 +76,8 @@ typedef struct SDHCIState {
 | 
				
			|||||||
    uint32_t buf_maxsz;
 | 
					    uint32_t buf_maxsz;
 | 
				
			||||||
    uint16_t data_count;   /* current element in FIFO buffer */
 | 
					    uint16_t data_count;   /* current element in FIFO buffer */
 | 
				
			||||||
    uint8_t  stopped_state;/* Current SDHC state */
 | 
					    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 */
 | 
					    /* Buffer Data Port Register - virtual access point to R and W buffers */
 | 
				
			||||||
    /* Software Reset Register - always reads as 0 */
 | 
					    /* Software Reset Register - always reads as 0 */
 | 
				
			||||||
    /* Force Event Auto CMD12 Error Interrupt Reg - write only */
 | 
					    /* Force Event Auto CMD12 Error Interrupt Reg - write only */
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user