memory: omap-gpmc: wait pin additions
This patch introduces support for setting the wait-pin polarity as well as using the same wait-pin for different CS regions. The waitpin polarity can be configured via the WAITPIN<X>POLARITY bits in the GPMC_CONFIG register. This is currently not supported by the driver. This patch adds support for setting the required register bits with the "ti,wait-pin-polarity" dt-property. The wait-pin can also be shared between different CS regions for special usecases. Therefore GPMC must keep track of wait-pin allocations, so it knows that either GPMC itself or another driver has the ownership. Signed-off-by: Benedikt Niedermayr <benedikt.niedermayr@siemens.com> Link: https://lore.kernel.org/r/20221102133047.1654449-2-benedikt.niedermayr@siemens.com Reviewed-by: Roger Quadros <rogerq@kernel.org> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
This commit is contained in:
parent
3821e96a01
commit
89aed3cd5c
|
@ -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 >= 0 && 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,17 +2300,9 @@ 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 @@ err_child_fail:
|
|||
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 @@ gpio_init_failed:
|
|||
|
||||
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);
|
||||
|
|
|
@ -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 -1
|
||||
#define GPMC_WAITPINPOLARITY_ACTIVE_LOW 0
|
||||
#define GPMC_WAITPINPOLARITY_ACTIVE_HIGH 1
|
||||
|
||||
#define GPMC_WAITPIN_INVALID -1
|
||||
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue