Thread (15 messages) 15 messages, 2 authors, 2015-07-27

[PATCH v2 5/5] mtd: atmel-quadspi: add driver for Atmel QSPI controller

From: marex@denx.de (Marek Vasut)
Date: 2015-07-27 11:07:55
Also in: linux-devicetree, linux-spi, lkml

On Monday, July 27, 2015 at 10:41:37 AM, Cyrille Pitchen wrote:
Hi Marek,

Le 22/07/2015 15:50, Marek Vasut a ?crit :
quoted
On Wednesday, July 22, 2015 at 03:17:10 PM, Cyrille Pitchen wrote:
quoted
This driver add support to the new Atmel QSPI controller embedded into
sama5d2x SoCs. It expects a NOR memory to be connected to the QSPI
controller.

Signed-off-by: Cyrille Pitchen <redacted>
---
[...]
quoted
+/* QSPI register offsets */
+#define QSPI_CR		0x0000	/* Control Register */
+#define QSPI_MR		0x0004	/* Mode Register */
+#define QSPI_RD		0x0008	/* Receive Data Register */
+#define QSPI_TD		0x000c	/* Transmit Data Register */
+#define QSPI_SR		0x0010	/* Status Register */
+#define QSPI_IER	0x0014	/* Interrupt Enable Register */
+#define QSPI_IDR	0x0018	/* Interrupt Disable Register */
+#define QSPI_IMR	0x001c	/* Interrupt Mask Register */
+#define QSPI_SCR	0x0020	/* Serial Clock Register */
+
+#define QSPI_IAR	0x0030	/* Instruction Address Register */
+#define QSPI_ICR	0x0034	/* Instruction Code Register */
+#define QSPI_IFR	0x0038	/* Instruction Frame Register */
+
+#define QSPI_SMR	0x0040	/* Scrambling Mode Register */
+#define QSPI_SKR	0x0044	/* Scrambling Key Register */
+
+#define QSPI_WPMR	0x00E4	/* Write Protection Mode Register */
+#define QSPI_WPSR	0x00E8	/* Write Protection Status Register */
+
+#define QSPI_VERSION	0x00FC	/* Version Register */
+
+/* Bitfields in QSPI_CR (Control Register) */
+#define QSPI_CR_QSPIEN_OFFSET		0
+#define QSPI_CR_QSPIEN_SIZE		1
+#define QSPI_CR_QSPIDIS_OFFSET		1
+#define QSPI_CR_QSPIDIS_SIZE		1
+#define QSPI_CR_SWRST_OFFSET		7
+#define QSPI_CR_SWRST_SIZE		1
+#define QSPI_CR_LASTXFER_OFFSET		24
+#define QSPI_CR_LASTXFER_SIZE		1
+
+/* Bitfields in QSPI_MR (Mode Register) */
+#define QSPI_MR_SSM_OFFSET		0
+#define QSPI_MR_SSM_SIZE		1
+#define QSPI_MR_LLB_OFFSET		1
+#define QSPI_MR_LLB_SIZE		1
+#define QSPI_MR_WDRBT_OFFSET		2
+#define QSPI_MR_WDRBT_SIZE		1
+#define QPSI_MR_SMRM_OFFSET		3
+#define QSPI_MR_SMRM_SIZE		1
+#define QSPI_MR_CSMODE_OFFSET		4
+#define QSPI_MR_CSMODE_SIZE		2
+#define QSPI_MR_NBBITS_OFFSET		8
+#define QSPI_MR_NBBITS_SIZE		4
+#define		QSPI_MR_NBBITS_8_BIT		0
+#define		QSPI_MR_NBBITS_9_BIT		1
+#define		QSPI_MR_NBBITS_10_BIT		2
+#define		QSPI_MR_NBBITS_11_BIT		3
+#define		QSPI_MR_NBBITS_12_BIT		4
+#define		QSPI_MR_NBBITS_13_BIT		5
+#define		QSPI_MR_NBBITS_14_BIT		6
+#define		QSPI_MR_NBBITS_15_BIT		7
+#define		QSPI_MR_NBBITS_16_BIT		8
You might want to turn this into something like:

