Received: by 2002:a25:ef43:0:0:0:0:0 with SMTP id w3csp230323ybm; Thu, 28 May 2020 01:03:18 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyME3UHbmQlk+ecyIMoI+F0tb6wC2r/RzNdva6A3+QbSFw8MwWkNmj8ECMESZRX5o/2B62Y X-Received: by 2002:a17:906:cd03:: with SMTP id oz3mr1974315ejb.391.1590652998204; Thu, 28 May 2020 01:03:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1590652998; cv=none; d=google.com; s=arc-20160816; b=MVGHUeIEHPIwVdLD7SvHqA8BpdnjhLrHWgUGFCqv1HzKOulwAQXQNcrXq+WNQ76wme CMBnxUU0DB0gRLleAUdfu+GeGVaFm26/KIt3xMimlGlwHACCj7b/gmyB+YAjP7prVbrq VootqAgxvkRX+naBOhanGdHZSuKQG1kc7gVgpXuwMf75yK+qSf631JmH5a44PddSSQ0E IxSQ/3YGEGlASYXXSp54VOHuZ9CQr6OB2ozBA49MztTYnZTymzlb6jzmRfKpSDcJfusM tmp4XXEul3X4mSw+D8hdPqVzOXG7InLpQom903hs1RAujgkxQOJ+eHQsV/4Hp0X3Y8kb Ug+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=P4JDq1pAhxakUVINhRYGEeSNd9H6h+CWTzVCCkixy+0=; b=C7ifEopJIxr7C8eaC7Oz59ZDk7FJbiOaKqgk4KAYH0VzZ1xrvoFu5NC3rjw8iGMl9F eKB91iw0aSiinJPutDFM3E9OAlSyPXj9inDjPgnv7IzvheaQcNF+zzXrP2zFgC6iR9L7 5jmY3pEO40dXAAULtOXTbDrXo7OhneeYSXhboxeKYlLUmsO6rWsrogWQhgLg+sf3z1un BJHUm4dcRrTvgHf36gxdYvfiY1IOstCZjFYQLwi9Sn0KFGvvAk6v3BqAk7cvYsAtIdC6 6f1WlPdGd8QD8lxRmvUkpKOvinFdmUy0WAQD05gJ3wu4CKo0WVe6Y9nXMlZ0Pz/fR7nL Oxog== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z17si3263185ejf.735.2020.05.28.01.02.55; Thu, 28 May 2020 01:03:18 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726844AbgE1H7E (ORCPT + 99 others); Thu, 28 May 2020 03:59:04 -0400 Received: from twhmllg4.macronix.com ([122.147.135.202]:31213 "EHLO TWHMLLG4.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726774AbgE1H7E (ORCPT ); Thu, 28 May 2020 03:59:04 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG4.macronix.com with ESMTP id 04S7wMHg030973; Thu, 28 May 2020 15:58:28 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, tudor.ambarus@microchip.com, miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com, boris.brezillon@collabora.com, matthias.bgg@gmail.com Cc: p.yadav@ti.com, juliensu@mxic.com.tw, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-spi@vger.kernel.org, Mason Yang Subject: [PATCH v3 07/14] mtd: spi-nor: sfdp: parse xSPI Profile 1.0 table Date: Thu, 28 May 2020 15:58:09 +0800 Message-Id: <1590652696-8844-8-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1590652696-8844-1-git-send-email-masonccyang@mxic.com.tw> References: <1590652696-8844-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG4.macronix.com 04S7wMHg030973 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org JESD251, xSPI profile 1.0 table supports octal DTR mode. Extract information like the fast read opcode, dummy cycles for various frequencies, the number of dummy cycles needed for a Read Status Register command, the number of address bytes needed for a Read Status Register command, read volatile register command and write volatile register command. According to BFPT 20th DWORD of octal maximum speed, driver get it's specific dummy cycles from profile 1.0 table and then could update it to device by their fixup hooks. Since driver get octal DTR read opcode and then set read settings, expose spi_nor_set_read_settings() in core.h. Signed-off-by: Mason Yang --- drivers/mtd/spi-nor/core.c | 2 +- drivers/mtd/spi-nor/core.h | 16 +++++++ drivers/mtd/spi-nor/sfdp.c | 106 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 388e695..642e3c0 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2355,7 +2355,7 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -static void +void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index f644ed1..837f5e9 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -193,6 +193,12 @@ struct spi_nor_locking_ops { * @size: the flash memory density in bytes. * @page_size: the page size of the SPI NOR flash memory. * @octal_max_speed: maximum operation speed of device in octal mode. + * @rdsr_dummy: dummy cycles needed for Read Status Register command. + * @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register + * command. + * @rd_reg_cmd: read volatile register command for xSPI device. + * @wr_reg_cmd: write volatile register command for xSPI device. + * @dummy_cycles: dummy cycles used for various frequencies. * @hwcaps: describes the read and page program hardware * capabilities. * @reads: read capabilities ordered by priority: the higher index @@ -216,6 +222,11 @@ struct spi_nor_flash_parameter { u64 size; u32 page_size; u16 octal_max_speed; + u8 rdsr_dummy; + u8 rdsr_addr_nbytes; + u8 rd_reg_cmd; + u8 wr_reg_cmd; + u8 dummy_cycles; struct spi_nor_hwcaps hwcaps; struct spi_nor_read_command reads[SNOR_CMD_READ_MAX]; @@ -426,6 +437,11 @@ ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, int spi_nor_hwcaps_read2cmd(u32 hwcaps); u8 spi_nor_convert_3to4_read(u8 opcode); +void spi_nor_set_read_settings(struct spi_nor_read_command *read, + u8 num_mode_clocks, + u8 num_wait_states, + u8 opcode, + enum spi_nor_protocol proto); void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, enum spi_nor_protocol proto); diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index d7ef47a..550422b 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -20,6 +20,7 @@ #define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ #define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */ +#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 table. */ #define SFDP_SIGNATURE 0x50444653U #define SFDP_JESD216_MAJOR 1 @@ -27,6 +28,27 @@ #define SFDP_JESD216A_MINOR 5 #define SFDP_JESD216B_MINOR 6 +/* xSPI Profile 1.0 table (from JESD216D.01). */ +#define XSPI_PF1_DWORD1_RD_CMD GENMASK(15, 8) +#define XSPI_PF1_DWORD1_RDSR_ADDR_BYTES BIT(29) +#define XSPI_PF1_DWORD1_RDSR_DUMMY_CYCLES BIT(28) +#define XSPI_PF1_DWORD2_RD_REG_CMD GENMASK(31, 24) +#define XSPI_PF1_DWORD2_WR_REG_CMD GENMASK(15, 8) +#define XSPI_PF1_DUMMY_CYCLES_DEFAULT 20 +#define XSPI_DWORD(x) ((x) - 1) +#define XSPI_DWORD_MAX 5 + +struct sfdp_xspi { + u32 dwords[XSPI_DWORD_MAX]; +}; + +struct xspi_dummy_cycles { + u16 speed_hz; /* Speed MHz */ + u8 dwords; /* Dwords index */ + u32 mask; /* Mask */ + u8 shift; /* Bit shift */ +}; + /* Basic Flash Parameter Table 20th DWORD, Max operation speed of device */ struct octal_max_speed { u8 idx; /* Bits value */ @@ -1146,6 +1168,86 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, } /** + * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table + * @nor: pointer to a 'struct spi_nor' + * @param_header: xspi profile 1 parameter table header + * @params: pointer to the 'struct spi_nor_flash_parameter' to be. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_profile1(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + struct spi_nor_flash_parameter *params) +{ + struct sfdp_xspi pfile1; + u8 opcode; + u32 i, addr; + size_t len; + int ret; + static const struct xspi_dummy_cycles dummy[] = { + /* {MHz, Dwords index, Mask, Bit shift} */ + { 200, 4, GENMASK(11, 7), 7}, + { 166, 5, GENMASK(31, 27), 27}, + { 133, 5, GENMASK(21, 17), 17}, + { 100, 5, GENMASK(11, 7), 7}, + }; + + if (header->major != SFDP_JESD216_MAJOR || + header->length < XSPI_DWORD_MAX) + return -EINVAL; + + len = min_t(size_t, sizeof(pfile1), + header->length * sizeof(u32)); + + memset(&pfile1, 0, sizeof(pfile1)); + + addr = SFDP_PARAM_HEADER_PTP(header); + ret = spi_nor_read_sfdp(nor, addr, len, &pfile1); + if (ret) + goto out; + + /* Fix endianness of the xSPI 1.0 DWORDs. */ + le32_to_cpu_array(pfile1.dwords, XSPI_DWORD_MAX); + + /* Get 8D-8D-8D fast read opcode and dummy cycles. */ + opcode = FIELD_GET(XSPI_PF1_DWORD1_RD_CMD, + pfile1.dwords[XSPI_DWORD(1)]); + + if (pfile1.dwords[XSPI_DWORD(1)] & XSPI_PF1_DWORD1_RDSR_ADDR_BYTES) + params->rdsr_addr_nbytes = 4; + else + params->rdsr_addr_nbytes = 0; + + if (pfile1.dwords[XSPI_DWORD(1)] & XSPI_PF1_DWORD1_RDSR_DUMMY_CYCLES) + params->rdsr_dummy = 8; + else + params->rdsr_dummy = 4; + + params->rd_reg_cmd = FIELD_GET(XSPI_PF1_DWORD2_RD_REG_CMD, + pfile1.dwords[XSPI_DWORD(2)]); + params->wr_reg_cmd = FIELD_GET(XSPI_PF1_DWORD2_WR_REG_CMD, + pfile1.dwords[XSPI_DWORD(2)]); + + /* according to BFPT 20th DOWRD to get devices dummy cycles */ + for (i = 0; i < ARRAY_SIZE(dummy); i++) { + if (params->octal_max_speed == dummy[i].speed_hz) { + params->dummy_cycles = (dummy[i].mask & + pfile1.dwords[XSPI_DWORD(dummy[i].dwords)]) >> + dummy[i].shift; + break; + } + } + if (i == ARRAY_SIZE(dummy)) + params->dummy_cycles = XSPI_PF1_DUMMY_CYCLES_DEFAULT; + + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, params->dummy_cycles, + opcode, SNOR_PROTO_8_8_8_DTR); +out: + return ret; +} + +/** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @params: pointer to the 'struct spi_nor_flash_parameter' to be @@ -1246,6 +1348,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor, err = spi_nor_parse_4bait(nor, param_header, params); break; + case SFDP_PROFILE1_ID: + err = spi_nor_parse_profile1(nor, param_header, params); + break; + default: break; } -- 1.9.1