[PATCH v3 1/5] mtd: spi-nor: add memory controllers for the Aspeed AST2500 SoC

Cédric Le Goater clg at kaod.org
Sat Dec 10 09:34:32 PST 2016


Hello, 

On 12/10/2016 05:01 AM, Marek Vasut wrote:
> On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
> 
> [...]
> 
> 
>> +static int aspeed_smc_read_from_ahb(void *buf, const void __iomem *src,
>> +				    size_t len)
>> +{
>> +	if (IS_ALIGNED((u32)src, sizeof(u32)) &&
>> +	    IS_ALIGNED((u32)buf, sizeof(u32)) &&
>> +	    IS_ALIGNED(len, sizeof(u32))) {
> 
> Did you try compiling this on any 64bit system ?

I cross compile the kernel on a 64bit host and then upload on the
target. What kind of problem are you forseeing ? 

> 
>> +		while (len > 3) {
>> +			*(u32 *)buf = readl(src);
> 
> ioread32_rep() to avoid open-coding the loop .

ok.

>> +			buf += 4;
>> +			src += 4;
>> +			len -= 4;
>> +		}
>> +	}
>> +
>> +	while (len--) {
>> +		*(u8 *)buf = readb(src);
>> +		buf += 1;
>> +		src += 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int aspeed_smc_write_to_ahb(void __iomem *dst, const void *buf,
>> +				   size_t len)
>> +{
>> +	if (IS_ALIGNED((u32)dst, sizeof(u32)) &&
>> +	    IS_ALIGNED((u32)buf, sizeof(u32)) &&
>> +	    IS_ALIGNED(len, sizeof(u32))) {
>> +		while (len > 3) {
>> +			u32 val = *(u32 *)buf;
>> +
>> +			writel(val, dst);
> 
> iowrite32_rep()
> 
>> +			buf += 4;
>> +			dst += 4;
>> +			len -= 4;
>> +		}
>> +	}
>> +
>> +	while (len--) {
>> +		u8 val = *(u8 *)buf;
>> +
>> +		writeb(val, dst);
>> +		buf += 1;
>> +		dst += 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +/*
>> + * The driver only support SPI flash
>> + */
>> +enum aspeed_smc_flash_type {
>> +	smc_type_nor  = 0,
>> +	smc_type_nand = 1,
>> +	smc_type_spi  = 2,
>> +};
>> +
>> +struct aspeed_smc_chip;
>> +
>> +struct aspeed_smc_info {
>> +	u32 maxsize;		/* maximum size of chip window */
>> +	u8 nce;			/* number of chip enables */
>> +	bool hastype;		/* flash type field exists in config reg */
>> +	u8 we0;			/* shift for write enable bit for CE0 */
>> +	u8 ctl0;		/* offset in regs of ctl for CE0 */
>> +
>> +	void (*set_4b)(struct aspeed_smc_chip *chip);
>> +};
> 
> Move all the structs to the beginning of the driver please.

ok.

> 
>> +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
>> +
>> +static const struct aspeed_smc_info fmc_2500_info = {
>> +	.maxsize = 256 * 1024 * 1024,
>> +	.nce = 3,
>> +	.hastype = true,
>> +	.we0 = 16,
>> +	.ctl0 = 0x10,
>> +	.set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +static const struct aspeed_smc_info spi_2500_info = {
>> +	.maxsize = 128 * 1024 * 1024,
>> +	.nce = 2,
>> +	.hastype = false,
>> +	.we0 = 16,
>> +	.ctl0 = 0x10,
>> +	.set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +enum aspeed_smc_ctl_reg_value {
>> +	smc_base,		/* base value without mode for other commands */
>> +	smc_read,		/* command reg for (maybe fast) reads */
>> +	smc_write,		/* command reg for writes */
>> +	smc_max,
>> +};
> 
> [...]
> 
>> +#define CONTROL_CE_STOP_ACTIVE_CONTROL	BIT(2)
>> +#define CONTROL_COMMAND_MODE_MASK	GENMASK(1, 0)
>> +#define CONTROL_COMMAND_MODE_NORMAL	(0)
>> +#define CONTROL_COMMAND_MODE_FREAD	(1)
>> +#define CONTROL_COMMAND_MODE_WRITE	(2)
>> +#define CONTROL_COMMAND_MODE_USER	(3)
> 
> Drop the parenthesis around constants :)

yeah

>> +#define CONTROL_KEEP_MASK						\
>> +	(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
>> +	 CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK |		\
>> +	 CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
>> +
>> +/*
>> + * Segment Address Registers. Start and end addresses are encoded
>> + * using 8MB units
>> + */
>> +#define SEGMENT_ADDR_REG0		0x30
>> +#define SEGMENT_ADDR_START(_r)		((((_r) >> 16) & 0xFF) << 23)
> 
> is that ((r) & 0xff0000) << 7 ?
> 
>> +#define SEGMENT_ADDR_END(_r)		((((_r) >> 24) & 0xFF) << 23)
> 
> ((r) & 0xff000000) >> 1 ?

yes. 

I rather keep the initial macros though, which I found easier to 
understand.

The Segment Register uses a 8MB unit to encode the start address
and the end address of the mapping window of a flash SPI slave :

        | byte 1 | byte 2 | byte 3 | byte 4 |
        +--------+--------+--------+--------+
        |  end   |  start |   0    |   0    |



>> +static inline u32 aspeed_smc_chip_write_bit(struct aspeed_smc_chip *chip)
>> +{
>> +	return BIT(chip->controller->info->we0 + chip->cs);
>> +}
> 
> [...]
> 
>> +static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
>> +				      struct resource *res)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	const struct aspeed_smc_info *info = controller->info;
>> +	u32 reg, base_reg;
>> +
>> +	/*
>> +	 * Always turn on the write enable bit to allow opcodes to be
>> +	 * sent in user mode.
>> +	 */
>> +	aspeed_smc_chip_enable_write(chip);
>> +
>> +	/* The driver only supports SPI type flash */
>> +	if (info->hastype)
>> +		aspeed_smc_chip_set_type(chip, smc_type_spi);
>> +
>> +	/*
>> +	 * Configure chip base address in memory
>> +	 */
>> +	chip->ahb_base = aspeed_smc_chip_base(chip, res);
>> +	if (!chip->ahb_base) {
>> +		dev_warn(chip->nor.dev, "CE segment window closed.\n");
>> +		return -1;
> 
> return -EINVAL ? Check whether you always use errno.h macros in returns.

ah yes. I missed that one.

> 
>> +	}
>> +
>> +	/*
>> +	 * Get value of the inherited control register. U-Boot usually
>> +	 * does some timing calibration on the FMC chip, so it's good
>> +	 * to keep them. In the future, we should handle calibration
>> +	 * from Linux.
>> +	 */
>> +	reg = readl(chip->ctl);
>> +	dev_dbg(controller->dev, "control register: %08x\n", reg);
>> +
>> +	base_reg = reg & CONTROL_KEEP_MASK;
>> +	if (base_reg != reg) {
>> +		dev_info(controller->dev,
>> +			 "control register changed to: %08x\n",
>> +			 base_reg);
>> +	}
>> +	chip->ctl_val[smc_base] = base_reg;
> 
> [...]
> 
> Mostly minor nits, looks nice otherwise, thanks :)


Thanks for the review,

C.




More information about the linux-mtd mailing list