From nobody Sun Apr 28 12:30:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528300236493957.9102859245543; Wed, 6 Jun 2018 08:50:36 -0700 (PDT) Received: from localhost ([::1]:53229 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQahn-0001Ro-FU for importer@patchew.org; Wed, 06 Jun 2018 11:50:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46791) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fQag3-0008Hh-Id for qemu-devel@nongnu.org; Wed, 06 Jun 2018 11:48:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fQag1-0003IZ-WE for qemu-devel@nongnu.org; Wed, 06 Jun 2018 11:48:47 -0400 Received: from mail-qt0-x22c.google.com ([2607:f8b0:400d:c0d::22c]:46172) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fQag1-0003I2-RJ for qemu-devel@nongnu.org; Wed, 06 Jun 2018 11:48:45 -0400 Received: by mail-qt0-x22c.google.com with SMTP id h5-v6so6814650qtm.13 for ; Wed, 06 Jun 2018 08:48:45 -0700 (PDT) Received: from x1.local ([138.117.48.222]) by smtp.gmail.com with ESMTPSA id k127-v6sm24397758qke.20.2018.06.06.08.48.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Jun 2018 08:48:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QJLd+6YzJXalbe+6jf5ks2OnAcZ6mDxiPrx/OxJ5m6Q=; b=jQ1xt4UJUdlKRemmgZbua5V1TNtx/v45yMH23idpV4cx3ExYNbh3bviF+b/kIvclfc AopBY50xTkaOGdnN9yCG9NJ5HMGfTNZmuY/aErLlORM93AeAtSLyQEdWWRpHKjOtmJOz MRSNM0cVEZOsQyc7RDboPrg7sUdupHOXzQ6yYwrNurH/cKRhzqeFy0eIFAO78MyhfUyJ GNJ959MMxa9rHO4RXNMEcYp9EWFnpeFgCO8px9EAS9RRzaSlaWyh23cAJD6FS1P2moZA SFIB1DYg/p616GEhBihmEs/uVGU8Y7wDSIWp68ZXavWfJ9QDpEStI3TnJ3MOZe1mdAnc 7Q0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=QJLd+6YzJXalbe+6jf5ks2OnAcZ6mDxiPrx/OxJ5m6Q=; b=F2b8it1bxvDFjy2NkQUqgPgutID7YAynmjFOVd6o7YAnOkB3CXzKruFca45ESvgADD OZraW8n+OAD+z1PIysIu3NiO5bwKOMpauIWTqz94knhmBHwk1ARd7s9NQshNxiiWTrw4 0wOWZEEl4RD4nfwkJPoDjYiJJUjglH9Xg6E6ZkHG5EllQ+HVUukYo0QacrRoZfwImlJg 5JW1LVot3aJ/VHH53lED4yETdqbQf1onxyJsr/klSV7Qv9oDsi7ODLZMcTxiCzJ1A0db wrNQ2cp0E2Wc4etnyFtwGbVYKnEw29SNf6aEHamEsyaqiNbyudFIQsXE5vzXLecmLCe0 nqqQ== X-Gm-Message-State: APt69E084obQRwIeuR7uiOgqrGP+TDcT0cMTmXp3aAqcVxC/0dD+oJzA hjrRQv87nXzhYMEM+39Wh24= X-Google-Smtp-Source: ADUXVKJv6qGUgpH5ouTFuI4agv+vqIWcxwrPWmd3UCnaGuOF0kgXgVr2/oIji51BHAEqzS9GndCIvA== X-Received: by 2002:ac8:1b9a:: with SMTP id z26-v6mr3330845qtj.344.1528300125166; Wed, 06 Jun 2018 08:48:45 -0700 (PDT) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: Peter Maydell , "Edgar E . Iglesias" , Alistair Francis Date: Wed, 6 Jun 2018 12:48:35 -0300 Message-Id: <20180606154835.2276-2-f4bug@amsat.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180606154835.2276-1-f4bug@amsat.org> References: <20180606154835.2276-1-f4bug@amsat.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400d:c0d::22c Subject: [Qemu-devel] [PATCH v3 1/1] sdcard: Implement the UHS-I Switch Function entries (Spec v3) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Per the "Physical Layer Simplified Specification Version 3.01": 2. System Features Switch function command supports Bus Speed Mode, Command System, Drive Strength, and future functions. 4.3.10 Switch Function Command The switch function command (CMD6) is used to switch or expand memory card functions. Signed-off-by: Philippe Mathieu-Daud=C3=A9 Reviewed-by: Peter Maydell --- hw/sd/sd.c | 238 ++++++++++++++++++++++++++++++++++++++++----- hw/sd/trace-events | 1 + 2 files changed, 217 insertions(+), 22 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7af19fa06c..5b05d77ac0 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -124,6 +124,10 @@ struct SDState { bool enable; uint8_t dat_lines; bool cmd_line; + /* Whether the card entered the UHS mode with voltage level adjusted + * (used by soft-reset) + */ + bool uhs_activated; }; =20 static const char *sd_state_name(enum SDCardStates state) @@ -561,6 +565,7 @@ static void sd_reset(DeviceState *dev) sd->blk_len =3D 0x200; sd->pwd_len =3D 0; sd->expecting_acmd =3D false; + sd->uhs_activated =3D false; sd->dat_lines =3D 0xf; sd->cmd_line =3D true; sd->multi_blk_cnt =3D 0; @@ -761,32 +766,221 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } =20 +/* Function Group */ +enum { + FG_MIN =3D 1, + FG_ACCESS_MODE =3D 1, + FG_COMMAND_SYSTEM =3D 2, + FG_DRIVER_STRENGTH =3D 3, + FG_CURRENT_LIMIT =3D 4, + FG_RSVD_5 =3D 5, + FG_RSVD_6 =3D 6, + FG_MAX =3D 6, + FG_COUNT +}; + +/* Function name */ +enum { + FN_NO_INFLUENCE =3D 0xf, + FN_COUNT =3D 16 +}; + +/* Bus Speed Mode */ +static bool fg1_selectable(SDState *sd, int fn) +{ + if (sd->uhs_activated) { + return fn <=3D 4; + } + return fn <=3D 1; +} + +/* driver strength selection for UHS-I modes */ +static bool fg3_selectable(SDState *sd, int fn) +{ + if (sd->uhs_activated) { + return fn <=3D 3; + } + return false; +} + +/* Current Limit switch for SDR50, SDR104 and DDR50 */ +static bool fg4_selectable(SDState *sd, int fn) +{ + if (sd->uhs_activated) { + return fn <=3D 3; + } + return false; +} + +typedef struct sd_fn_support { + bool (*is_selectable)(SDState *sd, int fn); + const char *name[FN_COUNT]; +} sd_fn_support; + +static const sd_fn_support fn_support_defs[FG_COUNT] =3D { + [FG_ACCESS_MODE] =3D { + &fg1_selectable, { + [0] =3D "default/SDR12", + [1] =3D "high-speed/SDR25", + [2] =3D "SDR50", + [3] =3D "SDR104", + [4] =3D "DDR50", + } + }, + [FG_COMMAND_SYSTEM] =3D { + NULL, { + [1] =3D "For eC", + [3] =3D "OTP", + [4] =3D "ASSD", + } + }, + [FG_DRIVER_STRENGTH] =3D { + &fg3_selectable, { + [0] =3D "default/Type B", + [1] =3D "Type A", + [2] =3D "Type C", + [3] =3D "Type D", + } + }, + [FG_CURRENT_LIMIT] =3D { + &fg4_selectable, { + [0] =3D "default/200mA", + [1] =3D "400mA", + [2] =3D "600mA", + [3] =3D "800mA", + } + }, +}; + +static const char *sd_fn_grp_name[FG_COUNT] =3D { + [FG_ACCESS_MODE] =3D "ACCESS_MODE", + [FG_COMMAND_SYSTEM] =3D "COMMAND_SYSTEM", + [FG_DRIVER_STRENGTH] =3D "DRIVER_STRENGTH", + [FG_CURRENT_LIMIT] =3D "CURRENT_LIMIT", + [FG_RSVD_5] =3D "RSVD5", + [FG_RSVD_6] =3D "RSVD6", +}; + +static const char *sd_fn_name(int grp, int fn) +{ + if (fn_support_defs[grp].name[fn]) { + return fn_support_defs[grp].name[fn]; + } + if (fn =3D=3D 0) { + return "default"; + } + return "invalid"; +}; + +static bool sd_function_is_selectable(SDState *sd, int grp, int fn) +{ + const sd_fn_support *def =3D &fn_support_defs[grp]; + + if (fn =3D=3D 0) { + /* default is always selectable */ + return true; + } + if (def->is_selectable) { + return def->is_selectable(sd, fn); + } + return false; +} + +static bool sd_function_is_valid(SDState *sd, int group, int fn) +{ + const sd_fn_support *def =3D &fn_support_defs[group]; + bool is_valid =3D false; + + if (fn =3D=3D FN_NO_INFLUENCE) { + fn =3D sd->function_group[group - 1]; + } + if (fn =3D=3D 0) { + /* default is always valid */ + is_valid =3D true; + } else if (!def->name[fn]) { + qemu_log_mask(LOG_GUEST_ERROR, + "Function %d not valid for function group %d\n", + fn, group); + } else if (!def->is_selectable) { + qemu_log_mask(LOG_UNIMP, "Function %s (fn group %d) not implemente= d\n", + sd_fn_name(group, fn), group); + } else if (!def->is_selectable(sd, fn)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Function %s (fn group %d) only valid in current mod= e\n", + sd_fn_name(group, fn), group); + } else { + is_valid =3D true; + } + + return is_valid; +} + static void sd_function_switch(SDState *sd, uint32_t arg) { - int i, mode, new_func; - mode =3D !!(arg & 0x80000000); - - sd->data[0] =3D 0x00; /* Maximum current consumption */ - sd->data[1] =3D 0x01; - sd->data[2] =3D 0x80; /* Supported group 6 functions */ - sd->data[3] =3D 0x01; - sd->data[4] =3D 0x80; /* Supported group 5 functions */ - sd->data[5] =3D 0x01; - sd->data[6] =3D 0x80; /* Supported group 4 functions */ - sd->data[7] =3D 0x01; - sd->data[8] =3D 0x80; /* Supported group 3 functions */ - sd->data[9] =3D 0x01; - sd->data[10] =3D 0x80; /* Supported group 2 functions */ - sd->data[11] =3D 0x43; - sd->data[12] =3D 0x80; /* Supported group 1 functions */ - sd->data[13] =3D 0x03; - for (i =3D 0; i < 6; i ++) { - new_func =3D (arg >> (i * 4)) & 0x0f; - if (mode && new_func !=3D 0x0f) - sd->function_group[i] =3D new_func; - sd->data[14 + (i >> 1)] =3D new_func << ((i * 4) & 4); + int group, func_num, i; + uint16_t max_current_mA =3D 1; /* 1 mA is virtually enough */ + uint32_t switch_fns =3D 0; + bool do_switch =3D extract32(arg, 31, 1); + + /* Bits 400-495: groups functions supported (16 bits each group) */ + for (group =3D FG_MIN; group <=3D FG_MAX; group++) { + uint16_t supported_fns =3D 1 << FN_NO_INFLUENCE; + + for (i =3D 0; i < FN_COUNT; ++i) { + if (sd_function_is_selectable(sd, group, i)) { + supported_fns |=3D 1 << i; + } + } + stw_be_p(sd->data + 2 + 2 * (FG_MAX - group), supported_fns); + } + + /* Bits 376-399: functions information (4 bits each group) */ + for (group =3D FG_MIN; group <=3D FG_MAX; group++) { + bool fn_valid; + func_num =3D (arg >> ((group - 1) * 4)) & 0x0f; + fn_valid =3D sd_function_is_valid(sd, group, func_num); + trace_sdcard_function_select(1, "valid", fn_valid, + group, sd_fn_grp_name[group], + sd_fn_name(group, func_num)); + if (!fn_valid) { + /* 0xf shows function set error with the argument. */ + switch_fns =3D deposit32(switch_fns, 4 * (group + 1), 4, 0xf); + } + } + if (switch_fns) { + /* pass #1 set switch_fns if an invalid function got selected. + * + * Maximum current consumption: + * If one of the selected functions was wrong, the return value is= 0. + */ + max_current_mA =3D 0; + } else { + for (group =3D FG_MIN; group <=3D FG_MAX; group++) { + func_num =3D (arg >> ((group - 1) * 4)) & 0x0f; + if (func_num =3D=3D FN_NO_INFLUENCE) { + /* Guest requested no influence, so this function group + * stays the same. + */ + func_num =3D sd->function_group[group - 1]; + } + trace_sdcard_function_select(2, "switch", do_switch, + group, sd_fn_grp_name[group], + sd_fn_name(group, func_num)); + if (do_switch) { + sd->function_group[group - 1] =3D func_num; + } + switch_fns =3D deposit32(switch_fns, 4 * (group + 1), 4, func_= num); + } } + stl_be_p(sd->data + 14, switch_fns); + + /* Data Structure Version =3D 0x00: 376 bits reserved (undefined) */ memset(&sd->data[17], 0, 47); + + /* Bits 496-511 Maximum current consumption */ + stw_be_p(sd->data, max_current_mA); + + /* Finally update the checksum */ stw_be_p(sd->data + 64, sd_crc16(sd->data, 64)); } =20 diff --git a/hw/sd/trace-events b/hw/sd/trace-events index bfd1d62efc..82fa2e18d4 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -48,6 +48,7 @@ sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%= " PRIx64 " size 0x%x" sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, ui= nt8_t value) "%s %20s/ CMD%02d value 0x%02x" sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, int= length) "%s %20s/ CMD%02d len %d" sdcard_set_voltage(uint16_t millivolts) "%u mV" +sdcard_function_select(int pass, const char *bool_name, bool bool_value, i= nt grp_num, const char *grp_name, const char *fn_name) "PASS#%d %s:%u group= :%d/%s func:'%s'" =20 # hw/sd/milkymist-memcard.c milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x = value 0x%08x" --=20 2.17.1