#define QSPI_NR_NBBITS(n) ((n) - 8)
done in the next series
quoted
quoted
+#define QSPI_MR_DLYBCT_OFFSET		16
+#define QSPI_MR_DLYBCT_SIZE		8
+#define QSPI_MR_DLYCS_OFFSET		24
+#define QSPI_MR_DLYCS_SIZE		8
[...]
quoted
+/* Bitfields in QSPI_IFR (Instruction Frame Register) */
+#define QSPI_IFR_WIDTH_OFFSET		0
+#define QSPI_IFR_WIDTH_SIZE		3
+#define		QSPI_IFR_WIDTH_SINGLE_BIT_SPI		0
+#define		QSPI_IFR_WIDTH_DUAL_OUTPUT		1
+#define		QSPI_IFR_WIDTH_QUAD_OUTPUT		2
+#define		QSPI_IFR_WIDTH_DUAL_IO			3
+#define		QSPI_IFR_WIDTH_QUAD_IO			4
+#define		QSPI_IFR_WIDTH_DUAL_CMD			5
+#define		QSPI_IFR_WIDTH_QUAD_CMD			6
Please use #define[SPACE] instead of inconsistent #define[TAB]
done in the next series. I also use BIT and GENMASK macros as much as
possible to define the register bit fields.
quoted
[...]
quoted
+/* Bit manipulation macros */
+#define QSPI_BIT(name) \
+	(1 << QSPI_##name##_OFFSET)
+#define QSPI_BF(name, value) \
+	(((value) & ((1 << QSPI_##name##_SIZE) - 1)) << QSPI_##name##_OFFSET)
+#define QSPI_BFEXT(name, value) \
+	(((value) >> QSPI_##name##_OFFSET) & ((1 << QSPI_##name##_SIZE) - 1))
+#define QSPI_BFINS(name, value, old) \
+	(((old) & ~(((1 << QSPI_##name##_SIZE) - 1) << QSPI_##name##_OFFSET))
\ +	 | QSPI_BF(name, value))
+
+/* Register access macros */
+#define qspi_readl(port, reg) \
+	readl_relaxed((port)->regs + QSPI_##reg)
+#define qspi_writel(port, reg, value) \
+	writel_relaxed((value), (port)->regs + QSPI_##reg)
+
+#define qspi_readw(port, reg) \
+	readw_relaxed((port)->regs + QSPI_##reg)
+#define qspi_writew(port, reg, value) \
+	writew_relaxed((value), (port)->regs + QSPI_##reg)
+
+#define qspi_readb(port, reg) \
+	readb_relaxed((port)->regs + QSPI_##reg)
+#define qspi_writeb(port, reg, value) \
+	writeb_relaxed((value), (port)->regs + QSPI_##reg)
I cannot say I'd be very fond of those preprocessor concatenations. Can't
you do something about them? It's really hard to look for symbols which
are in fact result of this horrible macro voodoo .
I agree with you. I did it this way at first to make it consistent with
other Atmel drivers which use such macros but we tend to remove them
progressively as they prevent from using ctags for instance.
quoted
quoted
+struct atmel_qspi {
+	void __iomem		*regs;
+	void __iomem		*mem;
+	dma_addr_t		phys_addr;
+	struct dma_chan		*chan;
+	struct clk		*clk;
+	struct platform_device	*pdev;
+	u32			ifr_width;
+	u32			pending;
+
+	struct mtd_info		mtd;
+	struct spi_nor		nor;
+	u32			clk_rate;
+	struct completion	completion;
+
+#ifdef DEBUG
+	u8			last_instruction;
+#endif
+};
[...]
quoted
+#ifdef DEBUG
+static void atmel_qspi_debug_command(struct atmel_qspi *aq,
+				     const struct atmel_qspi_command *cmd)
+{
+	u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+	size_t len = 0;
+	int i;
+
+	if (cmd->enable.bits.instruction) {
+		if (aq->last_instruction == cmd->instruction)
+			return;
+		aq->last_instruction = cmd->instruction;
+	}
+
+	if (cmd->enable.bits.instruction)
+		cmd_buf[len++] = cmd->instruction;
+
+	for (i = cmd->enable.bits.address-1; i >= 0; --i)
+		cmd_buf[len++] = (cmd->address >> (i << 3)) & 0xff;
+
+	if (cmd->enable.bits.mode)
+		cmd_buf[len++] = cmd->mode;
+
+	if (cmd->enable.bits.dummy) {
+		int num = cmd->num_dummy_cycles;
+
+		switch (aq->ifr_width) {
+		case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
+		case QSPI_IFR_WIDTH_DUAL_OUTPUT:
+		case QSPI_IFR_WIDTH_QUAD_OUTPUT:
+			num >>= 3;
+			break;
+		case QSPI_IFR_WIDTH_DUAL_IO:
+		case QSPI_IFR_WIDTH_DUAL_CMD:
+			num >>= 2;
+			break;
+		case QSPI_IFR_WIDTH_QUAD_IO:
+		case QSPI_IFR_WIDTH_QUAD_CMD:
+			num >>= 1;
+			break;
+		default:
+			return;
+		}
+
+		for (i = 0; i < num; ++i)
+			cmd_buf[len++] = 0;
+	}
+
+	print_hex_dump(KERN_DEBUG, "qspi cmd: ", DUMP_PREFIX_NONE,
+		       32, 1, cmd_buf, len, false);
+
+#ifdef VERBOSE_DEBUG
The print_hex_dump() is already KERN_DEBUG, so I don't think there's any
need to introduce yet another preprocessor check here.
Indeed, there is only one debug level for printk() and print_hex_dump():
KERN_DEBUG. However I've used the DEBUG and VERBOSE_DEBUG macros to have
two levels of debug output. When the DEBUG macro is defined the driver
prints the QSPI command. When both the DEBUG and VERBOSE_DEBUG macro are
defined, the driver also prints the RX or TX data following the commands.
Depending on the command to debug, data can be usefull, as for the READ ID
command, or really annoying as for big Fast Read commands.

If it's fine with you, I'd rather keep these two debug levels.
I'm not the one to decide, but it does indeed make sense.

Thanks a lot for doing the cleanups !
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help