Re: [PATCH linux dev-5.3 07/13] mtd: spi-nor: aspeed: Introduce segment operations
Andrew Jeffery
andrew at aj.id.au
Thu Sep 26 12:00:07 AEST 2019
On Wed, 25 Sep 2019, at 22:12, Cédric Le Goater wrote:
> AST2600 will use a different encoding for the addresses defined in the
> Segment Register.
>
> Signed-off-by: Cédric Le Goater <clg at kaod.org>
Reviewed-by: Andrew Jeffery <andrew at aj.id.au>
> ---
> drivers/mtd/spi-nor/aspeed-smc.c | 76 +++++++++++++++++++++++---------
> 1 file changed, 56 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
> index b3a128ada320..4e768092a965 100644
> --- a/drivers/mtd/spi-nor/aspeed-smc.c
> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
> @@ -32,6 +32,7 @@ enum aspeed_smc_flash_type {
> };
>
> struct aspeed_smc_chip;
> +struct aspeed_smc_controller;
>
> struct aspeed_smc_info {
> u32 maxsize; /* maximum size of chip window */
> @@ -43,12 +44,22 @@ struct aspeed_smc_info {
>
> void (*set_4b)(struct aspeed_smc_chip *chip);
> int (*optimize_read)(struct aspeed_smc_chip *chip, u32 max_freq);
> + u32 (*segment_start)(struct aspeed_smc_controller *controller, u32 reg);
> + u32 (*segment_end)(struct aspeed_smc_controller *controller, u32 reg);
> + u32 (*segment_reg)(struct aspeed_smc_controller *controller,
> + u32 start, u32 end);
> };
>
> static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip);
> static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
> static int aspeed_smc_optimize_read(struct aspeed_smc_chip *chip,
> u32 max_freq);
> +static u32 aspeed_smc_segment_start(
> + struct aspeed_smc_controller *controller, u32 reg);
> +static u32 aspeed_smc_segment_end(
> + struct aspeed_smc_controller *controller, u32 reg);
> +static u32 aspeed_smc_segment_reg(
> + struct aspeed_smc_controller *controller, u32 start, u32 end);
>
> static const struct aspeed_smc_info fmc_2400_info = {
> .maxsize = 64 * 1024 * 1024,
> @@ -59,6 +70,9 @@ static const struct aspeed_smc_info fmc_2400_info = {
> .timing = 0x94,
> .set_4b = aspeed_smc_chip_set_4b,
> .optimize_read = aspeed_smc_optimize_read,
> + .segment_start = aspeed_smc_segment_start,
> + .segment_end = aspeed_smc_segment_end,
> + .segment_reg = aspeed_smc_segment_reg,
> };
>
> static const struct aspeed_smc_info spi_2400_info = {
> @@ -70,6 +84,7 @@ static const struct aspeed_smc_info spi_2400_info = {
> .timing = 0x14,
> .set_4b = aspeed_smc_chip_set_4b_spi_2400,
> .optimize_read = aspeed_smc_optimize_read,
> + /* No segment registers */
> };
>
> static const struct aspeed_smc_info fmc_2500_info = {
> @@ -81,6 +96,9 @@ static const struct aspeed_smc_info fmc_2500_info = {
> .timing = 0x94,
> .set_4b = aspeed_smc_chip_set_4b,
> .optimize_read = aspeed_smc_optimize_read,
> + .segment_start = aspeed_smc_segment_start,
> + .segment_end = aspeed_smc_segment_end,
> + .segment_reg = aspeed_smc_segment_reg,
> };
>
> static const struct aspeed_smc_info spi_2500_info = {
> @@ -92,6 +110,9 @@ static const struct aspeed_smc_info spi_2500_info = {
> .timing = 0x94,
> .set_4b = aspeed_smc_chip_set_4b,
> .optimize_read = aspeed_smc_optimize_read,
> + .segment_start = aspeed_smc_segment_start,
> + .segment_end = aspeed_smc_segment_end,
> + .segment_reg = aspeed_smc_segment_reg,
> };
>
> enum aspeed_smc_ctl_reg_value {
> @@ -201,22 +222,33 @@ struct aspeed_smc_controller {
> (CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
> CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
>
> -/*
> - * 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 |
> - */
> #define SEGMENT_ADDR_REG0 0x30
> -#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
> -#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23)
> -#define SEGMENT_ADDR_VALUE(start, end) \
> - (((((start) >> 23) & 0xFF) << 16) | ((((end) >> 23) & 0xFF) << 24))
> #define SEGMENT_ADDR_REG(controller, cs) \
> ((controller)->regs + SEGMENT_ADDR_REG0 + (cs) * 4)
>
> +/*
> + * The Segment Registers of the AST2400 and AST2500 have a 8MB
> + * unit. The address range of a flash SPI slave is encoded with
> + * absolute addresses which should be part of the overall controller
> + * window.
> + */
> +static u32 aspeed_smc_segment_start(
> + struct aspeed_smc_controller *controller, u32 reg)
> +{
> + return ((reg >> 16) & 0xFF) << 23;
> +}
> +
> +static u32 aspeed_smc_segment_end(
> + struct aspeed_smc_controller *controller, u32 reg)
> +{
> + return ((reg >> 24) & 0xFF) << 23;
> +}
> +
> +static u32 aspeed_smc_segment_reg(
> + struct aspeed_smc_controller *controller, u32 start, u32 end)
> +{
> + return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24);
> +}
> /*
> * Switch to turn off read optimisation if needed
> */
> @@ -519,16 +551,19 @@ static void __iomem *aspeed_smc_chip_base(struct
> aspeed_smc_chip *chip,
> struct resource *res)
> {
> struct aspeed_smc_controller *controller = chip->controller;
> + const struct aspeed_smc_info *info = controller->info;
> u32 offset = 0;
> u32 reg;
>
> - if (controller->info->nce > 1) {
> + if (info->nce > 1) {
> reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));
>
> - if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
> + if (info->segment_start(controller, reg) >=
> + info->segment_end(controller, reg)) {
> return NULL;
> + }
>
> - offset = SEGMENT_ADDR_START(reg) - res->start;
> + offset = info->segment_start(controller, reg) - res->start;
> }
>
> return controller->ahb_base + offset;
> @@ -538,6 +573,7 @@ static u32 chip_set_segment(struct aspeed_smc_chip
> *chip, u32 cs, u32 start,
> u32 size)
> {
> struct aspeed_smc_controller *controller = chip->controller;
> + const struct aspeed_smc_info *info = controller->info;
> void __iomem *seg_reg;
> u32 seg_oldval, seg_newval, end;
> u32 ahb_base_phy = controller->ahb_base_phy;
> @@ -551,7 +587,7 @@ static u32 chip_set_segment(struct aspeed_smc_chip
> *chip, u32 cs, u32 start,
> * previous segment
> */
> if (!size)
> - size = SEGMENT_ADDR_END(seg_oldval) - start;
> + size = info->segment_end(controller, seg_oldval) - start;
>
> /*
> * The segment cannot exceed the maximum window size of the
> @@ -564,7 +600,7 @@ static u32 chip_set_segment(struct aspeed_smc_chip
> *chip, u32 cs, u32 start,
> }
>
> end = start + size;
> - seg_newval = SEGMENT_ADDR_VALUE(start, end);
> + seg_newval = info->segment_reg(controller, start, end);
> writel(seg_newval, seg_reg);
>
> /*
> @@ -575,8 +611,8 @@ static u32 chip_set_segment(struct aspeed_smc_chip
> *chip, u32 cs, u32 start,
> if (seg_newval != readl(seg_reg)) {
> dev_err(chip->nor.dev, "CE%d window invalid", cs);
> writel(seg_oldval, seg_reg);
> - start = SEGMENT_ADDR_START(seg_oldval);
> - end = SEGMENT_ADDR_END(seg_oldval);
> + start = info->segment_start(controller, seg_oldval);
> + end = info->segment_end(controller, seg_oldval);
> size = end - start;
> }
>
> @@ -639,7 +675,7 @@ static u32 aspeed_smc_chip_set_segment(struct
> aspeed_smc_chip *chip)
> if (chip->cs) {
> u32 prev = readl(SEGMENT_ADDR_REG(controller, chip->cs - 1));
>
> - start = SEGMENT_ADDR_END(prev);
> + start = controller->info->segment_end(controller, prev);
> } else {
> start = ahb_base_phy;
> }
> --
> 2.21.0
>
>
More information about the openbmc
mailing list