From patchwork Tue Jan 23 03:30:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= X-Patchwork-Id: 864586 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JZFbzTiL"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zQZ3Q2bQPz9sPk for ; Tue, 23 Jan 2018 14:46:26 +1100 (AEDT) Received: from localhost ([::1]:60135 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1edpXU-0007nz-Cc for incoming@patchwork.ozlabs.org; Mon, 22 Jan 2018 22:46:24 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37946) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1edpJ9-0003oo-95 for qemu-devel@nongnu.org; Mon, 22 Jan 2018 22:31:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1edpJ8-0008Ku-1x for qemu-devel@nongnu.org; Mon, 22 Jan 2018 22:31:35 -0500 Received: from mail-qt0-x243.google.com ([2607:f8b0:400d:c0d::243]:39821) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1edpJ7-0008Kf-SD for qemu-devel@nongnu.org; Mon, 22 Jan 2018 22:31:33 -0500 Received: by mail-qt0-x243.google.com with SMTP id f4so26485523qtj.6 for ; Mon, 22 Jan 2018 19:31:33 -0800 (PST) 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=T8gn24HY8q8q1LswSc7jncRZqWmz1Mk0tP3MG1goWM4=; b=JZFbzTiLXcqOldLdEYwITG+YkmPVv2pq8z4Br5H3zZv5HGafL+W4PZvH0Co/eaIOxh rB+TM4tAB7E0cKeR/x/DUSlmib21WVF5awIeKE2pg5XVwGPPS1oJWrSjah504Ur2g2Xi nFP6536vp4oPS+MDIcr5v+vmXunMhfg9oCNOCi9FujRGB573X8R7S6OemaesVArWygvF KnYmqHPmH1evHCluej6/mHJeoiIq1TJKt97fYWHzNiah2omPIanx+rRe7zb513Z2djb5 /WjYKolxTHyQZsguu2QFjDzowl17RE6ZthX3iOs4R9oyTmCncwReJUR6eyUIa04YAY+9 QMrw== 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=T8gn24HY8q8q1LswSc7jncRZqWmz1Mk0tP3MG1goWM4=; b=eNwYVc569lSbgXu11hwHmH50h8ajlXJC1KHWbdZjte2c+ERW7iV03ywWV+D7TgoZOi NHlTkVx4tktFmjCdHc1n1nhGXkX+0Lsj+Jlmepj/sDVVZY++ZsRoCHqr3WOHicGkYFTG 3J1JMFhGp1NJbxvtcXed+8pOU4j9NJeYRwLyLWV9WiXZ18WeMDpuK3eqfUiRtMOfovSR wB0AithCVLrId8k+dZvdm1HWX/vahXMas/wk+IYnn5nyUSMtB3WPgo7tGeAfeoex+O1t sVGD8T2Gr4actdeVMd57e/22RNPNgcOE44vV4NpVWChD7jAidkPV1XjZGUiHxoHeMIht QH6Q== X-Gm-Message-State: AKwxytffUq6FV3vrCKoc5IbOAPVZ5+nEINFKOhhduLIR0AdeItJmsbZy KHpy7MeR5T5xEQidsohWoMQ= X-Google-Smtp-Source: AH8x225YHTLkEZ8+J5ibloKhM4fRF1j8lat/5YAI8iG8aD3nKEy4IrV14dWbR4Nzfo+SO+ududFavA== X-Received: by 10.55.178.66 with SMTP id b63mr1648910qkf.246.1516678293308; Mon, 22 Jan 2018 19:31:33 -0800 (PST) Received: from x1.lan ([138.117.48.219]) by smtp.gmail.com with ESMTPSA id w8sm3848586qka.2.2018.01.22.19.31.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 22 Jan 2018 19:31:32 -0800 (PST) From: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= To: Alistair Francis , Peter Maydell , Igor Mitsyanko Date: Tue, 23 Jan 2018 00:30:33 -0300 Message-Id: <20180123033034.29493-18-f4bug@amsat.org> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180123033034.29493-1-f4bug@amsat.org> References: <20180123033034.29493-1-f4bug@amsat.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400d:c0d::243 Subject: [Qemu-devel] [PATCH v3 17/18] 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: "Edgar E . Iglesias" , Prasad J Pandit , Peter Crosthwaite , =?utf-8?q?Philippe_M?= =?utf-8?q?athieu-Daud=C3=A9?= , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" [based on a patch from Alistair Francis from qemu/xilinx tag xilinx-v2015.2] Signed-off-by: Philippe Mathieu-Daudé --- hw/sd/sd.c | 148 +++++++++++++++++++++++++++++++++++++++++++++-------- hw/sd/trace-events | 1 + 2 files changed, 127 insertions(+), 22 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b3b6859bc4..1f6c4ce2a4 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -125,6 +125,7 @@ struct SDState { bool enable; uint8_t dat_lines; bool cmd_line; + bool uhs_enabled; }; static const char *sd_state_name(enum SDCardStates state) @@ -569,6 +570,7 @@ static void sd_reset(DeviceState *dev) sd->expecting_acmd = false; sd->dat_lines = 0xf; sd->cmd_line = true; + sd->uhs_enabled = false; sd->multi_blk_cnt = 0; } @@ -767,30 +769,132 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) return ret; } +/* Function Group */ +enum { + SD_FG_MIN = 1, + SD_FG_ACCESS_MODE = 1, + SD_FG_COMMAND_SYSTEM = 2, + SD_FG_DRIVER_STRENGTH = 3, + SD_FG_CURRENT_LIMIT = 4, + SD_FG_RSVD_5 = 5, + SD_FG_RSVD_6 = 6, + SD_FG_COUNT +}; + +/* Function name */ +#define SD_FN_COUNT 16 + +static const char *sd_fn_grp_name[SD_FG_COUNT] = { + [SD_FG_ACCESS_MODE] = "ACCESS_MODE", + [SD_FG_COMMAND_SYSTEM] = "COMMAND_SYSTEM", + [SD_FG_DRIVER_STRENGTH] = "DRIVER_STRENGTH", + [SD_FG_CURRENT_LIMIT] = "CURRENT_LIMIT", + [SD_FG_RSVD_5] = "RSVD5", + [SD_FG_RSVD_6] = "RSVD6", +}; + +typedef struct sd_fn_support { + const char *name; + bool uhs_only; + bool unimp; +} sd_fn_support; + +static const sd_fn_support *sd_fn_support_defs[SD_FG_COUNT] = { + [SD_FG_ACCESS_MODE] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default/SDR12" }, + [1] = { .name = "high-speed/SDR25" }, + [2] = { .name = "SDR50", .uhs_only = true }, + [3] = { .name = "SDR104", .uhs_only = true }, + [4] = { .name = "DDR50", .uhs_only = true }, + }, + [SD_FG_COMMAND_SYSTEM] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default" }, + [1] = { .name = "For eC" }, + [3] = { .name = "OTP", .unimp = true }, + [4] = { .name = "ASSD", .unimp = true }, + }, + [SD_FG_DRIVER_STRENGTH] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default/Type B" }, + [1] = { .name = "Type A", .uhs_only = true }, + [2] = { .name = "Type C", .uhs_only = true }, + [3] = { .name = "Type D", .uhs_only = true }, + }, + [SD_FG_CURRENT_LIMIT] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default/200mA" }, + [1] = { .name = "400mA", .uhs_only = true }, + [2] = { .name = "600mA", .uhs_only = true }, + [3] = { .name = "800mA", .uhs_only = true }, + }, + [SD_FG_RSVD_5] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default" }, + }, + [SD_FG_RSVD_6] = (sd_fn_support [SD_FN_COUNT]) { + [0] = { .name = "default" }, + }, +}; + +#define SD_FN_NO_INFLUENCE (1 << 15) + static void sd_function_switch(SDState *sd, uint32_t arg) { - int i, mode, new_func; - mode = !!(arg & 0x80000000); - - sd->data[0] = 0x00; /* Maximum current consumption */ - sd->data[1] = 0x01; - sd->data[2] = 0x80; /* Supported group 6 functions */ - sd->data[3] = 0x01; - sd->data[4] = 0x80; /* Supported group 5 functions */ - sd->data[5] = 0x01; - sd->data[6] = 0x80; /* Supported group 4 functions */ - sd->data[7] = 0x01; - sd->data[8] = 0x80; /* Supported group 3 functions */ - sd->data[9] = 0x01; - sd->data[10] = 0x80; /* Supported group 2 functions */ - sd->data[11] = 0x43; - sd->data[12] = 0x80; /* Supported group 1 functions */ - sd->data[13] = 0x03; - for (i = 0; i < 6; i ++) { - new_func = (arg >> (i * 4)) & 0x0f; - if (mode && new_func != 0x0f) - sd->function_group[i] = new_func; - sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4); + int fn_grp, new_func, i; + uint8_t *data_p; + bool mode = extract32(arg, 31, 1); /* 0: check only, 1: do switch */ + + stw_be_p(sd->data + 0, 0x0001); /* Maximum current consumption */ + + data_p = &sd->data[2]; + for (fn_grp = SD_FG_COUNT - 1; fn_grp >= SD_FG_MIN; fn_grp--) { + uint16_t supported_fns = SD_FN_NO_INFLUENCE; + for (i = 0; i < SD_FN_COUNT; ++i) { + const sd_fn_support *def = &sd_fn_support_defs[fn_grp][i]; + + if (def->name && !def->unimp && + !(def->uhs_only && !sd->uhs_enabled)) { + supported_fns |= 1 << i; + } + } + stw_be_p(data_p, supported_fns); + data_p += 2; + } + + assert(data_p == &sd->data[14]); + for (fn_grp = SD_FG_COUNT - 1; fn_grp >= SD_FG_MIN; fn_grp--) { + new_func = (arg >> ((fn_grp - 1) * 4)) & 0x0f; + if (new_func == 0xf) { + new_func = sd->function_group[fn_grp - 1]; + } else { + const sd_fn_support *def = &sd_fn_support_defs[fn_grp][new_func]; + if (mode) { + if (!def->name) { + qemu_log_mask(LOG_GUEST_ERROR, + "Function %d not a valid for " + "function group %d\n", + new_func, fn_grp); + new_func = 0xf; + } else if (def->unimp) { + qemu_log_mask(LOG_UNIMP, + "Function %s (fn grp %d) not implemented\n", + def->name, fn_grp); + new_func = 0xf; + } else if (def->uhs_only && !sd->uhs_enabled) { + qemu_log_mask(LOG_GUEST_ERROR, + "Function %s (fn grp %d) only " + "valid in UHS mode\n", + def->name, fn_grp); + new_func = 0xf; + } else { + sd->function_group[fn_grp - 1] = new_func; + } + } + trace_sdcard_function_select(def->name, sd_fn_grp_name[fn_grp], + mode); + } + if (!(fn_grp & 0x1)) { /* evens go in high nibble */ + *data_p = new_func << 4; + } else { /* odds go in low nibble */ + *(data_p++) |= new_func; + } } memset(&sd->data[17], 0, 47); stw_be_p(sd->data + 65, sd_crc16(sd->data, 64)); diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 2059ace61f..c106541a47 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -42,6 +42,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, uint8_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(const char *fn_name, const char *grp_name, bool do_switch) "Function %s (group: %s, sw: %u)" # hw/sd/milkymist-memcard.c milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"