Commit fe04716e authored by Arnd Bergmann's avatar Arnd Bergmann

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.orgSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 26a12002 8dd7e4af
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %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# $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: maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com> - Miquel Raynal <miquel.raynal@bootlin.com>
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com> - Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
description: description: |
The PL353 Static Memory Controller is a bus where you can connect two kinds 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 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' # We need a select here so we don't match all nodes with 'arm,primecell'
select: select:
properties: properties:
compatible: compatible:
contains: contains:
const: arm,pl353-smc-r2p1 enum:
- arm,pl353-smc-r2p1
- arm,pl354
required: required:
- compatible - compatible
...@@ -30,7 +35,9 @@ properties: ...@@ -30,7 +35,9 @@ properties:
compatible: compatible:
items: items:
- const: arm,pl353-smc-r2p1 - enum:
- arm,pl353-smc-r2p1
- arm,pl354
- const: arm,primecell - const: arm,primecell
"#address-cells": "#address-cells":
...@@ -46,30 +53,25 @@ properties: ...@@ -46,30 +53,25 @@ properties:
The three chip select regions are defined in 'ranges'. The three chip select regions are defined in 'ranges'.
clocks: clocks:
items: minItems: 1
- description: clock for the memory device bus maxItems: 2
- description: main clock of the SMC
clock-names: clock-names:
items: minItems: 1
- const: memclk maxItems: 2
- const: apb_pclk
ranges: ranges:
minItems: 1 minItems: 1
description: | maxItems: 8
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
interrupts: true interrupts:
minItems: 1
items:
- description: Combined or Memory interface 0 IRQ
- description: Memory interface 1 IRQ
patternProperties: patternProperties:
"@[0-3],[a-f0-9]+$": "@[0-7],[a-f0-9]+$":
type: object type: object
description: | description: |
The child device node represents the controller connected to the SMC The child device node represents the controller connected to the SMC
...@@ -87,7 +89,7 @@ patternProperties: ...@@ -87,7 +89,7 @@ patternProperties:
- description: | - description: |
Chip-select ID, as in the parent range property. Chip-select ID, as in the parent range property.
minimum: 0 minimum: 0
maximum: 2 maximum: 7
- description: | - description: |
Offset of the memory region requested by the device. Offset of the memory region requested by the device.
- description: | - description: |
...@@ -102,12 +104,36 @@ required: ...@@ -102,12 +104,36 @@ required:
- reg - reg
- clock-names - clock-names
- clocks - clocks
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false 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: examples:
- | - |
smcc: memory-controller@e000e000 { smcc: memory-controller@e000e000 {
......
...@@ -230,6 +230,13 @@ properties: ...@@ -230,6 +230,13 @@ properties:
Wait-pin used by client. Must be less than "gpmc,num-waitpins". Wait-pin used by client. Must be less than "gpmc,num-waitpins".
$ref: /schemas/types.yaml#/definitions/uint32 $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: gpmc,wait-on-read:
description: Enables wait monitoring on reads. description: Enables wait monitoring on reads.
type: boolean type: boolean
......
...@@ -1685,7 +1685,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com> ...@@ -1685,7 +1685,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com> M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained 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 F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER ARM PRIMECELL CLCD PL110 DRIVER
......
...@@ -134,6 +134,7 @@ ...@@ -134,6 +134,7 @@
#define GPMC_CONFIG_DEV_SIZE 0x00000002 #define GPMC_CONFIG_DEV_SIZE 0x00000002
#define GPMC_CONFIG_DEV_TYPE 0x00000003 #define GPMC_CONFIG_DEV_TYPE 0x00000003
#define GPMC_CONFIG_WAITPINPOLARITY(pin) (BIT(pin) << 8)
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31) #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30) #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29) #define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
...@@ -229,6 +230,12 @@ struct omap3_gpmc_regs { ...@@ -229,6 +230,12 @@ struct omap3_gpmc_regs {
struct gpmc_cs_config cs_context[GPMC_CS_NUM]; struct gpmc_cs_config cs_context[GPMC_CS_NUM];
}; };
struct gpmc_waitpin {
u32 pin;
u32 polarity;
struct gpio_desc *desc;
};
struct gpmc_device { struct gpmc_device {
struct device *dev; struct device *dev;
int irq; int irq;
...@@ -236,6 +243,7 @@ struct gpmc_device { ...@@ -236,6 +243,7 @@ struct gpmc_device {
struct gpio_chip gpio_chip; struct gpio_chip gpio_chip;
struct notifier_block nb; struct notifier_block nb;
struct omap3_gpmc_regs context; struct omap3_gpmc_regs context;
struct gpmc_waitpin *waitpins;
int nirqs; int nirqs;
unsigned int is_suspended:1; unsigned int is_suspended:1;
struct resource *data; struct resource *data;
...@@ -1035,6 +1043,62 @@ void gpmc_cs_free(int cs) ...@@ -1035,6 +1043,62 @@ void gpmc_cs_free(int cs)
} }
EXPORT_SYMBOL(gpmc_cs_free); 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 * gpmc_configure - write request to configure gpmc
* @cmd: command type * @cmd: command type
...@@ -1886,6 +1950,17 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p) ...@@ -1886,6 +1950,17 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1); 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; return 0;
} }
...@@ -1975,7 +2050,25 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) ...@@ -1975,7 +2050,25 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
__func__); __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 (!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, p->wait_on_read = of_property_read_bool(np,
"gpmc,wait-on-read"); "gpmc,wait-on-read");
p->wait_on_write = of_property_read_bool(np, p->wait_on_write = of_property_read_bool(np,
...@@ -2080,7 +2173,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2080,7 +2173,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
const char *name; const char *name;
int ret, cs; int ret, cs;
u32 val; u32 val;
struct gpio_desc *waitpin_desc = NULL;
struct gpmc_device *gpmc = platform_get_drvdata(pdev); struct gpmc_device *gpmc = platform_get_drvdata(pdev);
if (of_property_read_u32(child, "reg", &cs) < 0) { if (of_property_read_u32(child, "reg", &cs) < 0) {
...@@ -2208,18 +2300,10 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2208,18 +2300,10 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
/* Reserve wait pin if it is required and valid */ /* Reserve wait pin if it is required and valid */
if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) { if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
unsigned int wait_pin = gpmc_s.wait_pin; ret = gpmc_alloc_waitpin(gpmc, &gpmc_s);
if (ret < 0)
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);
goto err; goto err;
} }
}
gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings"); gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
...@@ -2260,7 +2344,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2260,7 +2344,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
ret = -ENODEV; ret = -ENODEV;
err_cs: err_cs:
gpiochip_free_own_desc(waitpin_desc); gpmc_free_waitpin(gpmc, gpmc_s.wait_pin);
err: err:
gpmc_cs_free(cs); gpmc_cs_free(cs);
...@@ -2489,7 +2573,7 @@ static int omap_gpmc_context_notifier(struct notifier_block *nb, ...@@ -2489,7 +2573,7 @@ static int omap_gpmc_context_notifier(struct notifier_block *nb,
static int gpmc_probe(struct platform_device *pdev) static int gpmc_probe(struct platform_device *pdev)
{ {
int rc; int rc, i;
u32 l; u32 l;
struct resource *res; struct resource *res;
struct gpmc_device *gpmc; struct gpmc_device *gpmc;
...@@ -2545,6 +2629,15 @@ static int gpmc_probe(struct platform_device *pdev) ...@@ -2545,6 +2629,15 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc_nr_waitpins = GPMC_NR_WAITPINS; 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_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
...@@ -2598,9 +2691,12 @@ static int gpmc_probe(struct platform_device *pdev) ...@@ -2598,9 +2691,12 @@ static int gpmc_probe(struct platform_device *pdev)
static int gpmc_remove(struct platform_device *pdev) static int gpmc_remove(struct platform_device *pdev)
{ {
int i;
struct gpmc_device *gpmc = platform_get_drvdata(pdev); struct gpmc_device *gpmc = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&gpmc->nb); cpu_pm_unregister_notifier(&gpmc->nb);
for (i = 0; i < gpmc_nr_waitpins; i++)
gpmc_free_waitpin(gpmc, i);
gpmc_free_irq(gpmc); gpmc_free_irq(gpmc);
gpmc_mem_exit(); gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
......
...@@ -136,6 +136,13 @@ struct gpmc_device_timings { ...@@ -136,6 +136,13 @@ struct gpmc_device_timings {
#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ #define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
#define GPMC_MUX_AD 2 /* 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 { struct gpmc_settings {
bool burst_wrap; /* enables wrap bursting */ bool burst_wrap; /* enables wrap bursting */
bool burst_read; /* enables read page/burst mode */ bool burst_read; /* enables read page/burst mode */
...@@ -149,6 +156,7 @@ struct gpmc_settings { ...@@ -149,6 +156,7 @@ struct gpmc_settings {
u32 device_width; /* device bus width (8 or 16 bit) */ u32 device_width; /* device bus width (8 or 16 bit) */
u32 mux_add_data; /* multiplex address & data */ u32 mux_add_data; /* multiplex address & data */
u32 wait_pin; /* wait-pin to be used */ u32 wait_pin; /* wait-pin to be used */
u32 wait_pin_polarity;
}; };
/* Data for each chip select */ /* Data for each chip select */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment