[PATCH linux dev-4.7 02/12] mtd: spi-nor: aspeed: Manage the segment address registers

Cédric Le Goater clg at kaod.org
Mon Oct 17 18:40:36 AEDT 2016


On 10/17/2016 07:13 AM, Joel Stanley wrote:
> On Fri, Oct 14, 2016 at 11:07 PM, Cédric Le Goater <clg at kaod.org> wrote:
>> From: Milton Miller <miltonm at us.ibm.com>
>>
>> This changes the aspeed mtd driver to use the segment address
>> registers from the driver, this eliminating a source of mismatch and
>> placing the kernel in control using its knowledge instead of relying
>> on hardware defaults or bootloaders to choose good values for the
>> windows based on the attached chips.
>>
>> The initial commit factors out discovering the current window in which
>> the flash module is mapped by the controller. The intent is to adjust
>> the windows to the required size of the attached flash.  Also planned
>> is to enable direct memory mapped access and dma access, at least for
>> read accesses when the flash size is supported by the hardware.
>>
>> The spi-nor layer already trusts its database of jedec ids over any
>> information in the device tree, this continues that philosophy
>> by using the knowledge to optimize the programming of the hardware.
>> The device tree may be used in the future to limit the choices,
>> for example specifying a max clock rate based on board wiring.
>>
>> This does not have any locking around sanitizing the segments
>> or copying the new addresses back to the per-chip base address.
>> In the present code registers are updated before the devices
>> are probed.
>>
>> We may want to cache the offsets in the per-chip structure to
>> when we support DMA.
>>
>> Signed-off-by: Milton Miller <miltonm at us.ibm.com>
>> [clg : removed the calculation on the segment registers to check
>>        overlaps and kept only the reading of the segment base address.
>>        It needs more work ]
>> Signed-off-by: Cédric Le Goater <clg at kaod.org>
>> ---
>>  drivers/mtd/spi-nor/aspeed-smc.c | 58 +++++++++++++++++++++++++++++++---------
>>  1 file changed, 46 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
>> index e8744aef5fdc..a47eecfdfda2 100644
>> --- a/drivers/mtd/spi-nor/aspeed-smc.c
>> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
>> @@ -136,6 +136,7 @@ enum smc_flash_type {
>>  };
>>
>>  struct aspeed_smc_info {
>> +       u32 maxsize;            /* maximum size of 1 chip window */
> 
> It doesn't look like you use maxsize at all.

Indeed. I removed its use in this patch but I will be useful for 
the overall check at the end. We could have a window size smaller 
than the sum of the size of the chip.

I am still uncertain how these flash windows work as I could 
read/write the 128MB chip on the witherspoon with a 8MB window ...
So I don't want to do too much in this area.

C. 

> 
> 
>>         u8 nce;                 /* number of chip enables */
>>         u8 maxwidth;            /* max width of spi bus */
>>         bool hasdma;            /* has dma engine */
>> @@ -147,6 +148,7 @@ struct aspeed_smc_info {
>>  };
>>
>>  static struct aspeed_smc_info fmc_2400_info = {
>> +       .maxsize = 64 * 1024 * 1024,
>>         .nce = 5,
>>         .maxwidth = 4,
>>         .hasdma = true,
>> @@ -158,6 +160,7 @@ static struct aspeed_smc_info fmc_2400_info = {
>>  };
>>
>>  static struct aspeed_smc_info smc_2400_info = {
>> +       .maxsize = 64 * 1024 * 1024,
>>         .nce = 1,
>>         .maxwidth = 2,
>>         .hasdma = false,
>> @@ -169,6 +172,7 @@ static struct aspeed_smc_info smc_2400_info = {
>>  };
>>
>>  static struct aspeed_smc_info fmc_2500_info = {
>> +       .maxsize = 256 * 1024 * 1024,
>>         .nce = 3,
>>         .maxwidth = 2,
>>         .hasdma = true,
>> @@ -180,6 +184,7 @@ static struct aspeed_smc_info fmc_2500_info = {
>>  };
>>
>>  static struct aspeed_smc_info smc_2500_info = {
>> +       .maxsize = 128 * 1024 * 1024,
>>         .nce = 2,
>>         .maxwidth = 2,
>>         .hasdma = false,
>> @@ -212,11 +217,17 @@ struct aspeed_smc_controller {
>>         struct mutex mutex;                     /* controller access mutex */
>>         const struct aspeed_smc_info *info;     /* type info of controller */
>>         void __iomem *regs;                     /* controller registers */
>> +       void __iomem *windows;                  /* per-chip windows resource */
>>         struct aspeed_smc_per_chip *chips[0];   /* pointers to attached chips */
>>  };
>>
>>  #define TYPE_SETTING_REG 0x0
>>
>> +#define LOG_8MB (23)   /* log(2)(8 * 1024 * 1024) */
>> +#define SEGMENT_ADDR_REG0 0x30
>> +#define         SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << LOG_8MB)
>> +#define         SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << LOG_8MB)
>> +
>>  #define CONTROL_SPI_AAF_MODE BIT(31)
>>  #define CONTROL_SPI_IO_MODE_MASK GENMASK(30, 28)
>>  #define CONTROL_SPI_IO_DUAL_DATA BIT(29)
>> @@ -403,13 +414,30 @@ of_platform_device_create_or_find(struct device_node *child,
>>         return cdev;
>>  }
>>
>> +static void __iomem *window_start(struct aspeed_smc_controller *controller,
>> +                                 struct resource *r, unsigned int n)
>> +{
>> +       u32 offset = 0;
>> +       u32 reg;
>> +
>> +       if (controller->info->nce > 1) {
>> +               reg = readl(controller->regs + SEGMENT_ADDR_REG0 + n * 4);
>> +
>> +               if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
>> +                       return NULL;
>> +
>> +               offset = SEGMENT_ADDR_START(reg) - r->start;
>> +       }
>> +
>> +       return controller->windows + offset;
>> +}
>> +
>>  static int aspeed_smc_probe(struct platform_device *dev)
>>  {
>>         struct aspeed_smc_controller *controller;
>>         const struct of_device_id *match;
>>         const struct aspeed_smc_info *info;
>>         struct resource *r;
>> -       void __iomem *regs;
>>         struct device_node *child;
>>         int err = 0;
>>         unsigned int n;
>> @@ -418,19 +446,24 @@ static int aspeed_smc_probe(struct platform_device *dev)
>>         if (!match || !match->data)
>>                 return -ENODEV;
>>         info = match->data;
>> -       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
>> -       regs = devm_ioremap_resource(&dev->dev, r);
>> -       if (IS_ERR(regs))
>> -               return PTR_ERR(regs);
>>
>>         controller = devm_kzalloc(&dev->dev, sizeof(*controller) +
>>                 info->nce * sizeof(controller->chips[0]), GFP_KERNEL);
>>         if (!controller)
>>                 return -ENOMEM;
>> -       platform_set_drvdata(dev, controller);
>> -       controller->regs = regs;
>>         controller->info = info;
>>         mutex_init(&controller->mutex);
>> +       platform_set_drvdata(dev, controller);
>> +
>> +       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
>> +       controller->regs = devm_ioremap_resource(&dev->dev, r);
>> +       if (IS_ERR(controller->regs))
>> +               return PTR_ERR(controller->regs);
>> +
>> +       r = platform_get_resource(dev, IORESOURCE_MEM, 1);
>> +       controller->windows = devm_ioremap_resource(&dev->dev, r);
>> +       if (IS_ERR(controller->windows))
>> +               return PTR_ERR(controller->windows);
>>
>>         /* The pinmux or bootloader will disable legacy mode. */
>>
>> @@ -476,17 +509,18 @@ static int aspeed_smc_probe(struct platform_device *dev)
>>                 if (!chip)
>>                         continue;
>>
>> -               r = platform_get_resource(dev, IORESOURCE_MEM, n + 1);
>> -               chip->base = devm_ioremap_resource(&dev->dev, r);
>> -               if (!chip->base)
>> -                       continue;
>> -
>>                 chip->controller = controller;
>>                 chip->ctl = controller->regs + info->ctl0 + n * 4;
>>
>>                 /* The device tree said the chip is spi. */
>>                 chip->type = smc_type_spi;
>>
>> +               chip->base = window_start(controller, r, n);
>> +               if (!chip->base) {
>> +                       dev_warn(&cdev->dev, "CE segment window closed.\n");
>> +                       continue;
>> +               }
>> +
>>                 /*
>>                  * Always turn on the write enable bit in the type and settings
>>                  * or flash configuration register to allow opcodes to be sent
>> --
>> 2.7.4
>>



More information about the openbmc mailing list