forked from mirrors/linux
		
	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
					
				
					 2 changed files with 117 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -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,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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 a new issue