* [PATCH 2/9] mtd: nand: Introduce nand_data_interface
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
Currently we have no data structure to fully describe a NAND timing.
We only have struct nand_sdr_timings for NAND timings in SDR mode,
but nothing for DDR mode and also no container to store both types
of timing.
This patch adds struct nand_data_interface which stores the timing
type and a union of different timings. This can be used to pass to
drivers in order to configure the timing.
Add kerneldoc for struct nand_sdr_timings while touching it anyway.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
include/linux/mtd/nand.h | 165 +++++++++++++++++++++++++++++++++--------------
1 file changed, 116 insertions(+), 49 deletions(-)
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 9890df2..f305bed 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -566,6 +566,122 @@ struct nand_buffers {
};
/**
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These information can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
+ * Parameters)
+ *
+ * All these timings are expressed in picoseconds.
+ *
+ * @tALH_min: ALE hold time
+ * @tADL_min: ALE to data loading time
+ * @tALS_min: ALE setup time
+ * @tAR_min: ALE to RE# delay
+ * @tCEA_max: CE# access time
+ * @tCEH_min:
+ * @tCH_min: CE# hold time
+ * @tCHZ_max: CE# high to output hi-Z
+ * @tCLH_min: CLE hold time
+ * @tCLR_min: CLE to RE# delay
+ * @tCLS_min: CLE setup time
+ * @tCOH_min: CE# high to output hold
+ * @tCS_min: CE# setup time
+ * @tDH_min: Data hold time
+ * @tDS_min: Data setup time
+ * @tFEAT_max: Busy time for Set Features and Get Features
+ * @tIR_min: Output hi-Z to RE# low
+ * @tITC_max: Interface and Timing Mode Change time
+ * @tRC_min: RE# cycle time
+ * @tREA_max: RE# access time
+ * @tREH_min: RE# high hold time
+ * @tRHOH_min: RE# high to output hold
+ * @tRHW_min: RE# high to WE# low
+ * @tRHZ_max: RE# high to output hi-Z
+ * @tRLOH_min: RE# low to output hold
+ * @tRP_min: RE# pulse width
+ * @tRR_min: Ready to RE# low (data only)
+ * @tRST_max: Device reset time, measured from the falling edge of R/B# to the rising edge of R/B#.
+ * @tWB_max: WE# high to SR[6] low
+ * @tWC_min: WE# cycle time
+ * @tWH_min: WE# high hold time
+ * @tWHR_min: WE# high to RE# low
+ * @tWP_min: WE# pulse width
+ * @tWW_min: WP# transition to WE# low
+ */
+struct nand_sdr_timings {
+ u32 tALH_min;
+ u32 tADL_min;
+ u32 tALS_min;
+ u32 tAR_min;
+ u32 tCEA_max;
+ u32 tCEH_min;
+ u32 tCH_min;
+ u32 tCHZ_max;
+ u32 tCLH_min;
+ u32 tCLR_min;
+ u32 tCLS_min;
+ u32 tCOH_min;
+ u32 tCS_min;
+ u32 tDH_min;
+ u32 tDS_min;
+ u32 tFEAT_max;
+ u32 tIR_min;
+ u32 tITC_max;
+ u32 tRC_min;
+ u32 tREA_max;
+ u32 tREH_min;
+ u32 tRHOH_min;
+ u32 tRHW_min;
+ u32 tRHZ_max;
+ u32 tRLOH_min;
+ u32 tRP_min;
+ u32 tRR_min;
+ u64 tRST_max;
+ u32 tWB_max;
+ u32 tWC_min;
+ u32 tWH_min;
+ u32 tWHR_min;
+ u32 tWP_min;
+ u32 tWW_min;
+};
+
+/**
+ * enum nand_data_interface_type - NAND interface timing type
+ * @NAND_SDR_IFACE: Single Data Rate interface
+ */
+enum nand_data_interface_type {
+ NAND_SDR_IFACE,
+};
+
+/**
+ * struct nand_data_interface - NAND interface timing
+ * @type: type of the timing
+ * @timings: The timing, type according to @type
+ */
+struct nand_data_interface {
+ enum nand_data_interface_type type;
+ union {
+ struct nand_sdr_timings sdr;
+ } timings;
+};
+
+/**
+ * nand_get_sdr_timings - get SDR timing from data interface
+ * @conf: The data interface
+ */
+static inline const struct nand_sdr_timings *
+nand_get_sdr_timings(const struct nand_data_interface *conf)
+{
+ if (conf->type != NAND_SDR_IFACE)
+ return ERR_PTR(-EINVAL);
+
+ return &conf->timings.sdr;
+}
+
+/**
* struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
@@ -1023,55 +1139,6 @@ static inline int jedec_feature(struct nand_chip *chip)
: 0;
}
-/*
- * struct nand_sdr_timings - SDR NAND chip timings
- *
- * This struct defines the timing requirements of a SDR NAND chip.
- * These informations can be found in every NAND datasheets and the timings
- * meaning are described in the ONFI specifications:
- * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
- * Parameters)
- *
- * All these timings are expressed in picoseconds.
- */
-
-struct nand_sdr_timings {
- u32 tALH_min;
- u32 tADL_min;
- u32 tALS_min;
- u32 tAR_min;
- u32 tCEA_max;
- u32 tCEH_min;
- u32 tCH_min;
- u32 tCHZ_max;
- u32 tCLH_min;
- u32 tCLR_min;
- u32 tCLS_min;
- u32 tCOH_min;
- u32 tCS_min;
- u32 tDH_min;
- u32 tDS_min;
- u32 tFEAT_max;
- u32 tIR_min;
- u32 tITC_max;
- u32 tRC_min;
- u32 tREA_max;
- u32 tREH_min;
- u32 tRHOH_min;
- u32 tRHW_min;
- u32 tRHZ_max;
- u32 tRLOH_min;
- u32 tRP_min;
- u32 tRR_min;
- u64 tRST_max;
- u32 tWB_max;
- u32 tWC_min;
- u32 tWH_min;
- u32 tWHR_min;
- u32 tWP_min;
- u32 tWW_min;
-};
-
/* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
--
2.8.1
^ permalink raw reply related
* [PATCH 3/9] mtd: nand: convert ONFI mode into data interface
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
struct nand_data_interface is the designated type to pass to
the NAND drivers to configure the timing. To simplify further
patches convert the onfi_sdr_timings array from type struct
nand_sdr_timings nand_data_interface.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_timings.c | 430 +++++++++++++++++++++-------------------
1 file changed, 224 insertions(+), 206 deletions(-)
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index e81470a..9af2ebc 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -13,228 +13,246 @@
#include <linux/export.h>
#include <linux/mtd/nand.h>
-static const struct nand_sdr_timings onfi_sdr_timings[] = {
+static const struct nand_data_interface onfi_sdr_timings[] = {
/* Mode 0 */
{
- .tADL_min = 200000,
- .tALH_min = 20000,
- .tALS_min = 50000,
- .tAR_min = 25000,
- .tCEA_max = 100000,
- .tCEH_min = 20000,
- .tCH_min = 20000,
- .tCHZ_max = 100000,
- .tCLH_min = 20000,
- .tCLR_min = 20000,
- .tCLS_min = 50000,
- .tCOH_min = 0,
- .tCS_min = 70000,
- .tDH_min = 20000,
- .tDS_min = 40000,
- .tFEAT_max = 1000000,
- .tIR_min = 10000,
- .tITC_max = 1000000,
- .tRC_min = 100000,
- .tREA_max = 40000,
- .tREH_min = 30000,
- .tRHOH_min = 0,
- .tRHW_min = 200000,
- .tRHZ_max = 200000,
- .tRLOH_min = 0,
- .tRP_min = 50000,
- .tRST_max = 250000000000ULL,
- .tWB_max = 200000,
- .tRR_min = 40000,
- .tWC_min = 100000,
- .tWH_min = 30000,
- .tWHR_min = 120000,
- .tWP_min = 50000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 200000,
+ .tALH_min = 20000,
+ .tALS_min = 50000,
+ .tAR_min = 25000,
+ .tCEA_max = 100000,
+ .tCEH_min = 20000,
+ .tCH_min = 20000,
+ .tCHZ_max = 100000,
+ .tCLH_min = 20000,
+ .tCLR_min = 20000,
+ .tCLS_min = 50000,
+ .tCOH_min = 0,
+ .tCS_min = 70000,
+ .tDH_min = 20000,
+ .tDS_min = 40000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 10000,
+ .tITC_max = 1000000,
+ .tRC_min = 100000,
+ .tREA_max = 40000,
+ .tREH_min = 30000,
+ .tRHOH_min = 0,
+ .tRHW_min = 200000,
+ .tRHZ_max = 200000,
+ .tRLOH_min = 0,
+ .tRP_min = 50000,
+ .tRST_max = 250000000000ULL,
+ .tWB_max = 200000,
+ .tRR_min = 40000,
+ .tWC_min = 100000,
+ .tWH_min = 30000,
+ .tWHR_min = 120000,
+ .tWP_min = 50000,
+ .tWW_min = 100000,
+ },
},
/* Mode 1 */
{
- .tADL_min = 100000,
- .tALH_min = 10000,
- .tALS_min = 25000,
- .tAR_min = 10000,
- .tCEA_max = 45000,
- .tCEH_min = 20000,
- .tCH_min = 10000,
- .tCHZ_max = 50000,
- .tCLH_min = 10000,
- .tCLR_min = 10000,
- .tCLS_min = 25000,
- .tCOH_min = 15000,
- .tCS_min = 35000,
- .tDH_min = 10000,
- .tDS_min = 20000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 50000,
- .tREA_max = 30000,
- .tREH_min = 15000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRP_min = 25000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 45000,
- .tWH_min = 15000,
- .tWHR_min = 80000,
- .tWP_min = 25000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 100000,
+ .tALH_min = 10000,
+ .tALS_min = 25000,
+ .tAR_min = 10000,
+ .tCEA_max = 45000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 25000,
+ .tCOH_min = 15000,
+ .tCS_min = 35000,
+ .tDH_min = 10000,
+ .tDS_min = 20000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 50000,
+ .tREA_max = 30000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 25000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 45000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 25000,
+ .tWW_min = 100000,
+ },
},
/* Mode 2 */
{
- .tADL_min = 100000,
- .tALH_min = 10000,
- .tALS_min = 15000,
- .tAR_min = 10000,
- .tCEA_max = 30000,
- .tCEH_min = 20000,
- .tCH_min = 10000,
- .tCHZ_max = 50000,
- .tCLH_min = 10000,
- .tCLR_min = 10000,
- .tCLS_min = 15000,
- .tCOH_min = 15000,
- .tCS_min = 25000,
- .tDH_min = 5000,
- .tDS_min = 15000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 35000,
- .tREA_max = 25000,
- .tREH_min = 15000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tRP_min = 17000,
- .tWC_min = 35000,
- .tWH_min = 15000,
- .tWHR_min = 80000,
- .tWP_min = 17000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 100000,
+ .tALH_min = 10000,
+ .tALS_min = 15000,
+ .tAR_min = 10000,
+ .tCEA_max = 30000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 15000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 15000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 35000,
+ .tREA_max = 25000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tRP_min = 17000,
+ .tWC_min = 35000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 17000,
+ .tWW_min = 100000,
+ },
},
/* Mode 3 */
{
- .tADL_min = 100000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 50000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 25000,
- .tDH_min = 5000,
- .tDS_min = 10000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 30000,
- .tREA_max = 20000,
- .tREH_min = 10000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRP_min = 15000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 30000,
- .tWH_min = 10000,
- .tWHR_min = 80000,
- .tWP_min = 15000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 100000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 30000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 15000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 30000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 15000,
+ .tWW_min = 100000,
+ },
},
/* Mode 4 */
{
- .tADL_min = 70000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 30000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 20000,
- .tDH_min = 5000,
- .tDS_min = 10000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 25000,
- .tREA_max = 20000,
- .tREH_min = 10000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 5000,
- .tRP_min = 12000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 25000,
- .tWH_min = 10000,
- .tWHR_min = 80000,
- .tWP_min = 12000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 70000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 20000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 25000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 12000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 25000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 12000,
+ .tWW_min = 100000,
+ },
},
/* Mode 5 */
{
- .tADL_min = 70000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 30000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 15000,
- .tDH_min = 5000,
- .tDS_min = 7000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 20000,
- .tREA_max = 16000,
- .tREH_min = 7000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 5000,
- .tRP_min = 10000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 20000,
- .tWH_min = 7000,
- .tWHR_min = 80000,
- .tWP_min = 10000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 70000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 15000,
+ .tDH_min = 5000,
+ .tDS_min = 7000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 20000,
+ .tREA_max = 16000,
+ .tREH_min = 7000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 10000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 20000,
+ .tWH_min = 7000,
+ .tWHR_min = 80000,
+ .tWP_min = 10000,
+ .tWW_min = 100000,
+ },
},
};
@@ -248,6 +266,6 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
return ERR_PTR(-EINVAL);
- return &onfi_sdr_timings[mode];
+ return &onfi_sdr_timings[mode].timings.sdr;
}
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
--
2.8.1
^ permalink raw reply related
* [PATCH 4/9] mtd: nand: Add function to convert ONFI mode to data_interface
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
onfi_init_data_interface() initializes a data interface with
values from a given ONFI mode.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_timings.c | 28 ++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 5 +++++
2 files changed, 33 insertions(+)
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 9af2ebc..608d098 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -269,3 +269,31 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
return &onfi_sdr_timings[mode].timings.sdr;
}
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+
+/**
+ * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
+ * given ONFI mode
+ * @iface: The data interface to be initialized
+ * @mode: The ONFI timing mode
+ */
+int onfi_init_data_interface(struct nand_chip *chip,
+ struct nand_data_interface *iface,
+ enum nand_data_interface_type type,
+ int timing_mode)
+{
+ if (type != NAND_SDR_IFACE)
+ return -EINVAL;
+
+ if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+ return -EINVAL;
+
+ *iface = onfi_sdr_timings[timing_mode];
+
+ /*
+ * TODO: initialize timings that cannot be deduced from timing mode:
+ * tR, tPROG, tCCS, ...
+ * These information are part of the ONFI parameter page.
+ */
+
+ return 0;
+}
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index f305bed..7216f54 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1104,6 +1104,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
}
+int onfi_init_data_interface(struct nand_chip *chip,
+ struct nand_data_interface *iface,
+ enum nand_data_interface_type type,
+ int timing_mode);
+
/*
* Check if it is a SLC nand.
* The !nand_is_slc() can be used to check the MLC/TLC nand chips.
--
2.8.1
^ permalink raw reply related
* [PATCH 5/9] mtd: nand: Expose data interface for ONFI mode 0
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
The nand layer will need ONFI mode 0 to use it as timing mode
before and right after reset.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_timings.c | 11 +++++++++++
include/linux/mtd/nand.h | 2 ++
2 files changed, 13 insertions(+)
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 608d098..9cdbc16 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -297,3 +297,14 @@ int onfi_init_data_interface(struct nand_chip *chip,
return 0;
}
+
+/**
+ * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
+ * data interface for mode 0. This is used as default timing after
+ * reset.
+ */
+const struct nand_data_interface *nand_get_default_data_interface(void)
+{
+ return &onfi_sdr_timings[0];
+}
+EXPORT_SYMBOL(nand_get_default_data_interface);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7216f54..29ae324 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1146,6 +1146,8 @@ static inline int jedec_feature(struct nand_chip *chip)
/* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+/* get data interface from ONFI timing mode 0, used after reset. */
+const struct nand_data_interface *nand_get_default_data_interface(void);
int nand_check_erased_ecc_chunk(void *data, int datalen,
void *ecc, int ecclen,
--
2.8.1
^ permalink raw reply related
* [PATCH 6/9] mtd: nand: automate NAND timings selection
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
From: Boris Brezillon <boris.brezillon@free-electrons.com>
The NAND framework provides several helpers to query timing modes supported
by a NAND chip, but this implies that all NAND controller drivers have
to implement the same timings selection dance. Also currently NAND
devices can be resetted at arbitrary places which also resets the timing
for ONFI chips to timing mode 0.
Provide a common logic to select the best timings based on ONFI or
->onfi_timing_mode_default information. Hook this into nand_reset()
to make sure the new timing is applied each time during a reset.
NAND controller willing to support timings adjustment should just
implement the ->setup_data_interface() method.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_base.c | 156 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 14 ++--
2 files changed, 166 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 1f704cc..c7d500ea 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -948,6 +948,146 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
}
/**
+ * nand_reset_data_interface - Reset data interface and timings
+ * @chip: The NAND chip
+ *
+ * Reset the Data interface and timings to ONFI mode 0.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_reset_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = &chip->mtd;
+ const struct nand_data_interface *conf;
+ int ret;
+
+ if (!chip->setup_data_interface)
+ return 0;
+
+ /*
+ * The ONFI specification says:
+ * "
+ * To transition from NV-DDR or NV-DDR2 to the SDR data
+ * interface, the host shall use the Reset (FFh) command
+ * using SDR timing mode 0. A device in any timing mode is
+ * required to recognize Reset (FFh) command issued in SDR
+ * timing mode 0.
+ * "
+ *
+ * Configure the data interface in SDR mode and set the
+ * timings to timing mode 0.
+ */
+
+ conf = nand_get_default_data_interface();
+ ret = chip->setup_data_interface(mtd, conf, false);
+ if (ret)
+ pr_err("Failed to configure data interface to SDR timing mode 0\n");
+
+ return ret;
+}
+
+/**
+ * nand_setup_data_interface - Setup the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find and configure the best data interface and NAND timings supported by
+ * the chip and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_setup_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = &chip->mtd;
+ int ret;
+
+ if (!chip->setup_data_interface || !chip->data_interface)
+ return 0;
+
+ /*
+ * Ensure the timing mode has been changed on the chip side
+ * before changing timings on the controller side.
+ */
+ if (chip->onfi_version) {
+ uint8_t tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+ chip->onfi_timing_mode_default,
+ };
+
+ ret = chip->onfi_set_features(mtd, chip,
+ ONFI_FEATURE_ADDR_TIMING_MODE,
+ tmode_param);
+ if (ret)
+ goto err;
+ }
+
+ ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+err:
+ return ret;
+}
+
+/**
+ * nand_init_data_interface - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table. After this
+ * function nand_chip->data_interface is initialized with the best timing mode
+ * available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_init_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = &chip->mtd;
+ int modes, mode, ret;
+
+ if (!chip->setup_data_interface)
+ return 0;
+
+ /*
+ * First try to identify the best timings from ONFI parameters and
+ * if the NAND does not support ONFI, fallback to the default ONFI
+ * timing mode.
+ */
+ modes = onfi_get_async_timing_mode(chip);
+ if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+ if (!chip->onfi_timing_mode_default)
+ return 0;
+
+ modes = GENMASK(chip->onfi_timing_mode_default, 0);
+ }
+
+ chip->data_interface = kzalloc(sizeof(*chip->data_interface), GFP_KERNEL);
+ if (!chip->data_interface)
+ return -ENOMEM;
+
+ for (mode = fls(modes) - 1; mode >= 0; mode--) {
+ ret = onfi_init_data_interface(chip, chip->data_interface,
+ NAND_SDR_IFACE, mode);
+ if (ret)
+ continue;
+
+ ret = chip->setup_data_interface(mtd, chip->data_interface, true);
+ if (!ret) {
+ chip->onfi_timing_mode_default = mode;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void nand_release_data_interface(struct nand_chip *chip)
+{
+ kfree(chip->data_interface);
+}
+
+/**
* nand_reset - Reset and initialize a NAND device
* @chip: The NAND chip
*
@@ -955,8 +1095,18 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
*/
int nand_reset(struct nand_chip *chip)
{
+ int ret;
+
+ ret = nand_reset_data_interface(chip);
+ if (ret)
+ return ret;
+
chip->cmdfunc(&chip->mtd, NAND_CMD_RESET, -1, -1);
+ ret = nand_setup_data_interface(chip);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -4168,6 +4318,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return PTR_ERR(type);
}
+ ret = nand_init_data_interface(chip);
+ if (ret)
+ return ret;
+
chip->select_chip(mtd, -1);
/* Check for a chip array */
@@ -4627,6 +4781,8 @@ void nand_release(struct mtd_info *mtd)
mtd_device_unregister(mtd);
+ nand_release_data_interface(chip);
+
/* Free bad block table memory */
kfree(chip->bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 29ae324..24b4190 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -743,10 +743,9 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* also from the datasheet. It is the recommended ECC step
* size, if known; if unknown, set to zero.
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
- * either deduced from the datasheet if the NAND
- * chip is not ONFI compliant or set to 0 if it is
- * (an ONFI chip is always configured in mode 0
- * after a NAND reset)
+ * set to the actually used ONFI mode if the chip is
+ * ONFI compliant or deduced from the datasheet if
+ * the NAND chip is not ONFI compliant.
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
@@ -766,6 +765,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
@@ -812,6 +812,10 @@ struct nand_chip {
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
+ int (*setup_data_interface)(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only);
+
int chip_delay;
unsigned int options;
@@ -841,6 +845,8 @@ struct nand_chip {
struct nand_jedec_params jedec_params;
};
+ struct nand_data_interface *data_interface;
+
int read_retries;
flstate_t state;
--
2.8.1
^ permalink raw reply related
* [PATCH 7/9] mtd: nand: sunxi: switch from manual to automated timing config
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
The NAND framework is now able to select the best NAND timings for us.
All we have to do is implement a ->setup_data_interface() function to
apply those timings and remove the timing selection code from the sunxi
driver.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/sunxi_nand.c | 76 ++++++++-----------------------------------
1 file changed, 14 insertions(+), 62 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index e414b31..8c59a10 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1572,14 +1572,22 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
- const struct nand_sdr_timings *timings)
+static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
+ const struct nand_sdr_timings *timings;
u32 min_clk_period = 0;
s32 tWB, tADL, tWHR, tRHW, tCAD;
long real_clk_rate;
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -ENOTSUPP;
+
/* T1 <=> tCLS */
if (timings->tCLS_min > min_clk_period)
min_clk_period = timings->tCLS_min;
@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return tRHW;
}
+ if (check_only)
+ return 0;
+
/*
* TODO: according to ONFI specs this value only applies for DDR NAND,
* but Allwinner seems to set this to 0x7. Mimic them for now.
@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0;
}
-static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
- struct device_node *np)
-{
- struct mtd_info *mtd = nand_to_mtd(&chip->nand);
- const struct nand_sdr_timings *timings;
- int ret;
- int mode;
-
- mode = onfi_get_async_timing_mode(&chip->nand);
- if (mode == ONFI_TIMING_MODE_UNKNOWN) {
- mode = chip->nand.onfi_timing_mode_default;
- } else {
- uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
- int i;
-
- mode = fls(mode) - 1;
- if (mode < 0)
- mode = 0;
-
- feature[0] = mode;
- for (i = 0; i < chip->nsels; i++) {
- chip->nand.select_chip(mtd, i);
- ret = chip->nand.onfi_set_features(mtd, &chip->nand,
- ONFI_FEATURE_ADDR_TIMING_MODE,
- feature);
- chip->nand.select_chip(mtd, -1);
- if (ret)
- return ret;
- }
- }
-
- timings = onfi_async_timing_mode_to_sdr_timings(mode);
- if (IS_ERR(timings))
- return PTR_ERR(timings);
-
- return sunxi_nand_chip_set_timings(chip, timings);
-}
-
static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -1975,7 +1948,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
- const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip;
struct mtd_info *mtd;
struct nand_chip *nand;
@@ -2065,25 +2037,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->read_buf = sunxi_nfc_read_buf;
nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte;
+ nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- timings = onfi_async_timing_mode_to_sdr_timings(0);
- if (IS_ERR(timings)) {
- ret = PTR_ERR(timings);
- dev_err(dev,
- "could not retrieve timings for ONFI mode 0: %d\n",
- ret);
- return ret;
- }
-
- ret = sunxi_nand_chip_set_timings(chip, timings);
- if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
- return ret;
- }
-
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
return ret;
@@ -2096,12 +2054,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->options |= NAND_SUBPAGE_READ;
- ret = sunxi_nand_chip_init_timings(chip, np);
- if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
- return ret;
- }
-
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
--
2.8.1
^ permalink raw reply related
* [PATCH 8/9] mtd: nand: mxc: implement onfi get/set features
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
To be able to support different ONFI timing modes we have to implement
the onfi_set_features and onfi_get_features. Tested on an i.MX25 SoC.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/mxc_nand.c | 53 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 5173fad..1db8299 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1239,6 +1239,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
+static int mxc_nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+ int addr, uint8_t *subfeature_param)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int i;
+
+ if (!chip->onfi_version ||
+ !(le16_to_cpu(chip->onfi_params.opt_cmd)
+ & ONFI_OPT_CMD_SET_GET_FEATURES))
+ return -EINVAL;
+
+ host->buf_start = 0;
+
+ for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+ chip->write_byte(mtd, subfeature_param[i]);
+
+ memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+ host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
+ mxc_do_addr_cycle(mtd, addr, -1);
+ host->devtype_data->send_page(mtd, NFC_INPUT);
+
+ return 0;
+}
+
+static int mxc_nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+ int addr, uint8_t *subfeature_param)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int i;
+
+ if (!chip->onfi_version ||
+ !(le16_to_cpu(chip->onfi_params.opt_cmd)
+ & ONFI_OPT_CMD_SET_GET_FEATURES))
+ return -EINVAL;
+
+ *(uint32_t *)host->main_area0 = 0xdeadbeef;
+
+ host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
+ mxc_do_addr_cycle(mtd, addr, -1);
+ host->devtype_data->send_page(mtd, NFC_OUTPUT);
+ memcpy32_fromio(host->data_buf, host->main_area0, 512);
+ host->buf_start = 0;
+
+ for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+ *subfeature_param++ = chip->read_byte(mtd);
+
+ return 0;
+}
+
/*
* The generic flash bbt decriptors overlap with our ecc
* hardware, so define some i.MX specific ones.
@@ -1513,6 +1564,8 @@ static int mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
+ this->onfi_set_features = mxc_nand_onfi_set_features;
+ this->onfi_get_features = mxc_nand_onfi_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
--
2.8.1
^ permalink raw reply related
* [PATCH 9/9] mtd: nand: mxc: Add timing setup for v2 controllers
From: Sascha Hauer @ 2016-09-15 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473928373-8680-1-git-send-email-s.hauer@pengutronix.de>
So far we relied on reset default or the bootloader to configure a
suitable clk rate for the Nand controller. This works but we can
optimize the timing for better performance. This sets the clk rate for
v2 controllers (i.MX25/35) based on the timing mode read from the ONFI
parameter page. This may also enable the symmetric mode (aks EDO mode)
if necessary which reads one word per clock cycle.
Tested on an i.MX25 with a Micron MT29F4G08ABBDAHC attached.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/mxc_nand.c | 84 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 82 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 1db8299..0d34d72 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
+ int (*setup_data_interface)(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int tRC_min_ns, tRC_ps, ret;
+ unsigned long rate, rate_round;
+ const struct nand_sdr_timings *timings;
+ uint16_t config1;
+
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -ENOTSUPP;
+
+ config1 = readw(NFC_V1_V2_CONFIG1);
+
+ tRC_min_ns = timings->tRC_min / 1000;
+ rate = 1000000000 / tRC_min_ns;
+
+ /*
+ * For tRC < 30ns we have to use EDO mode. In this case the controller
+ * does one access per clock cycle. Otherwise the controller does one
+ * access in two clock cycles, thus we have to double the rate to the
+ * controller.
+ */
+ if (tRC_min_ns < 30) {
+ rate_round = clk_round_rate(host->clk, rate);
+ config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
+ tRC_ps = 1000000000 / (rate_round / 1000);
+ } else {
+ rate *= 2;
+ rate_round = clk_round_rate(host->clk, rate);
+ config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
+ tRC_ps = 1000000000 / (rate_round / 1000 / 2);
+ }
+
+ /*
+ * The timing values compared against are from the i.MX25 Automotive
+ * datasheet, Table 50. NFC Timing Parameters
+ */
+ if (timings->tCLS_min > tRC_ps - 1000 ||
+ timings->tCLH_min > tRC_ps - 2000 ||
+ timings->tCS_min > tRC_ps - 1000 ||
+ timings->tCH_min > tRC_ps - 2000 ||
+ timings->tWP_min > tRC_ps - 1500 ||
+ timings->tALS_min > tRC_ps ||
+ timings->tALH_min > tRC_ps - 3000 ||
+ timings->tDS_min > tRC_ps ||
+ timings->tDH_min > tRC_ps - 5000 ||
+ timings->tWC_min > 2 * tRC_ps ||
+ timings->tWH_min > tRC_ps - 2500 ||
+ timings->tRR_min > 6 * tRC_ps ||
+ timings->tRP_min > 3 * tRC_ps / 2 ||
+ timings->tRC_min > 2 * tRC_ps ||
+ timings->tREH_min > (tRC_ps / 2) - 2500) {
+ dev_dbg(host->dev, "Timing out of bounds\n");
+ return -EINVAL;
+ }
+
+ if (check_only)
+ return 0;
+
+ ret = clk_set_rate(host->clk, rate);
+ if (ret)
+ return ret;
+
+ writew(config1, NFC_V1_V2_CONFIG1);
+
+ dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
+ config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
+ "normal");
+
+ return 0;
+}
+
static void preset_v2(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
@@ -1276,8 +1355,6 @@ static int mxc_nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *ch
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
- *(uint32_t *)host->main_area0 = 0xdeadbeef;
-
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
@@ -1378,6 +1455,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3,
+ .setup_data_interface = mxc_nand_v2_setup_data_interface,
.irqpending_quirk = 0,
.needs_ip = 0,
.regs_offset = 0x1e00,
@@ -1586,6 +1664,8 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0)
return err;
+ this->setup_data_interface = host->devtype_data->setup_data_interface;
+
if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
--
2.8.1
^ permalink raw reply related
* [RFC PATCH 00/11] pci: support for configurable PCI endpoint
From: Kishon Vijay Abraham I @ 2016-09-15 8:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2837059.ka7z3gzjF2@wuerfel>
Hi Arnd,
On Wednesday 14 September 2016 06:55 PM, Arnd Bergmann wrote:
> On Wednesday, September 14, 2016 10:41:56 AM CEST Kishon Vijay Abraham I wrote:
>> This patch series
>> *) adds PCI endpoint core layer
>> *) modifies designware/dra7xx driver to be configured in EP mode
>> *) adds a PCI endpoint *test* function driver
>
> Hi Kishon,
>
> I think this is a great start, thanks for posting early with a clear
> list of limitations and TODO items.
Thank you :-)
>
> I've added the drivers/ntb maintainers to Cc, given that there is
> a certain degree of overlap between your work and the existing
> code, I think they should be part of the discussion.
>
>> Known Limitation:
>> *) Does not support multi-function devices
>
> If I understand it right, this was a problem for USB and adding
> it later made it somewhat inconsistent. Maybe we can at least
> try to come up with an idea of how multi-function devices
> could be handled even if we don't implement it until someone
> actually needs it.
Actually IMO multi-function device in PCI should be much simpler than it is for
USB. In the case of USB, all the functions in a multi-function device will
share the same *usb configuration* . (USB device can have multiple
configuration but only one can be enabled at a time). A multi-function USB
device will still have a single vendor-id/product-id/class... So I think a
separate library (composite.c) in USB makes sense.
But in the case of PCI, every function can be treated independently since all
the functions have it's own 4KB configuration space. Each function can be
configured independently. Each can have it's own vendor-id/product-id/class..
I'm not sure if we'll need a separate library for PCI like we have for USB.
Now the restriction for not allowing multi-function device is because of the
following structure definition.
struct pci_epc {
..
struct pci_epf *epf;
..
};
EPC has a single reference to EPF and it is used *only* to notify the function
driver when the link is up. (If this can be changed to use notification
mechanism, multi-function devices can be supported here)
One more place where this restriction arises is in designware driver
struct dw_pcie_ep {
..
u8 bar_to_atu[6];
..
};
We use single ATU window to configure a BAR (in BAR). If there are multiple
functions, then this should also be modified since each function has 6 BARs.
This can be fixed without much effort unless some other issue props up.
>
> Is your hardware able to make the PCIe endpoint look like
> a device with multiple PCI functions, or would one have to
> do this in software inside of a single PCI function if we
> ever need it?
The hardware I have doesn't support multiple PCI functions (like having a
separate configuration space for each function). It has a dedicated space for
configuration space supporting only one function. [Section 24.9.7.3.2
PCIe_SS_EP_CFG_DBICS Register Description in [1]].
yeah, it has to be done in software (but that won't be multi-function device in
PCI terms).
[1] -> http://www.ti.com/lit/ug/spruhz6g/spruhz6g.pdf
>
>> TODO:
>> *) access buffers in RC
>> *) raise MSI interrupts
>> *) Enable user space control for the RC side PCI driver
>
> The user space control would end up just being one of several
> gadget drivers, right? E.g. gadget drivers for standard hardware
> (8250 uart, ATA, NVMe, some ethernet) could be done as kernel
> drivers while a user space driver can be used for things that
> are more unusual and that don't need to interface to another
> part of the kernel?
Actually I didn't mean that. It was more with respect to the host side PCI test
driver (drivers/misc/pci_endpoint_test.c). Right now it validates BAR, irq
itself. I wanted to change this so that the user controls which tests to run.
(Like for USB gadget zero tests, testusb.c invokes ioctls to perform various
tests). Similarly I want to have a userspace program invoke pci_endpoint_test
to perform various PCI tests.
>
>> *) Adapt all other users of designware to use the new design (only
>> dra7xx has been adapted)
>
> I don't fully understand this part. Does every designware based
> driver need modifications, or are the changes to the
> generic parts of the designware driver enough to make it
> work for the simpler platforms?
I have changed the core designware driver structures (like previously the
platform drivers will only use pcie_port, but now I introduced struct dw_pcie
to support both host and endpoint). This will break (compilation failure) all
the designware based drivers (except dra7xx). All these drivers should be
adapted to the new change (even if they work only in host mode these has to be
adapted).
>
>> HOW TO:
>>
>> ON THE EP SIDE:
>> ***************
>>
>> /* EP function is configured using configfs */
>> # mount -t configfs none /sys/kernel/config
>>
>> /* PCI EP core layer creates "pci_ep" entry in configfs */
>> # cd /sys/kernel/config/pci_ep/
>>
>> /*
>> * This is the 1st step in creating an endpoint function. This
>> * creates the endpoint function device *instance*. The string
>> * before the .<num> suffix will identify the driver this
>> * EP function will bind to.
>> * Just pci_epf_test is also valid. The .<num> suffix is used
>> * if there are multiple PCI controllers and all of them wants
>> * to use the same function.
>> */
>> # mkdir pci_epf_test.0
>
> I haven't used USB gadgets, but I assume this is modeled around
> the same interface. If there are notable differences, please mention
> what they are. Otherwise the general concept seems rather nice to me.
Yeah, both USB gadget and PCI endpoint use configfs interface but the semantics
are quite different.
Every directory in *usb_gadget* corresponds to a gadget device, and the gadget
device has a functions sub-directory which has the USB functions. And these
directories have fields or attributes specific to USB.
But in the case of PCI, every directory in *pci_ep* corresponds to a PCI
function and it has fields or attributes specific to PCI function.
The main reason for using configfs for PCI endpoint is to give the users to
control "which function has to be bound to which controller". The same concept
is used for USB gadget as well but there it is "which gadget device has to be
bound to which controller".
>
>> drivers/pci/{host => controller}/Kconfig | 109 +++++-
>> drivers/pci/{host => controller}/Makefile | 2 +
>> drivers/pci/{host => controller}/pci-aardvark.c | 0
>> drivers/pci/{host => controller}/pci-dra7xx.c | 340 +++++++++++++----
>> drivers/pci/{host => controller}/pci-exynos.c | 0
>> drivers/pci/{host => controller}/pci-host-common.c | 0
>> .../pci/{host => controller}/pci-host-generic.c | 0
>> drivers/pci/{host => controller}/pci-hyperv.c | 0
>> drivers/pci/{host => controller}/pci-imx6.c | 0
>> drivers/pci/{host => controller}/pci-keystone-dw.c | 0
>> drivers/pci/{host => controller}/pci-keystone.c | 0
>> drivers/pci/{host => controller}/pci-keystone.h | 0
>
> Maybe it's better to wait before moving it around, this will make
> it harder for you to rebase the patch series while you are working on
> it and other people are working on the existing code.
These patches just do "mv drivers/pci/host drivers/pci/controller", so I guess
irrespective of the changes in the existing driver it should just move. Anyways
I have to check this.
>
> I'd suggest dropping the rename patches for the moment and just work
> in drivers/pci/host.
Okay.
>
> Let's talk (high-level) about the DT binding. I see that the way
> you have done it here, one will need to have a different .dtb file
> for a machine depending on whether the PCIe is used in host or
> endpoint mode. The advantage of this way is that it's a much
> cleaner binding (PCIe host bindings are a mess, and adding more
> options to it will only make it worse), the downside is that
> you can't decide at runtime what you want to use it for. E.g.
> connecting two identical machines over PCIe requires deciding
> in the bootloader which one is the endpoint, or using DT
> overlays, which may be awkward for some users. Is this a realistic
> use case, or do you expect that all machines will only ever be
> used in one of the two ways?
It would definitely be nice to select the mode at runtime. Even for this patch
series, I added a temporary dtsi patch to configure the pci controller in EP
mode (which can't be merged since the same controller is also used to test RC).
Thanks
Kishon
^ permalink raw reply
* [PATCH 0/3] clk: sunxi-ng: sun6i-a31: Register offset and clk flag fixes
From: Maxime Ripard @ 2016-09-15 8:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160915065740.13664-1-wens@csie.org>
Hi,
On Thu, Sep 15, 2016 at 02:57:37PM +0800, Chen-Yu Tsai wrote:
> Hi,
>
> Here are 3 fixes for the new sunxi-ng clk driver for sun6i-a31 recently
> introduced for 4.9. The issues were noticed while working on the display
> pipeline for the A31/A31s. The second patch follows what Maxime has done
> for the A33 CCU driver. The third issue was noticed while doing the first
> patch.
>
> I hope we can get this into 4.9 as well, either right in -rc1, or in a
> later -rc.
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Stephen, could you apply those patches directly on top of my previous
PR, or do you want me to send another one?
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160915/9197698c/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: dts: sun8i: enable UART1 for iNet D978 Rev2 board
From: Maxime Ripard @ 2016-09-15 8:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1262161473906138@web14h.yandex.ru>
On Thu, Sep 15, 2016 at 10:22:18AM +0800, Icenowy Zheng wrote:
>
>
> 15.09.2016, 10:15, "Icenowy Zheng" <icenowy@aosc.xyz>:
> > UART1 is connected to the bluetooth part of RTL8723BS WiFi/BT combo card
> > on iNet D978 Rev2 board.
> >
> > Enable the UART1 to make it possible to use the modified hciattach by
> > Realtek to drive the BT part of RTL8723BS.
> >
> > On the board no r_uart pins are found now (the onboard RX/TX pins are
> > wired to PF2/PF4, which is muxed with mmc0), so also disabled it.
> >
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
>
> Oh I forgot to add a patch version number...
> It's PATCH v3.
>
> (But it seems that I should send a v4 to split the dtsi change and dts change.)
Indeed :)
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160915/792e2739/attachment.sig>
^ permalink raw reply
* [GIT PULL 2/3] DaVinci dts updates for v4.9
From: Sekhar Nori @ 2016-09-15 8:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3347114.RAnckMhlMa@wuerfel>
Hi Arnd,
On Wednesday 14 September 2016 09:23 PM, Arnd Bergmann wrote:
> On Wednesday, August 24, 2016 4:30:05 PM CEST Sekhar Nori wrote:
>> DaVinci DA850 device-tree enhancements include:
>>
>> - Support for new board OMAP-L138 LCDK
>> - Add AEMIF node on DA850 EVM and use it for NAND
>> - Audio support for LCDK
>> - Cleanups for PWM and UART
>>
>>
>
> This one fails to build:
>
>
> ERROR (phandle_references): Reference to non-existent node or label "nand_cs3_pins"
>
> ERROR: Input tree has errors, aborting (use -f to force output)
> DTC arch/arm/boot/dts/bcm47081-asus-rt-n18u.dtb
>
>
> Can you send a fixed version please?
Did the merge happen cleanly? There should be no nand_cs3_pins if the
merge was clean. It should be removed with 31e3a8817b66 ("ARM: dts:
da850,da850-evm: Add an aemif node and use it for the NAND").
If the merge was clean, can you please push the offending tree to some
place I can fetch and take a look. I dont have "nand_cs3_pins" in my
tree anymore nor I can reproduce the build break.
Thanks,
Sekhar
^ permalink raw reply
* [RFC PATCH v2 10/11] irqchip: mbigen: Add ACPI support
From: Marc Zyngier @ 2016-09-15 8:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-11-git-send-email-guohanjun@huawei.com>
On 14/09/16 15:21, Hanjun Guo wrote:
> From: Hanjun Guo <hanjun.guo@linaro.org>
>
> With the preparation of platform msi support and interrupt producer
> in DSDT, we can add mbigen ACPI support now.
>
> We are using _PRS methd to indicate number of irq pins instead
> of num_pins in DT.
>
> For mbi-gen,
> Device(MBI0) {
> Name(_HID, "HISI0152")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
> })
>
> Name (_PRS, ResourceTemplate() {
> Interrupt(ResourceProducer,...) {12,14,....}
> })
Since I know next to nothing about all of this, I'm going to play the
village idiot. What makes it legal to use _PRS as a way to describe the
interrupts that are exposed by MBI0? Looking at the 6.0 spec, I do not
see why the interrupts would be put there instead of _CRS, and why you'd
have a _PRS at all.
Also, are you going to exhaustively describe all the possible interrupts
via this method? Knowing that the mbigen can expose thousands of
interrupts, I find it slightly mad. Can't you express a range?
> }
>
> For devices,
>
> Device(COM0) {
> Name(_HID, "ACPIIDxx")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xb0030000, 0x10000)
> Interrupt(ResourceConsumer,..., "\_SB.MBI0") {12}
> })
> }
>
> With the helpe of platform msi and interrupt producer, then devices
> will get the virq from mbi-gen's irqdomain.
>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ma Jun <majun258@huawei.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
> drivers/irqchip/irq-mbigen.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index 9484ea0..ca6add1 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -16,6 +16,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/acpi.h>
> #include <linux/interrupt.h>
> #include <linux/irqchip.h>
> #include <linux/module.h>
> @@ -180,7 +181,7 @@ static int mbigen_domain_translate(struct irq_domain *d,
> unsigned long *hwirq,
> unsigned int *type)
> {
> - if (is_of_node(fwspec->fwnode)) {
> + if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
> if (fwspec->param_count != 2)
> return -EINVAL;
>
> @@ -271,6 +272,54 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,
> + void *context)
> +{
> + struct acpi_resource_extended_irq *ext_irq;
> + u32 *num_irqs = context;
> +
> + switch (ares->type) {
> + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> + ext_irq = &ares->data.extended_irq;
> + *num_irqs += ext_irq->interrupt_count;
> + break;
> + default:
> + break;
> + }
> +
> + return AE_OK;
> +}
> +
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + struct irq_domain *domain;
> + u32 num_msis = 0;
> + acpi_status status;
> +
> + status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,
> + mbigen_acpi_process_resource, &num_msis);
> + if (ACPI_FAILURE(status) || num_msis == 0)
> + return -EINVAL;
> +
> + domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
> + mbigen_write_msg,
> + &mbigen_domain_ops,
> + mgn_chip);
> + if (!domain)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +#else
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + return -ENODEV;
> +}
> +#endif
> +
> static int mbigen_device_probe(struct platform_device *pdev)
> {
> struct mbigen_device *mgn_chip;
> @@ -288,9 +337,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
> if (IS_ERR(mgn_chip->base))
> return PTR_ERR(mgn_chip->base);
>
> - err = mbigen_of_create_domain(pdev, mgn_chip);
> - if (err)
> + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
> + err = mbigen_of_create_domain(pdev, mgn_chip);
> + else if (ACPI_COMPANION(&pdev->dev))
> + err = mbigen_acpi_create_domain(pdev, mgn_chip);
> + else
> + err = -EINVAL;
> +
> + if (err) {
> + dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);
> return err;
> + }
>
> platform_set_drvdata(pdev, mgn_chip);
> return 0;
> @@ -302,10 +359,17 @@ static const struct of_device_id mbigen_of_match[] = {
> };
> MODULE_DEVICE_TABLE(of, mbigen_of_match);
>
> +static const struct acpi_device_id mbigen_acpi_match[] = {
> + { "HISI0152", 0 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
> +
> static struct platform_driver mbigen_platform_driver = {
> .driver = {
> .name = "Hisilicon MBIGEN-V2",
> .of_match_table = mbigen_of_match,
> + .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
> },
> .probe = mbigen_device_probe,
> };
>
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [GIT PULL] arm64: defconfig: hisilicon config updates for v4.9
From: Wei Xu @ 2016-09-15 8:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9688524.ke398xgQyd@wuerfel>
Hi Arnd,
On 14/09/2016 23:03, Arnd Bergmann wrote:
> On Friday, September 2, 2016 11:37:41 AM CEST Wei Xu wrote:
>> ARM64: hisilicon: defconfig updates for 4.9
>>
>> - Enable hisilicon SAS and XGE for hip05 and hip06
>> - Enable drm, powerkey, bluetooth and adv7511/adv7533 for hikey
>> - Add PINCTRL to HISI platform
>>
>
> Pulled into next/arm64, thanks!
Thanks!
Best Regards,
Wei
>
> Arnd
>
>
> .
>
^ permalink raw reply
* [GIT PULL] arm64: dts: hisilicon dts updates for v4.9
From: Wei Xu @ 2016-09-15 8:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4112756.vQdZALs121@wuerfel>
Hi Arnd,
On 14/09/2016 16:06, Arnd Bergmann wrote:
> On Friday, September 2, 2016 11:33:56 AM CEST Wei Xu wrote:
>> ARM64: DT: Hisilicon SoC DT updates for 4.9
>>
>> - Set UART1 clock frequency to 150MHz for higher baud rates on hikey
>> - Add display subsystem, HDMI and cma nodes on hikey to support display
>> - Add syscon-reboot-mode support on hikey
>> - Add pstore support on hikey
>> - Add resets and sd-uhs-sdr property dwmmc ndoe on hikey
>> - Remove hip05_hns.dtsi since it can not be built without mbigenv1
>> - Update system controller bingding document for hip05 and hip06
>> - Add xge and sas support on hip06
>>
>
> Pulled into next/dt64, thanks!
Thanks!
Best Regards,
Wei
>
> Arnd
>
>
> .
>
^ permalink raw reply
* [RFC/PATCH] usb: misc: Add a driver for TC7USB40MU
From: Peter Chen @ 2016-09-15 9:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <147384270449.13546.495288874027868435@sboyd-linaro>
On Wed, Sep 14, 2016 at 01:45:04AM -0700, Stephen Boyd wrote:
> Quoting Peter Chen (2016-09-14 01:03:21)
> > On Tue, Sep 13, 2016 at 10:58:26PM -0700, Stephen Boyd wrote:
> > > Quoting Peter Chen (2016-09-13 20:32:00)
> > > > On Tue, Sep 13, 2016 at 06:42:46PM -0700, Stephen Boyd wrote:
> > > > > On the db410c 96boards platform we have a TC7USB40MU[1] on the
> > > > > board to mux the D+/D- lines from the SoC between a micro usb
> > > > > "device" port and a USB hub for "host" roles. Upon a role switch,
> > > > > we need to change this mux to forward the D+/D- lines to either
> > > > > the port or the hub. Therefore, introduce a driver for this
> > > > > device that intercepts extcon USB_HOST events and logically
> > > > > asserts a gpio to mux the "host" D+/D- lines when a host cable is
> > > > > attached. When the cable goes away, it will logically deassert
> > > > > the gpio and mux the "device" lines.
> > > >
> > > > Would you please draw the design? It can also help me review your
> > > > chipidea patch well.
> > > >
> > > > 1. How many ports on the board?
> > > > 2. How the lines are connected on the board?
> > > >
> > >
> > > The schematic for the db410c is publically available here[2][3].
> > >
> > > There's also the 96boards spec[4] which talks about this switch based
> > > design a little bit. See the section titled "Single USB port Example".
> > >
> > > [2] https://github.com/96boards/documentation/blob/master/ConsumerEdition/DragonBoard-410c/HardwareDocs/Schematics_DragonBoard.pdf
> > > [3] https://github.com/96boards/documentation/raw/master/ConsumerEdition/DragonBoard-410c/HardwareDocs/Schematics_DragonBoard.pdf
> > > [4] https://www.96boards.org/wp-content/uploads/2015/02/96BoardsCESpecificationv1.0-EA1.pdf
> >
> > Ok, I see several use cases for this role switch
> >
> > 1. Using the hardware switch (218-4LPST)
> > In this case, you can set USB_SW_SEL as input gpio, and use
> > extcon-usb-gpio.c like before, just set this gpio as active
> > low at dts.
>
> Nice! I didn't think of this case but it's good that we can support
> that with some work.
>
After looking more, I find the main purpose of this switch is
what it writes, FORCE DSI SELECTION TO USB HOST MODE
When the switch is on, the system is host-only.
When the switch is off, the default role is device mode, and
switch the role through gpio USB_SW_SEL_PM by software.
> >
> > 2. Using USB_HS_ID as vbus-gpio (input), and USB_SW_SEL as id-gpio (output)
>
> This is pretty much what has been implemented. USB_HS_ID is an
> extcon-usb-gpio.c device.
At some designs, this gpio is tied to ID pin at MicroB connector, and
using a Mirco-AB cable to switch the role.
>
> > I can't find hardware relationship between each other, maybe I miss
> > something.
>
> I believe USB_SW_SEL is the physical switch (218-4LPST) while
> USB_SW_SEL_PM is the software controllable part using a GPIO. USB_HS_ID
> is just the vbus line from the uB connector and that line goes straight
> into the SoC via a GPIO.
>
> > This use case (design) seems strange, usually, we use ID pin controls
> > vbus, but seldom use vbus pin control ID.
> > How you would like to implement it? When the USB cable is connected
> > (between PC), it receives vbus-gpio interrupt, then you set USB_SW_SEL
> > as low? If disconnected, you set USB_SW_SEL as high?
>
> Right. The documented behavior is to detect the micro-usb cable and
> drive USB_SW_SEL low. When the cable is unplugged we drive USB_SW_SEL
> high. Maybe that should be changed though? If we always sampled
> USB_SW_SEL as a USB_HOST extcon and the vbus line as a USB extcon then
> we could allow the user to decide either with the physical switch or
> with some sort of software control to toggle that gpio.
>
> > When the USB controller works at Host mode, what will happen if the user
> > connects USB cable at device port?
>
> The devices on the two type-A connectors will be disconnected and we'll
> switch from host mode to device mode.
>
> >
> > 3. Using sysfs to switch the role
> > Set USB_SW_SEL according to "role" at debugfs
>
> sysfs isn't debugfs, but yes I wonder if we need to worry about the
> debugfs role switching support here and toggle the gpio manually without
> involving extcon. That would mean we need to have a way for the chipidea
> controller to toggle this gpio/mux itself.
>
> >
> > Which one you would like to implement? Or anything else I miss?
> >
>
> Mostly #2, but I'm concerned that the DT binding is going to force that
> decision on others who may have the same switch and want to do #1 or #3.
> So how to design it in a way that makes it work in all cases? Also, what
> to do if the USB_SW_SEL switch is driven high by the physical switch?
> That will "override" any software control we might be able to use, so
> hopefully we can detect this somehow and prevent the role switch from
> happening.
>From my point, the physical switch is only used to force host mode. The
#1 and #2 can't be supported at the same time. For #3, it is not the
use case for this design. #3 is usually used for the single port which
needs to support switching role on the fly without disconnection.
So, you may only need to consider #2, you can't use extcon-usb-gpio.c
directly since you need to set one gpio to mux the dp/dm, Baolu Lu had
USB MUX patch set before which may satisfy your requirement. [1]
[1] https://lkml.org/lkml/2016/5/30/36
--
Best Regards,
Peter Chen
^ permalink raw reply
* [PATCH v4 01/10] arm64: KVM: Use static keys for selecting the GIC backend
From: Christoffer Dall @ 2016-09-15 9:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57D96AA0.2010607@arm.com>
On Wed, Sep 14, 2016 at 04:20:00PM +0100, Vladimir Murzin wrote:
> On 13/09/16 10:22, Christoffer Dall wrote:
> > On Tue, Sep 13, 2016 at 10:11:10AM +0100, Marc Zyngier wrote:
> >> On 13/09/16 09:20, Christoffer Dall wrote:
> >>> On Mon, Sep 12, 2016 at 03:49:15PM +0100, Vladimir Murzin wrote:
> >>>> Currently GIC backend is selected via alternative framework and this
> >>>> is fine. We are going to introduce vgic-v3 to 32-bit world and there
> >>>> we don't have patching framework in hand, so we can either check
> >>>> support for GICv3 every time we need to choose which backend to use or
> >>>> try to optimise it by using static keys. The later looks quite
> >>>> promising because we can share logic involved in selecting GIC backend
> >>>> between architectures if both uses static keys.
> >>>>
> >>>> This patch moves arm64 from alternative to static keys framework for
> >>>> selecting GIC backend. For that we embed static key into vgic_global
> >>>> and enable the key during vgic initialisation based on what has
> >>>> already been exposed by the host GIC driver.
> >>>>
> >>>> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
> >>>> ---
> >>>> arch/arm64/kvm/hyp/switch.c | 21 +++++++++++----------
> >>>> include/kvm/arm_vgic.h | 4 ++++
> >>>> virt/kvm/arm/vgic/vgic-init.c | 4 ++++
> >>>> virt/kvm/arm/vgic/vgic.c | 2 +-
> >>>> 4 files changed, 20 insertions(+), 11 deletions(-)
> >>>>
> >>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> >>>> index 5a84b45..d5c4cc5 100644
> >>>> --- a/arch/arm64/kvm/hyp/switch.c
> >>>> +++ b/arch/arm64/kvm/hyp/switch.c
> >>>> @@ -16,6 +16,8 @@
> >>>> */
> >>>>
> >>>> #include <linux/types.h>
> >>>> +#include <linux/jump_label.h>
> >>>> +
> >>>> #include <asm/kvm_asm.h>
> >>>> #include <asm/kvm_hyp.h>
> >>>>
> >>>> @@ -126,17 +128,13 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
> >>>> write_sysreg(0, vttbr_el2);
> >>>> }
> >>>>
> >>>> -static hyp_alternate_select(__vgic_call_save_state,
> >>>> - __vgic_v2_save_state, __vgic_v3_save_state,
> >>>> - ARM64_HAS_SYSREG_GIC_CPUIF);
> >>>> -
> >>>> -static hyp_alternate_select(__vgic_call_restore_state,
> >>>> - __vgic_v2_restore_state, __vgic_v3_restore_state,
> >>>> - ARM64_HAS_SYSREG_GIC_CPUIF);
> >>>> -
> >>>> static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
> >>>> {
> >>>> - __vgic_call_save_state()(vcpu);
> >>>> + if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>
> >>> It's a bit weird that we use _unlikely for GICv3 (at least if/when GICv3
> >>> hardware becomes mainstream), but as we don't have another primitive for
> >>> the 'default disabled' case, I suppose that's the best we can do.
> >>
> >> We could always revert the "likelihood" of that test once GICv3 has
> >> conquered the world. Or start patching the 32bit kernel like we do for
> >> 64bit...
> >>
> >>>
> >>>> + __vgic_v3_save_state(vcpu);
> >>>> + else
> >>>> + __vgic_v2_save_state(vcpu);
> >>>> +
> >>>> write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
> >>>> }
> >>>>
> >>>> @@ -149,7 +147,10 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
> >>>> val |= vcpu->arch.irq_lines;
> >>>> write_sysreg(val, hcr_el2);
> >>>>
> >>>> - __vgic_call_restore_state()(vcpu);
> >>>> + if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>> + __vgic_v3_restore_state(vcpu);
> >>>> + else
> >>>> + __vgic_v2_restore_state(vcpu);
> >>>> }
> >>>>
> >>>> static bool __hyp_text __true_value(void)
> >>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >>>> index 19b698e..994665a 100644
> >>>> --- a/include/kvm/arm_vgic.h
> >>>> +++ b/include/kvm/arm_vgic.h
> >>>> @@ -23,6 +23,7 @@
> >>>> #include <linux/types.h>
> >>>> #include <kvm/iodev.h>
> >>>> #include <linux/list.h>
> >>>> +#include <linux/jump_label.h>
> >>>>
> >>>> #define VGIC_V3_MAX_CPUS 255
> >>>> #define VGIC_V2_MAX_CPUS 8
> >>>> @@ -63,6 +64,9 @@ struct vgic_global {
> >>>>
> >>>> /* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >>>> bool can_emulate_gicv2;
> >>>> +
> >>>> + /* GIC system register CPU interface */
> >>>> + struct static_key_false gicv3_cpuif;
> >>>
> >>> Documentation/static-keys.txt says that we are not supposed to use
> >>> struct static_key_false directly. This will obviously work quite
> >>> nicely, but we could consider adding a pair of
> >>> DECLARE_STATIC_KEY_TRUE/FALSE macros that don't have the assignments,
> >>> but obviously this will need an ack from other maintainers.
> >>>
> >>> Thoughts?
> >>
> >> Grepping through the tree shows that we're not the only abusers of this
> >> (dynamic debug is far worse!). Happy to write the additional macros and
> >> submit them if nobody beats me to it.
> >>
> >>>
> >>>
> >>>> };
> >>>>
> >>>> extern struct vgic_global kvm_vgic_global_state;
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> >>>> index 83777c1..14d6718 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-init.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-init.c
> >>>> @@ -405,6 +405,10 @@ int kvm_vgic_hyp_init(void)
> >>>> break;
> >>>> case GIC_V3:
> >>>> ret = vgic_v3_probe(gic_kvm_info);
> >>>> + if (!ret) {
> >>>> + static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
> >>>> + kvm_info("GIC system register CPU interface\n");
> >>>
> >>> nit: add enabled to the info message?
> >>>
> >>>> + }
> >>>> break;
> >>>> default:
> >>>> ret = -ENODEV;
> >>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>>> index e83b7fe..8a529a7 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>>> @@ -29,7 +29,7 @@
> >>>> #define DEBUG_SPINLOCK_BUG_ON(p)
> >>>> #endif
> >>>>
> >>>> -struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
> >>>> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state = {.gicv3_cpuif = STATIC_KEY_FALSE_INIT,};
> >>>>
> >>>> /*
> >>>> * Locking order is always:
> >>>> --
> >>>> 1.7.9.5
> >>>>
> >>>
> >>> Overall this looks really nice, as long as we're clear on the static
> >>> keys stuff.
> >>
> >> Indeed, we should get this sorted, though I'm not sure this should be a
> >> blocker for this code.
> >>
> > Agreed, let's ship it!
>
> To make it clear, should I respin with "enabled" into the info message
> and macros for static keys?
>
No, I can fix up the info message and we can worry aboutt he macros
later. Marc said he would be happy to do that :)
-Christoffer
^ permalink raw reply
* [PATCH] ARM: s3c24xx: Add dma_slave_map for s3c2440 devices
From: Sylwester Nawrocki @ 2016-09-15 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473877775-7537-1-git-send-email-sam.van.den.berge@telenet.be>
On 09/14/2016 08:29 PM, Sam Van Den Berge wrote:
> +static const struct dma_slave_map s3c2440_dma_slave_map[] = {
...
> + { "3c2440-sdi", "rx", (void *)DMACH_SDI },
> + { "3c2440-sdi", "tx", (void *)DMACH_SDI },
The device names seem misspelled here, and looking at what
drivers/mmc/host/s3cmci.c driver does we need just a single common
entry for rx and tx
{ "s3c2440-sdi", "rx-tx", (void *)DMACH_SDI },
With this fixed feel free to add
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
--
Thanks,
Sylwester
^ permalink raw reply
* [PATCHv3 00/11] crypto: omap HW crypto fixes
From: Tero Kristo @ 2016-09-15 9:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160913123849.GA31890@gondor.apana.org.au>
On 13/09/16 15:38, Herbert Xu wrote:
> On Thu, Aug 04, 2016 at 01:28:35PM +0300, Tero Kristo wrote:
>> Hi,
>>
>> This revision took quite a bit time to craft due to the rework needed
>> for sham buffer handling and export/import. I ended up implementing
>> a flush functionality for draining out the sham buffer when doing
>> export/import; just shrinking the buffer to sufficiently small size
>> impacted the performance with small data chunks too much so I dropped
>> this approach.
>>
>> The series also fixes a couple of existing issues with omap2/omap3
>> hardware acceleration, I ran a full boot test / crypto manager
>> test suite on all boards accessible to me now.
>>
>> Based on top of latest mainline, which is somewhere before 4.8-rc1
>> as of writing this, I am unable to rebase the series during the next
>> three weeks so wanted to get this out now. Targeted for 4.9 merge
>> window, some fixes could be picked up earlier though if needed.
>
> I have applied patches 1,4-5,7-11. Some of them didn't apply
> cleanly so please check the result in my tree.
>
> Thanks,
>
Thanks Herbert,
I just gave a trial for your branch, and seems to be working for me.
Also checked the patches you applied and they seem fine also.
I have also a new version of the sha buffer handling and export/import
available now, but need to cleanup it quite a bit, and figure out how to
split the patch properly.
drivers/crypto/omap-sham.c | 532
++++++++++++++++++++++++++-------------------
... It now uses sg for xmitting data where possible, and avoids the need
for a large internal buffer. The buffer size is also now properly
configurable, which can be used to overcome the performance issues if
needed (this however, requires the max statesize hack within the
crypto/ahash.c file, but thats fine.) I'll hopefully post this out maybe
tomorrow, but its going to be targeted for 4.10 I believe due to the
(ahem, rather) intrusive changes.
-Tero
^ permalink raw reply
* [PATCH v4 00/10] ARM: KVM: Support for vgic-v3
From: Christoffer Dall @ 2016-09-15 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473691764-29424-1-git-send-email-vladimir.murzin@arm.com>
Hi Valdimir,
On Mon, Sep 12, 2016 at 03:49:14PM +0100, Vladimir Murzin wrote:
> Hi,
>
> This is an attempt to make use vgic-v3 under arch/arm since
> save-restore functionality got re-written in C and can be shared
> between arm/arm64 like it has already been done for vgic-v2 and timer.
>
> With this patches I'm able to get 32 core an AArch32 ARMv8 guest boot:
>
> ...
> GICv3: CPU31: found redistributor 703 region 0:0x000000003ffd0000
> CPU31: thread -1, cpu 3, socket 7, mpidr 80000703
> Brought up 32 CPUs
> SMP: Total of 32 processors activated (768.00 BogoMIPS).
> CPU: All CPU(s) started in SVC mode.
> ...
>
> Additionally, quite lightweight test based on Self IPI guest test[1]
> has been run with up to 255 cpus.
>
I have applied this to kvmarm/queue, fixing up a few trivial conflicts,
and I have changed the kvm_info message.
If you could test the integrated branch with GICv3 on a 32-bit platform,
that would be great.
I'll give people a few days to give their acks to the non-KVM part of
the series and will then put it in next.
Thanks for the work,
-Christoffer
^ permalink raw reply
* [PATCHv3 06/11] crypto: omap-des: Fix support for unequal lengths
From: Tero Kristo @ 2016-09-15 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160913093506.GA30561@gondor.apana.org.au>
On 13/09/16 12:35, Herbert Xu wrote:
> On Thu, Aug 04, 2016 at 01:28:41PM +0300, Tero Kristo wrote:
>> From: Lokesh Vutla <a0131933@ti.com>
>>
>> For cases where total length of an input SGs is not same as
>> length of the input data for encryption, omap-des driver
>> crashes. This happens in the case when IPsec is trying to use
>> omap-des driver.
>>
>> To avoid this, we copy all the pages from the input SG list
>> into a contiguous buffer and prepare a single element SG list
>> for this buffer with length as the total bytes to crypt, which is
>> similar thing that is done in case of unaligned lengths.
>
> Ugh, that means copying every single packet, right?
>
> So if it's just the SG list that's the problem, why don't you
> copy that instead? That is, allocate a new SG list and set it
> up so that there is no excess data.
>
> Cheers,
>
I'll take a look at this. I have this kind of solution in place for the
re-worked SHA driver, so can probably re-use it here.
-Tero
^ permalink raw reply
* [PATCH v2 1/3] serial: xuartps: Adds RXBS register support for zynqmp
From: Nava kishore Manne @ 2016-09-15 9:15 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds RXBS register access support for zynqmp.
To avoid the corner error conditions it will consider only
RXBS[2:0] bits while checking the error conditions
(Parity,Framing and BRAK).
Signed-off-by: Nava kishore Manne <navam@xilinx.com>
---
Changes for v2:
-Initialize 'rxbs_status = 0'
drivers/tty/serial/xilinx_uartps.c | 101 +++++++++++++++++++++++++++++--------
1 file changed, 81 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 9ca1a4d..527526e 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
#define CDNS_UART_ISR 0x14 /* Interrupt Status */
#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
-#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
+#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
+#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
/* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
@@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
+#define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */
+#define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */
+#define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */
/*
* Mode Register:
@@ -131,8 +135,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
CDNS_UART_IXR_TOUT)
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
-#define CDNS_UART_IXR_BRK 0x80000000
+#define CDNS_UART_IXR_BRK 0x00002000
+#define CDNS_UART_RXBS_SUPPORT BIT(1)
/*
* Modem Control register:
* The read/write Modem Control register controls the interface with the modem
@@ -172,18 +177,29 @@ struct cdns_uart {
struct clk *pclk;
unsigned int baud;
struct notifier_block clk_rate_change_nb;
+ u32 quirks;
+};
+struct cdns_platform_data {
+ u32 quirks;
};
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb);
static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
{
+ struct cdns_uart *cdns_uart = port->private_data;
+ bool is_rxbs_support;
+ unsigned int rxbs_status = 0;
+ unsigned int status_mask;
+
+ is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
+
/*
* There is no hardware break detection, so we interpret framing
* error with all-zeros data as a break sequence. Most of the time,
* there's another non-zero byte at the end of the sequence.
*/
- if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) {
while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY)) {
if (!readl(port->membase + CDNS_UART_FIFO)) {
@@ -200,6 +216,8 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask;
+ status_mask = port->read_status_mask;
+ status_mask &= ~port->ignore_status_mask;
if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
return;
@@ -208,6 +226,9 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
u32 data;
char status = TTY_NORMAL;
+ if (is_rxbs_support)
+ rxbs_status = readl(port->membase + CDNS_UART_RXBS);
+
data = readl(port->membase + CDNS_UART_FIFO);
/* Non-NULL byte after BREAK is garbage (99%) */
@@ -217,21 +238,41 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
if (uart_handle_break(port))
continue;
}
+ if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) {
+ port->icount.brk++;
+ status = TTY_BREAK;
+ if (uart_handle_break(port))
+ continue;
+ }
if (uart_handle_sysrq_char(port, data))
continue;
port->icount.rx++;
- if (isrstatus & CDNS_UART_IXR_PARITY) {
- port->icount.parity++;
- status = TTY_PARITY;
- } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
- port->icount.frame++;
- status = TTY_FRAME;
- } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
- port->icount.overrun++;
+ if (is_rxbs_support) {
+ if ((rxbs_status & CDNS_UART_RXBS_PARITY)
+ && (status_mask & CDNS_UART_IXR_PARITY)) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ }
+ if ((rxbs_status & CDNS_UART_RXBS_FRAMING)
+ && (status_mask & CDNS_UART_IXR_PARITY)) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ }
+ } else {
+ if (isrstatus & CDNS_UART_IXR_PARITY) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ }
+ if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ }
}
+ if (isrstatus & CDNS_UART_IXR_OVERRUN)
+ port->icount.overrun++;
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
data, status);
@@ -736,10 +777,14 @@ static void cdns_uart_set_termios(struct uart_port *port,
*/
static int cdns_uart_startup(struct uart_port *port)
{
+ struct cdns_uart *cdns_uart = port->private_data;
+ bool is_brk_support;
int ret;
unsigned long flags;
unsigned int status = 0;
+ is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
+
spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX */
@@ -794,7 +839,11 @@ static int cdns_uart_startup(struct uart_port *port)
}
/* Set the Interrupt Registers with desired interrupts */
- writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
+ if (is_brk_support)
+ writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK,
+ port->membase + CDNS_UART_IER);
+ else
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
return 0;
}
@@ -1328,6 +1377,18 @@ static int cdns_uart_resume(struct device *device)
static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
cdns_uart_resume);
+static const struct cdns_platform_data zynqmp_uart_def = {
+ .quirks = CDNS_UART_RXBS_SUPPORT, };
+
+/* Match table for of_platform binding */
+static const struct of_device_id cdns_uart_of_match[] = {
+ { .compatible = "xlnx,xuartps", },
+ { .compatible = "cdns,uart-r1p8", },
+ { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
+
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@@ -1340,12 +1401,20 @@ static int cdns_uart_probe(struct platform_device *pdev)
struct uart_port *port;
struct resource *res;
struct cdns_uart *cdns_uart_data;
+ const struct of_device_id *match;
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL);
if (!cdns_uart_data)
return -ENOMEM;
+ match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
+ if (match && match->data) {
+ const struct cdns_platform_data *data = match->data;
+
+ cdns_uart_data->quirks = data->quirks;
+ }
+
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(cdns_uart_data->pclk)) {
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
@@ -1471,14 +1540,6 @@ static int cdns_uart_remove(struct platform_device *pdev)
return rc;
}
-/* Match table for of_platform binding */
-static const struct of_device_id cdns_uart_of_match[] = {
- { .compatible = "xlnx,xuartps", },
- { .compatible = "cdns,uart-r1p8", },
- {}
-};
-MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
-
static struct platform_driver cdns_uart_platform_driver = {
.probe = cdns_uart_probe,
.remove = cdns_uart_remove,
--
2.1.2
^ permalink raw reply related
* [PATCH v2 2/3] devicetree: bindings: uart: Add new compatible string for ZynqMP
From: Nava kishore Manne @ 2016-09-15 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473930931-1034-1-git-send-email-navam@xilinx.com>
From: Nava kishore Manne <nava.manne@xilinx.com>
Signed-off-by: Nava kishore Manne <navam@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
[stelford at cadence.com: cherry picked from
https://github.com/Xilinx/linux-xlnx commit
37b8a9780766422b2437f5166ddef3767bb60887]
Signed-off-by: Scott Telford <stelford@cadence.com>
---
Changes for v2:
-None
Documentation/devicetree/bindings/serial/cdns,uart.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.txt b/Documentation/devicetree/bindings/serial/cdns,uart.txt
index a3eb154..4fe7aae 100644
--- a/Documentation/devicetree/bindings/serial/cdns,uart.txt
+++ b/Documentation/devicetree/bindings/serial/cdns,uart.txt
@@ -1,7 +1,8 @@
Binding for Cadence UART Controller
Required properties:
-- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps"
+- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps" for Zynq and
+ "cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC uart controller.
- reg: Should contain UART controller registers location and length.
- interrupts: Should contain UART controller interrupts.
- clocks: Must contain phandles to the UART clocks
--
2.1.2
^ permalink raw reply related
* [PATCH v2 3/3] tty: serial: xuartps: Wait for rx and tx reset done status
From: Nava kishore Manne @ 2016-09-15 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473930931-1034-1-git-send-email-navam@xilinx.com>
After issuing the reset, driver is not checking the rx and tx reset
done status. So, modified driver to wait for the reset done status.
Signed-off-by: Nava kishore Manne <navam@xilinx.com>
---
Changes for v2:
-Added New patch
drivers/tty/serial/xilinx_uartps.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 527526e..b69dea3 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -694,6 +694,10 @@ static void cdns_uart_set_termios(struct uart_port *port,
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
writel(ctrl_reg, port->membase + CDNS_UART_CR);
+ while (readl(port->membase + CDNS_UART_CR) &
+ (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
+ cpu_relax();
+
/*
* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver.
@@ -797,6 +801,10 @@ static int cdns_uart_startup(struct uart_port *port)
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
port->membase + CDNS_UART_CR);
+ while (readl(port->membase + CDNS_UART_CR) &
+ (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
+ cpu_relax();
+
/*
* Clear the RX disable bit and then set the RX enable bit to enable
* the receiver.
--
2.1.2
^ permalink raw reply related
* [PATCH] ARM: s3c24xx: Add dma_slave_map for s3c2440 devices
From: Arnd Bergmann @ 2016-09-15 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473877775-7537-1-git-send-email-sam.van.den.berge@telenet.be>
On Wednesday, September 14, 2016 8:29:35 PM CEST Sam Van Den Berge wrote:
> This patch updates the s3c24xx dma driver to be able to pass a
> dma_slave_map array via the platform data. This is needed to
> be able to use the new, simpler dmaengine API [1].
> I used the virtual DMA channels as a parameter for the dma_filter
> function. By doing that, I could reuse the existing filter function in
> drivers/dma/s3c24xx-dma.c.
>
> I have tested this on my mini2440 board with the audio driver.
> (I first applied the audio fixes from Sylwester Nawrocki [2])
> According to my observations, dma_request_slave_channel in the
> function dmaengine_pcm_new in the file
> sound/soc/soc-generic-dmaengine-pcm.c now returns a valid DMA channel
> whereas before no DMA channel was returned at that point.
>
> Entries for DMACH_XD0, DMACH_XD1 and DMACH_TIMER are missing because I
> don't realy know which driver to use for these.
>
> [1]
> http://lists.infradead.org/pipermail/linux-arm-kernel/2015-December/393635.html
> [2] http://www.spinics.net/lists/arm-kernel/msg521918.html
>
> Signed-off-by: Sam Van Den Berge <sam.van.den.berge@telenet.be>
>
Thanks for doing this, once this is merged we should be able to
change all the drivers that currently use this DMA support
(I think just spi, mmc and audio) over to the new dma_request_chan
function.
The logical follow-up after that would be to unify the slave_map
with the s3c24xx_dma_channel tables, along the lines of
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -475,28 +475,14 @@ static struct resource s3c2443_dma_resource[] = {
[6] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA5),
};
-static struct s3c24xx_dma_channel s3c2443_dma_channels[DMACH_MAX] = {
+static struct dma_slave_map s3c2443_dma_channels[] = {
- [DMACH_XD0] = { S3C24XX_DMA_AHB, true, 17 },
- [DMACH_XD1] = { S3C24XX_DMA_AHB, true, 18 },
- [DMACH_SDI] = { S3C24XX_DMA_APB, false, 10 },
- [DMACH_SPI0_RX] = { S3C24XX_DMA_APB, true, 1 },
- [DMACH_SPI0_TX] = { S3C24XX_DMA_APB, true, 0 },
- [DMACH_SPI1_RX] = { S3C24XX_DMA_APB, true, 3 },
- [DMACH_SPI1_TX] = { S3C24XX_DMA_APB, true, 2 },
+ { "xd0", "data", S3C_DMA_SLAVE(S3C24XX_DMA_AHB, true, 17) },
+ { "xd1", "data", S3C_DMA_SLAVE(S3C24XX_DMA_AHB, true, 18) },
+ { "3c2440-sdi", "data", S3C_DMA_SLAVE(S3C24XX_DMA_APB, false, 10) },
+ { "s3c2410-spi.0", "rx", S3C_DMA_SLAVE(S3C24XX_DMA_APB, true, 1) },
+ { "s3c2410-spi.0", "tx", S3C_DMA_SLAVE(S3C24XX_DMA_APB, true, 0) },
+ { "s3c2410-spi.1", "rx", S3C_DMA_SLAVE(S3C24XX_DMA_APB, true, 3) },
+ { "s3c2410-spi.1", "tx", S3C_DMA_SLAVE(S3C24XX_DMA_APB, true, 2) },
...
};
static struct s3c24xx_dma_platdata s3c2443_dma_platdata = {
For this patch:
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox