[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