Re: [Qemu-devel] [PATCH v8 05/14] sdhci: implement UHS-I voltage switch

2018-01-23 Thread Alistair Francis
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudé  wrote:
> [based on a patch from Alistair Francis 
>  from qemu/xilinx tag xilinx-v2015.2]
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  include/hw/sd/sd.h| 16 
>  include/hw/sd/sdhci.h |  1 +
>  hw/sd/core.c  | 13 +
>  hw/sd/sd.c| 13 +
>  hw/sd/sdhci.c | 12 +++-
>  hw/sd/trace-events|  1 +
>  6 files changed, 55 insertions(+), 1 deletion(-)
>
> diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
> index 96caefe373..f086679493 100644
> --- a/include/hw/sd/sd.h
> +++ b/include/hw/sd/sd.h
> @@ -55,6 +55,20 @@
>  #define AKE_SEQ_ERROR  (1 << 3)
>  #define OCR_CCS_BITN30
>
> +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);
> diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
> index 0fff941a98..06e3784e54 100644
> --- a/include/hw/sd/sdhci.h
> +++ b/include/hw/sd/sdhci.h
> @@ -93,6 +93,7 @@ typedef struct SDHCIState {
>  /* Configurable properties */
>  bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */
>  uint8_t sd_spec_version;
> +uint8_t uhs_mode;
>  } SDHCIState;
>
>  #define TYPE_PCI_SDHCI "sdhci-pci"
> diff --git a/hw/sd/core.c b/hw/sd/core.c
> index 498284f109..6d198ea775 100644
> --- a/hw/sd/core.c
> +++ b/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);
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index 35347a5bbc..609b2da14f 100644
> --- a/hw/sd/sd.c
> +++ b/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) {
> @@ -1925,6 +1937,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;
> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
> index b7e69fbc22..aec6ca4d14 100644
> --- a/hw/sd/sdhci.c
> +++ b/hw/sd/sdhci.c
> @@ -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(>sdbus, SD_VOLTAGE_1_8V);
> +} else {
> +

[Qemu-devel] [PATCH v8 05/14] sdhci: implement UHS-I voltage switch

2018-01-22 Thread Philippe Mathieu-Daudé
[based on a patch from Alistair Francis 
 from qemu/xilinx tag xilinx-v2015.2]
Signed-off-by: Philippe Mathieu-Daudé 
---
 include/hw/sd/sd.h| 16 
 include/hw/sd/sdhci.h |  1 +
 hw/sd/core.c  | 13 +
 hw/sd/sd.c| 13 +
 hw/sd/sdhci.c | 12 +++-
 hw/sd/trace-events|  1 +
 6 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index 96caefe373..f086679493 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -55,6 +55,20 @@
 #define AKE_SEQ_ERROR  (1 << 3)
 #define OCR_CCS_BITN30
 
+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);
diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
index 0fff941a98..06e3784e54 100644
--- a/include/hw/sd/sdhci.h
+++ b/include/hw/sd/sdhci.h
@@ -93,6 +93,7 @@ typedef struct SDHCIState {
 /* Configurable properties */
 bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */
 uint8_t sd_spec_version;
+uint8_t uhs_mode;
 } SDHCIState;
 
 #define TYPE_PCI_SDHCI "sdhci-pci"
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 498284f109..6d198ea775 100644
--- a/hw/sd/core.c
+++ b/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);
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 35347a5bbc..609b2da14f 100644
--- a/hw/sd/sd.c
+++ b/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) {
@@ -1925,6 +1937,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;
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index b7e69fbc22..aec6ca4d14 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -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(>sdbus, SD_VOLTAGE_1_8V);
+} else {
+sdbus_set_voltage(>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