Unverified Commit fe04716e authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'memory-controller-drv-6.2-2' of...

Merge tag 'memory-controller-drv-6.2-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers

Memory controller drivers for v6.2, part two

1. ARM PL353: document PL354 in bindings.
2. TI/OMAP GPMC: allow setting wait-pin polarity.

* tag 'memory-controller-drv-6.2-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: omap-gpmc: fix coverity issue "Control flow issues"
  dt-bindings: memory-controllers: ti,gpmc: add wait-pin polarity
  memory: omap-gpmc: wait pin additions
  MAINTAINERS: arm,pl353-smc: correct dt-binding path
  dt-bindings: memory-controllers: arm,pl353-smc: Extend to support 'arm,pl354' SMC

Link: https://lore.kernel.org/r/20221116093509.19657-1-krzysztof.kozlowski@linaro.org


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 26a12002 8dd7e4af
Loading
Loading
Loading
Loading
+53 −27
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/arm,pl353-smc.yaml#
$id: http://devicetree.org/schemas/memory-controllers/arm,pl35x-smc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: ARM PL353 Static Memory Controller (SMC) device-tree bindings
title: Arm PL35x Series Static Memory Controller (SMC)

maintainers:
  - Miquel Raynal <miquel.raynal@bootlin.com>
  - Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>

description:
  The PL353 Static Memory Controller is a bus where you can connect two kinds
description: |
  The PL35x Static Memory Controller is a bus where you can connect two kinds
  of memory interfaces, which are NAND and memory mapped interfaces (such as
  SRAM or NOR).
  SRAM or NOR) depending on the specific configuration.

  The TRM is available here:
  https://documentation-service.arm.com/static/5e8e2524fd977155116a58aa

# We need a select here so we don't match all nodes with 'arm,primecell'
select:
  properties:
    compatible:
      contains:
        const: arm,pl353-smc-r2p1
        enum:
          - arm,pl353-smc-r2p1
          - arm,pl354
  required:
    - compatible

@@ -30,7 +35,9 @@ properties:

  compatible:
    items:
      - const: arm,pl353-smc-r2p1
      - enum:
          - arm,pl353-smc-r2p1
          - arm,pl354
      - const: arm,primecell

  "#address-cells":
@@ -46,30 +53,25 @@ properties:
          The three chip select regions are defined in 'ranges'.

  clocks:
    items:
      - description: clock for the memory device bus
      - description: main clock of the SMC
    minItems: 1
    maxItems: 2

  clock-names:
    items:
      - const: memclk
      - const: apb_pclk
    minItems: 1
    maxItems: 2

  ranges:
    minItems: 1
    description: |
      Memory bus areas for interacting with the devices. Reflects
      the memory layout with four integer values following:
      <cs-number> 0 <offset> <size>
    items:
      - description: NAND bank 0
      - description: NOR/SRAM bank 0
      - description: NOR/SRAM bank 1
    maxItems: 8

  interrupts: true
  interrupts:
    minItems: 1
    items:
      - description: Combined or Memory interface 0 IRQ
      - description: Memory interface 1 IRQ

patternProperties:
  "@[0-3],[a-f0-9]+$":
  "@[0-7],[a-f0-9]+$":
    type: object
    description: |
      The child device node represents the controller connected to the SMC
@@ -87,7 +89,7 @@ patternProperties:
              - description: |
                  Chip-select ID, as in the parent range property.
                minimum: 0
                maximum: 2
                maximum: 7
              - description: |
                  Offset of the memory region requested by the device.
              - description: |
@@ -102,12 +104,36 @@ required:
  - reg
  - clock-names
  - clocks
  - "#address-cells"
  - "#size-cells"
  - ranges

additionalProperties: false

allOf:
  - if:
      properties:
        compatible:
          contains:
            const: arm,pl354
    then:
      properties:
        clocks:
          # According to TRM, really should be 3 clocks
          maxItems: 1

        clock-names:
          const: apb_pclk

    else:
      properties:
        clocks:
          items:
            - description: clock for the memory device bus
            - description: main clock of the SMC

        clock-names:
          items:
            - const: memclk
            - const: apb_pclk

