[PATCH linux dev-4.7 02/12] mtd: spi-nor: aspeed: Manage the segment address registers
Joel Stanley
joel at jms.id.au
Mon Oct 17 16:13:14 AEDT 2016
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.
> 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