sdhci: implement UHS-I voltage switch
[based on a patch from Alistair Francis <alistair.francis@xilinx.com> from qemu/xilinx tag xilinx-v2015.2] Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Message-Id: <20180208164818.7961-22-f4bug@amsat.org>
This commit is contained in:
		
							parent
							
								
									238cd93567
								
							
						
					
					
						commit
						0034ebe6ee
					
				
							
								
								
									
										13
									
								
								hw/sd/core.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								hw/sd/core.c
									
									
									
									
									
								
							| @ -41,6 +41,19 @@ static SDState *get_card(SDBus *sdbus) | ||||
|     return SD_CARD(kid->child); | ||||
| } | ||||
| 
 | ||||
| void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts) | ||||
| { | ||||
|     SDState *card = get_card(sdbus); | ||||
| 
 | ||||
|     trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts); | ||||
|     if (card) { | ||||
|         SDCardClass *sc = SD_CARD_GET_CLASS(card); | ||||
| 
 | ||||
|         assert(sc->set_voltage); | ||||
|         sc->set_voltage(card, millivolts); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response) | ||||
| { | ||||
|     SDState *card = get_card(sdbus); | ||||
|  | ||||
							
								
								
									
										13
									
								
								hw/sd/sd.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								hw/sd/sd.c
									
									
									
									
									
								
							| @ -128,6 +128,18 @@ struct SDState { | ||||
|     bool enable; | ||||
| }; | ||||
| 
 | ||||
| static void sd_set_voltage(SDState *sd, uint16_t millivolts) | ||||
| { | ||||
|     switch (millivolts) { | ||||
|     case 3001 ... 3600: /* SD_VOLTAGE_3_3V */ | ||||
|     case 2001 ... 3000: /* SD_VOLTAGE_3_0V */ | ||||
|         break; | ||||
|     default: | ||||
|         qemu_log_mask(LOG_GUEST_ERROR, "SD card voltage not supported: %.3fV", | ||||
|                       millivolts / 1000.f); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void sd_set_mode(SDState *sd) | ||||
| { | ||||
|     switch (sd->state) { | ||||
| @ -1926,6 +1938,7 @@ static void sd_class_init(ObjectClass *klass, void *data) | ||||
|     dc->reset = sd_reset; | ||||
|     dc->bus_type = TYPE_SD_BUS; | ||||
| 
 | ||||
|     sc->set_voltage = sd_set_voltage; | ||||
|     sc->do_command = sd_do_command; | ||||
|     sc->write_data = sd_write_data; | ||||
|     sc->read_data = sd_read_data; | ||||
|  | ||||
| @ -1255,7 +1255,16 @@ 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); | ||||
|         MASKED_WRITE(s->acmd12errsts, mask, value & UINT16_MAX); | ||||
|         if (s->uhs_mode >= UHS_I) { | ||||
|             MASKED_WRITE(s->hostctl2, mask >> 16, value >> 16); | ||||
| 
 | ||||
|             if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, V18_ENA)) { | ||||
|                 sdbus_set_voltage(&s->sdbus, SD_VOLTAGE_1_8V); | ||||
|             } else { | ||||
|                 sdbus_set_voltage(&s->sdbus, SD_VOLTAGE_3_3V); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     case SDHC_CAPAB: | ||||
| @ -1310,6 +1319,7 @@ static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) | ||||
| 
 | ||||
| #define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ | ||||
|     DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \ | ||||
|     DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \ | ||||
|     \ | ||||
|     /* Capabilities registers provide information on supported
 | ||||
|      * features of this specific host controller implementation */ \ | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| sdbus_command(const char *bus_name, uint8_t cmd, uint32_t arg, uint8_t crc) "@%s CMD%02d arg 0x%08x crc 0x%02x" | ||||
| sdbus_read(const char *bus_name, uint8_t value) "@%s value 0x%02x" | ||||
| sdbus_write(const char *bus_name, uint8_t value) "@%s value 0x%02x" | ||||
| sdbus_set_voltage(const char *bus_name, uint16_t millivolts) "@%s %u (mV)" | ||||
| 
 | ||||
| # hw/sd/sdhci.c | ||||
| sdhci_set_inserted(const char *level) "card state changed: %s" | ||||
|  | ||||
| @ -55,6 +55,20 @@ | ||||
| #define AKE_SEQ_ERROR		(1 << 3) | ||||
| #define OCR_CCS_BITN        30 | ||||
| 
 | ||||
| typedef enum { | ||||
|     SD_VOLTAGE_0_4V     = 400,  /* currently not supported */ | ||||
|     SD_VOLTAGE_1_8V     = 1800, | ||||
|     SD_VOLTAGE_3_0V     = 3000, | ||||
|     SD_VOLTAGE_3_3V     = 3300, | ||||
| } sd_voltage_mv_t; | ||||
| 
 | ||||
| typedef enum  { | ||||
|     UHS_NOT_SUPPORTED   = 0, | ||||
|     UHS_I               = 1, | ||||
|     UHS_II              = 2,    /* currently not supported */ | ||||
|     UHS_III             = 3,    /* currently not supported */ | ||||
| } sd_uhs_mode_t; | ||||
| 
 | ||||
| typedef enum { | ||||
|     sd_none = -1, | ||||
|     sd_bc = 0,	/* broadcast -- no response */ | ||||
| @ -88,6 +102,7 @@ typedef struct { | ||||
|     void (*write_data)(SDState *sd, uint8_t value); | ||||
|     uint8_t (*read_data)(SDState *sd); | ||||
|     bool (*data_ready)(SDState *sd); | ||||
|     void (*set_voltage)(SDState *sd, uint16_t millivolts); | ||||
|     void (*enable)(SDState *sd, bool enable); | ||||
|     bool (*get_inserted)(SDState *sd); | ||||
|     bool (*get_readonly)(SDState *sd); | ||||
| @ -134,6 +149,7 @@ void sd_enable(SDState *sd, bool enable); | ||||
| /* Functions to be used by qdevified callers (working via
 | ||||
|  * an SDBus rather than directly with SDState) | ||||
|  */ | ||||
| void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts); | ||||
| 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); | ||||
|  | ||||
| @ -96,6 +96,7 @@ typedef struct SDHCIState { | ||||
|     bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ | ||||
|     uint32_t quirks; | ||||
|     uint8_t sd_spec_version; | ||||
|     uint8_t uhs_mode; | ||||
| } SDHCIState; | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Philippe Mathieu-Daudé
						Philippe Mathieu-Daudé