examples:
  - |
    smcc: memory-controller@e000e000 {
+7 −0
Original line number Diff line number Diff line
@@ -230,6 +230,13 @@ properties:
      Wait-pin used by client. Must be less than "gpmc,num-waitpins".
    $ref: /schemas/types.yaml#/definitions/uint32

  ti,wait-pin-polarity:
    description: |
      Set the desired polarity for the selected wait pin.
      0 for active low, 1 for active high.
    $ref: /schemas/types.yaml#/definitions/uint32
    enum: [0, 1]

  gpmc,wait-on-read:
    description: Enables wait monitoring on reads.
    type: boolean
+1 −1
Original line number Diff line number Diff line
@@ -1685,7 +1685,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com>
M:	Naga Sureshkumar Relli <nagasure@xilinx.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained
F:	Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
F:	Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
F:	drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER
+109 −13
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@
#define GPMC_CONFIG_DEV_SIZE	0x00000002
#define GPMC_CONFIG_DEV_TYPE	0x00000003

#define GPMC_CONFIG_WAITPINPOLARITY(pin)	(BIT(pin) << 8)
#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
@@ -229,6 +230,12 @@ struct omap3_gpmc_regs {
	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
};

struct gpmc_waitpin {
	u32 pin;
	u32 polarity;
	struct gpio_desc *desc;
};

struct gpmc_device {
	struct device *dev;
	int irq;
@@ -236,6 +243,7 @@ struct gpmc_device {
	struct gpio_chip gpio_chip;
	struct notifier_block nb;
	struct omap3_gpmc_regs context;
	struct gpmc_waitpin *waitpins;
	int nirqs;
	unsigned int is_suspended:1;
	struct resource *data;
@@ -1035,6 +1043,62 @@ void gpmc_cs_free(int cs)
}
EXPORT_SYMBOL(gpmc_cs_free);

static bool gpmc_is_valid_waitpin(u32 waitpin)
{
	return waitpin < gpmc_nr_waitpins;
}

static int gpmc_alloc_waitpin(struct gpmc_device *gpmc,
			      struct gpmc_settings *p)
{
	int ret;
	struct gpmc_waitpin *waitpin;
	struct gpio_desc *waitpin_desc;

	if (!gpmc_is_valid_waitpin(p->wait_pin))
		return -EINVAL;

	waitpin = &gpmc->waitpins[p->wait_pin];

	if (!waitpin->desc) {
		/* Reserve the GPIO for wait pin usage.
		 * GPIO polarity doesn't matter here. Wait pin polarity
		 * is set in GPMC_CONFIG register.
		 */
		waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
							 p->wait_pin, "WAITPIN",
							 GPIO_ACTIVE_HIGH,
							 GPIOD_IN);

		ret = PTR_ERR(waitpin_desc);
		if (IS_ERR(waitpin_desc) && ret != -EBUSY)
			return ret;

		/* New wait pin */
		waitpin->desc = waitpin_desc;
		waitpin->pin = p->wait_pin;
		waitpin->polarity = p->wait_pin_polarity;
	} else {
		/* Shared wait pin */
		if (p->wait_pin_polarity != waitpin->polarity ||
		    p->wait_pin != waitpin->pin) {
			dev_err(gpmc->dev,
				"shared-wait-pin: invalid configuration\n");
			return -EINVAL;
		}
		dev_info(gpmc->dev, "shared wait-pin: %d\n", waitpin->pin);
	}

	return 0;
}

static void gpmc_free_waitpin(struct gpmc_device *gpmc,
			      int wait_pin)
{
	if (gpmc_is_valid_waitpin(wait_pin))
		gpiochip_free_own_desc(gpmc->waitpins[wait_pin].desc);
}

/**
 * gpmc_configure - write request to configure gpmc
 * @cmd: command type
@@ -1886,6 +1950,17 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)

	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);

	if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_INVALID) {
		config1 = gpmc_read_reg(GPMC_CONFIG);

		if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_LOW)
			config1 &= ~GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);
		else if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_HIGH)
			config1 |= GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);

		gpmc_write_reg(GPMC_CONFIG, config1);
	}

	return 0;
}

@@ -1975,7 +2050,25 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
				__func__);
	}

	p->wait_pin = GPMC_WAITPIN_INVALID;
	p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;

	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
		if (!gpmc_is_valid_waitpin(p->wait_pin)) {
			pr_err("%s: Invalid wait-pin (%d)\n", __func__, p->wait_pin);
			p->wait_pin = GPMC_WAITPIN_INVALID;
		}

		if (!of_property_read_u32(np, "ti,wait-pin-polarity",
					  &p->wait_pin_polarity)) {
			if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_HIGH &&
			    p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_LOW) {
				pr_err("%s: Invalid wait-pin-polarity (%d)\n",
				       __func__, p->wait_pin_polarity);
				p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;
				}
		}

		p->wait_on_read = of_property_read_bool(np,
							"gpmc,wait-on-read");
		p->wait_on_write = of_property_read_bool(np,
@@ -2080,7 +2173,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
	const char *name;
	int ret, cs;
	u32 val;
	struct gpio_desc *waitpin_desc = NULL;
	struct gpmc_device *gpmc = platform_get_drvdata(pdev);

	if (of_property_read_u32(child, "reg", &cs) < 0) {
@@ -2208,18 +2300,10 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,

	/* Reserve wait pin if it is required and valid */
	if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
		unsigned int wait_pin = gpmc_s.wait_pin;

		waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
							 wait_pin, "WAITPIN",
							 GPIO_ACTIVE_HIGH,
							 GPIOD_IN);
		if (IS_ERR(waitpin_desc)) {
			dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
			ret = PTR_ERR(waitpin_desc);
		ret = gpmc_alloc_waitpin(gpmc, &gpmc_s);
		if (ret < 0)
			goto err;
	}
	}

	gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");

@@ -2260,7 +2344,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
	ret = -ENODEV;

err_cs:
	gpiochip_free_own_desc(waitpin_desc);
	gpmc_free_waitpin(gpmc, gpmc_s.wait_pin);
err:
	gpmc_cs_free(cs);

@@ -2489,7 +2573,7 @@ static int omap_gpmc_context_notifier(struct notifier_block *nb,

static int gpmc_probe(struct platform_device *pdev)
{
	int rc;
	int rc, i;
	u32 l;
	struct resource *res;
	struct gpmc_device *gpmc;
@@ -2545,6 +2629,15 @@ static int gpmc_probe(struct platform_device *pdev)
		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
	}

	gpmc->waitpins = devm_kzalloc(&pdev->dev,
				      gpmc_nr_waitpins * sizeof(struct gpmc_waitpin),
				      GFP_KERNEL);
	if (!gpmc->waitpins)
		return -ENOMEM;

	for (i = 0; i < gpmc_nr_waitpins; i++)
		gpmc->waitpins[i].pin = GPMC_WAITPIN_INVALID;

	pm_runtime_enable(&pdev->dev);
	pm_runtime_get_sync(&pdev->dev);

@@ -2598,9 +2691,12 @@ static int gpmc_probe(struct platform_device *pdev)

static int gpmc_remove(struct platform_device *pdev)
{
	int i;
	struct gpmc_device *gpmc = platform_get_drvdata(pdev);

	cpu_pm_unregister_notifier(&gpmc->nb);
	for (i = 0; i < gpmc_nr_waitpins; i++)
		gpmc_free_waitpin(gpmc, i);
	gpmc_free_irq(gpmc);
	gpmc_mem_exit();
	pm_runtime_put_sync(&pdev->dev);
+8 −0
Original line number Diff line number Diff line
@@ -136,6 +136,13 @@ struct gpmc_device_timings {
#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
#define GPMC_MUX_AD			2	/* Addr-Data multiplex */

/* Wait pin polarity values */
#define GPMC_WAITPINPOLARITY_INVALID UINT_MAX
#define GPMC_WAITPINPOLARITY_ACTIVE_LOW 0
#define GPMC_WAITPINPOLARITY_ACTIVE_HIGH 1

#define GPMC_WAITPIN_INVALID UINT_MAX

struct gpmc_settings {
	bool burst_wrap;	/* enables wrap bursting */
	bool burst_read;	/* enables read page/burst mode */
@@ -149,6 +156,7 @@ struct gpmc_settings {
	u32 device_width;	/* device bus width (8 or 16 bit) */
	u32 mux_add_data;	/* multiplex address & data */
	u32 wait_pin;		/* wait-pin to be used */
	u32 wait_pin_polarity;
};

/* Data for each chip select */