mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-17 07:54:54 +08:00
GPMC (General Purpose Memory Controller) changes for omaps. These
changes allow us to drop dependencies to bootloader timings now that the known device tree entries have been fixed. So we can now require proper timings to be configured and get rid of the legacy smsc91x code. Note that this branch has a dependency to the related device tree branch sent in a separate pull request as timings are now required. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUY5toAAoJEBvUPslcq6VzHAwQALbDoi++oqPFfgd9iHZngsFo wxAsb1n4ENaazBJtG2SayDDUo7h3zxKrh/NRqEO43g7oW1V6nD86a5ItM7HlnzH6 upjHAb8O3du3SL8Zmu+AMgcoqB2yz8iZjphPW2r25gnt6on9uFQio5AVMturEpO0 PVyWdpT0sTvLa1JZRjhmn/2cLC1z7eFdG4yjQQdwbrR5WDUX3IQz3X6n7dTM5IJy oH+gM2k9x8ymR7rfFDjBEuZl+0ShHJLfg30ubAGai+MfyLtSBSdKIIpiNdVEbbCe ytMVhTD4pS+5ToVNZ8m5rGtZjY+g0VN57wM8AfKTN7OF6L0nb8ZeOoz0dEJkXQcw IlZ0MP1/k/HhOyQ8FRWcSqvG/frvQjQSHNTaoJAWNvjpHtxQ4Lox1r5mnmy3PICv 2SxDYEysohwBrv/TQJlTMDJn+ndAvygbGxDbMYMbpqwmC1jsL5PA4vMnpMVDrBWo h7V2dHd/uw9uFB+FnSKvOJYMYs2vdsArlxYrk8br0RHt7syugWiVfKDjPvBhOum2 y24Q6bRXUZqloiq2hG4VNN+vhmB6TNdnAXV15kzp+pzmsNh3gsNRTMytQvi0el51 ztYBDvugwrN9WtNryKEaqV4bQrlFiWsxremVfcm8FiynGd8HqRUjf271lGXblsJe IfcIIVJwnpn0Cd/8SWZp =CA9d -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.19/gpmc-timings' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/omap-gpmc Pull "omap gpmc changes for v3.19" from Tony Lindgren: GPMC (General Purpose Memory Controller) changes for omaps. These changes allow us to drop dependencies to bootloader timings now that the known device tree entries have been fixed. So we can now require proper timings to be configured and get rid of the legacy smsc91x code. Note that this branch has a dependency to the related device tree branch sent in a separate pull request as timings are now required. * tag 'omap-for-v3.19/gpmc-timings' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP2+: Remove unnecesary include in GPMC driver ARM: OMAP2+: Drop legacy code for gpmc-smc91x.c ARM: OMAP2+: Require proper GPMC timings for devices ARM: OMAP2+: Show bootloader GPMC timings to allow configuring the .dts file ARM: OMAP2+: Fix support for multiple devices on a GPMC chip select ARM: OMAP2+: gpmc: Sanity check GPMC fck on probe ARM: OMAP2+: gpmc: Keep Chip Select disabled while configuring it ARM: OMAP2+: gpmc: Always enable A26-A11 for non NAND devices ARM: OMAP2+: gpmc: Error out if timings fail in gpmc_probe_generic_child() ARM: OMAP2+: gpmc: Print error message in set_gpmc_timing_reg() Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
594b732110
@ -284,9 +284,6 @@ obj-y += $(onenand-m) $(onenand-y)
|
||||
nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o
|
||||
obj-y += $(nand-m) $(nand-y)
|
||||
|
||||
smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
|
||||
obj-y += $(smc91x-m) $(smc91x-y)
|
||||
|
||||
smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
|
||||
obj-y += $(smsc911x-m) $(smsc911x-y)
|
||||
ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
#include "soc.h"
|
||||
#include "board-flash.h"
|
||||
@ -407,32 +406,6 @@ static int __init omap3430_i2c_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
|
||||
static struct omap_smc91x_platform_data board_smc91x_data = {
|
||||
.cs = 3,
|
||||
.flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
|
||||
IORESOURCE_IRQ_LOWLEVEL,
|
||||
};
|
||||
|
||||
static void __init board_smc91x_init(void)
|
||||
{
|
||||
if (omap_rev() > OMAP3430_REV_ES1_0)
|
||||
board_smc91x_data.gpio_irq = 6;
|
||||
else
|
||||
board_smc91x_data.gpio_irq = 29;
|
||||
|
||||
gpmc_smc91x_init(&board_smc91x_data);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void board_smc91x_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void enable_board_wakeup_source(void)
|
||||
{
|
||||
/* T2 interrupt line (keypad) */
|
||||
@ -609,7 +582,6 @@ static void __init omap_3430sdp_init(void)
|
||||
omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
|
||||
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
|
||||
usb_musb_init(NULL);
|
||||
board_smc91x_init();
|
||||
board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
|
||||
sdp3430_display_init();
|
||||
enable_board_wakeup_source();
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
#include "common.h"
|
||||
#include <linux/omap-dma.h>
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
#include "board-rx51.h"
|
||||
|
||||
@ -1146,33 +1145,6 @@ static struct omap_onenand_platform_data board_onenand_data[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
|
||||
static struct omap_smc91x_platform_data board_smc91x_data = {
|
||||
.cs = 1,
|
||||
.gpio_irq = 54,
|
||||
.gpio_pwrdwn = 86,
|
||||
.gpio_reset = 164,
|
||||
.flags = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
};
|
||||
|
||||
static void __init board_smc91x_init(void)
|
||||
{
|
||||
omap_mux_init_gpio(54, OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_gpio(86, OMAP_PIN_OUTPUT);
|
||||
omap_mux_init_gpio(164, OMAP_PIN_OUTPUT);
|
||||
|
||||
gpmc_smc91x_init(&board_smc91x_data);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void board_smc91x_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct gpio rx51_wl1251_gpios[] __initdata = {
|
||||
{ RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
|
||||
};
|
||||
@ -1303,7 +1275,6 @@ void __init rx51_peripherals_init(void)
|
||||
rx51_i2c_init();
|
||||
regulator_has_full_constraints();
|
||||
gpmc_onenand_init(board_onenand_data);
|
||||
board_smc91x_init();
|
||||
rx51_add_gpio_keys();
|
||||
rx51_init_wl1251();
|
||||
rx51_init_tsc2005();
|
||||
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap2/gpmc-smc91x.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Contact: Tony Lindgren
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/smc91x.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
static struct omap_smc91x_platform_data *gpmc_cfg;
|
||||
|
||||
static struct resource gpmc_smc91x_resources[] = {
|
||||
[0] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct smc91x_platdata gpmc_smc91x_info = {
|
||||
.flags = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0,
|
||||
.leda = RPC_LED_100_10,
|
||||
.ledb = RPC_LED_TX_RX,
|
||||
};
|
||||
|
||||
static struct platform_device gpmc_smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &gpmc_smc91x_info,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(gpmc_smc91x_resources),
|
||||
.resource = gpmc_smc91x_resources,
|
||||
};
|
||||
|
||||
static struct gpmc_settings smc91x_settings = {
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the gpmc timings for smc91c96. The timings are taken
|
||||
* from the data sheet available at:
|
||||
* http://www.smsc.com/main/catalog/lan91c96.html
|
||||
* REVISIT: Level shifters can add at least to the access latency.
|
||||
*/
|
||||
static int smc91c96_gpmc_retime(void)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
struct gpmc_device_timings dev_t;
|
||||
const int t3 = 10; /* Figure 12.2 read and 12.4 write */
|
||||
const int t4_r = 20; /* Figure 12.2 read */
|
||||
const int t4_w = 5; /* Figure 12.4 write */
|
||||
const int t5 = 25; /* Figure 12.2 read */
|
||||
const int t6 = 15; /* Figure 12.2 read */
|
||||
const int t7 = 5; /* Figure 12.4 write */
|
||||
const int t8 = 5; /* Figure 12.4 write */
|
||||
const int t20 = 185; /* Figure 12.2 read and 12.4 write */
|
||||
|
||||
/*
|
||||
* FIXME: Calculate the address and data bus muxed timings.
|
||||
* Note that at least adv_rd_off needs to be changed according
|
||||
* to omap3430 TRM Figure 11-11. Are the sdp boards using the
|
||||
* FPGA in between smc91x and omap as the timings are different
|
||||
* from above?
|
||||
*/
|
||||
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
|
||||
return 0;
|
||||
|
||||
memset(&dev_t, 0, sizeof(dev_t));
|
||||
|
||||
dev_t.t_oeasu = t3 * 1000;
|
||||
dev_t.t_oe = t5 * 1000;
|
||||
dev_t.t_cez_r = t4_r * 1000;
|
||||
dev_t.t_oez = t6 * 1000;
|
||||
dev_t.t_rd_cycle = (t20 - t3) * 1000;
|
||||
|
||||
dev_t.t_weasu = t3 * 1000;
|
||||
dev_t.t_wpl = t7 * 1000;
|
||||
dev_t.t_wph = t8 * 1000;
|
||||
dev_t.t_cez_w = t4_w * 1000;
|
||||
dev_t.t_wr_cycle = (t20 - t3) * 1000;
|
||||
|
||||
gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
|
||||
|
||||
return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize smc91x device connected to the GPMC. Note that we
|
||||
* assume that pin multiplexing is done in the board-*.c file,
|
||||
* or in the bootloader.
|
||||
*/
|
||||
void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
|
||||
{
|
||||
unsigned long cs_mem_base;
|
||||
int ret;
|
||||
|
||||
gpmc_cfg = board_data;
|
||||
|
||||
if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
|
||||
gpmc_cfg->retime = smc91c96_gpmc_retime;
|
||||
|
||||
if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
|
||||
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
|
||||
gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
|
||||
gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
|
||||
|
||||
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
|
||||
smc91x_settings.mux_add_data = GPMC_MUX_AD;
|
||||
if (gpmc_cfg->flags & GPMC_READ_MON)
|
||||
smc91x_settings.wait_on_read = true;
|
||||
if (gpmc_cfg->flags & GPMC_WRITE_MON)
|
||||
smc91x_settings.wait_on_write = true;
|
||||
if (gpmc_cfg->wait_pin)
|
||||
smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
|
||||
ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
|
||||
if (ret < 0)
|
||||
goto free1;
|
||||
|
||||
if (gpmc_cfg->retime) {
|
||||
ret = gpmc_cfg->retime();
|
||||
if (ret != 0)
|
||||
goto free1;
|
||||
}
|
||||
|
||||
if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
|
||||
goto free1;
|
||||
|
||||
gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
|
||||
|
||||
if (gpmc_cfg->gpio_pwrdwn) {
|
||||
ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
|
||||
GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
|
||||
if (ret)
|
||||
goto free2;
|
||||
}
|
||||
|
||||
if (gpmc_cfg->gpio_reset) {
|
||||
ret = gpio_request_one(gpmc_cfg->gpio_reset,
|
||||
GPIOF_OUT_INIT_LOW, "SMC91X reset");
|
||||
if (ret)
|
||||
goto free3;
|
||||
|
||||
gpio_set_value(gpmc_cfg->gpio_reset, 1);
|
||||
msleep(100);
|
||||
gpio_set_value(gpmc_cfg->gpio_reset, 0);
|
||||
}
|
||||
|
||||
if (platform_device_register(&gpmc_smc91x_device) < 0) {
|
||||
printk(KERN_ERR "Unable to register smc91x device\n");
|
||||
gpio_free(gpmc_cfg->gpio_reset);
|
||||
goto free3;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
free3:
|
||||
if (gpmc_cfg->gpio_pwrdwn)
|
||||
gpio_free(gpmc_cfg->gpio_pwrdwn);
|
||||
free2:
|
||||
gpio_free(gpmc_cfg->gpio_irq);
|
||||
free1:
|
||||
gpmc_cs_free(gpmc_cfg->cs);
|
||||
|
||||
printk(KERN_ERR "Could not initialize smc91x\n");
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* arch/arm/plat-omap/include/mach/gpmc-smc91x.h
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_OMAP_GPMC_SMC91X_H__
|
||||
|
||||
#define GPMC_TIMINGS_SMC91C96 (1 << 4)
|
||||
#define GPMC_MUX_ADD_DATA (1 << 5) /* GPMC_CONFIG1_MUXADDDATA */
|
||||
#define GPMC_READ_MON (1 << 6) /* GPMC_CONFIG1_WAIT_READ_MON */
|
||||
#define GPMC_WRITE_MON (1 << 7) /* GPMC_CONFIG1_WAIT_WRITE_MON */
|
||||
|
||||
struct omap_smc91x_platform_data {
|
||||
int cs;
|
||||
int gpio_irq;
|
||||
int gpio_pwrdwn;
|
||||
int gpio_reset;
|
||||
int wait_pin; /* Optional GPMC_CONFIG1_WAITPINSELECT */
|
||||
u32 flags;
|
||||
int (*retime)(void);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SMC91X) || \
|
||||
defined(CONFIG_SMC91X_MODULE)
|
||||
|
||||
extern void gpmc_smc91x_init(struct omap_smc91x_platform_data *d);
|
||||
|
||||
#else
|
||||
|
||||
#define board_smc91x_data NULL
|
||||
|
||||
static inline void gpmc_smc91x_init(struct omap_smc91x_platform_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -37,7 +37,6 @@
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "common.h"
|
||||
#include "omap_device.h"
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-nand.h"
|
||||
@ -85,6 +84,8 @@
|
||||
#define GPMC_ECC_CTRL_ECCREG8 0x008
|
||||
#define GPMC_ECC_CTRL_ECCREG9 0x009
|
||||
|
||||
#define GPMC_CONFIG_LIMITEDADDRESS BIT(1)
|
||||
|
||||
#define GPMC_CONFIG2_CSEXTRADELAY BIT(7)
|
||||
#define GPMC_CONFIG3_ADVEXTRADELAY BIT(7)
|
||||
#define GPMC_CONFIG4_OEEXTRADELAY BIT(7)
|
||||
@ -118,6 +119,15 @@
|
||||
*/
|
||||
#define GPMC_NR_IRQ 2
|
||||
|
||||
struct gpmc_cs_data {
|
||||
const char *name;
|
||||
|
||||
#define GPMC_CS_RESERVED (1 << 0)
|
||||
u32 flags;
|
||||
|
||||
struct resource mem;
|
||||
};
|
||||
|
||||
struct gpmc_client_irq {
|
||||
unsigned irq;
|
||||
u32 bitmask;
|
||||
@ -155,10 +165,9 @@ static struct irq_chip gpmc_irq_chip;
|
||||
static int gpmc_irq_start;
|
||||
|
||||
static struct resource gpmc_mem_root;
|
||||
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||
static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
|
||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
/* Define chip-selects as reserved by default until probe completes */
|
||||
static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
|
||||
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
|
||||
static unsigned int gpmc_nr_waitpins;
|
||||
static struct device *gpmc_dev;
|
||||
@ -202,11 +211,6 @@ static unsigned long gpmc_get_fclk_period(void)
|
||||
{
|
||||
unsigned long rate = clk_get_rate(gpmc_l3_clk);
|
||||
|
||||
if (rate == 0) {
|
||||
printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rate /= 1000;
|
||||
rate = 1000000000 / rate; /* In picoseconds */
|
||||
|
||||
@ -284,12 +288,130 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
||||
bool raw, bool noval, int shift,
|
||||
const char *name)
|
||||
{
|
||||
u32 l;
|
||||
int nr_bits, max_value, mask;
|
||||
|
||||
l = gpmc_cs_read_reg(cs, reg);
|
||||
nr_bits = end_bit - st_bit + 1;
|
||||
max_value = (1 << nr_bits) - 1;
|
||||
mask = max_value << st_bit;
|
||||
l = (l & mask) >> st_bit;
|
||||
if (shift)
|
||||
l = (shift << l);
|
||||
if (noval && (l == 0))
|
||||
return 0;
|
||||
if (!raw) {
|
||||
unsigned int time_ns_min, time_ns, time_ns_max;
|
||||
|
||||
time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
|
||||
time_ns = gpmc_ticks_to_ns(l);
|
||||
time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ?
|
||||
max_value : l + 1);
|
||||
pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n",
|
||||
name, time_ns, time_ns_min, time_ns_max, l);
|
||||
} else {
|
||||
pr_info("gpmc,%s = <%u>\n", name, l);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
#define GPMC_PRINT_CONFIG(cs, config) \
|
||||
pr_info("cs%i %s: 0x%08x\n", cs, #config, \
|
||||
gpmc_cs_read_reg(cs, config))
|
||||
#define GPMC_GET_RAW(reg, st, end, field) \
|
||||
get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 0, 0, field)
|
||||
#define GPMC_GET_RAW_BOOL(reg, st, end, field) \
|
||||
get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, 0, field)
|
||||
#define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \
|
||||
get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, (shift), field)
|
||||
#define GPMC_GET_TICKS(reg, st, end, field) \
|
||||
get_gpmc_timing_reg(cs, (reg), (st), (end), 0, 0, 0, field)
|
||||
|
||||
static void gpmc_show_regs(int cs, const char *desc)
|
||||
{
|
||||
pr_info("gpmc cs%i %s:\n", cs, desc);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG1);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG2);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG3);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG4);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG5);
|
||||
GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG6);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that gpmc,wait-pin handing wrongly assumes bit 8 is available,
|
||||
* see commit c9fb809.
|
||||
*/
|
||||
static void gpmc_cs_show_timings(int cs, const char *desc)
|
||||
{
|
||||
gpmc_show_regs(cs, desc);
|
||||
|
||||
pr_info("gpmc cs%i access configuration:\n", cs);
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 4, 4, "time-para-granularity");
|
||||
GPMC_GET_RAW(GPMC_CS_CONFIG1, 8, 9, "mux-add-data");
|
||||
GPMC_GET_RAW(GPMC_CS_CONFIG1, 12, 13, "device-width");
|
||||
GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read");
|
||||
GPMC_GET_RAW_SHIFT(GPMC_CS_CONFIG1, 23, 24, 4, "burst-length");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 30, 30, "burst-read");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 31, 31, "burst-wrap");
|
||||
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG2, 7, 7, "cs-extra-delay");
|
||||
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG3, 7, 7, "adv-extra-delay");
|
||||
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 23, 23, "we-extra-delay");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 7, 7, "oe-extra-delay");
|
||||
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 7, 7, "cycle2cycle-samecsen");
|
||||
GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 6, 6, "cycle2cycle-diffcsen");
|
||||
|
||||
pr_info("gpmc cs%i timings configuration:\n", cs);
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG2, 0, 3, "cs-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG2, 8, 12, "cs-rd-off-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG2, 16, 20, "cs-wr-off-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 0, 3, "adv-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 8, 12, "adv-rd-off-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 16, 20, "adv-wr-off-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 0, 3, "oe-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 8, 12, "oe-off-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 16, 19, "we-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 24, 28, "we-off-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG5, 0, 4, "rd-cycle-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG5, 8, 12, "wr-cycle-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG5, 16, 20, "access-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG5, 24, 27, "page-burst-access-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG1, 18, 19, "wait-monitoring-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG1, 25, 26, "clk-activation-ns");
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns");
|
||||
}
|
||||
#else
|
||||
static inline void gpmc_cs_show_timings(int cs, const char *desc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
||||
int time, const char *name)
|
||||
#else
|
||||
static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
||||
int time)
|
||||
#endif
|
||||
{
|
||||
u32 l;
|
||||
int ticks, mask, nr_bits;
|
||||
@ -299,15 +421,15 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
||||
else
|
||||
ticks = gpmc_ns_to_ticks(time);
|
||||
nr_bits = end_bit - st_bit + 1;
|
||||
if (ticks >= 1 << nr_bits) {
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
|
||||
cs, name, time, ticks, 1 << nr_bits);
|
||||
#endif
|
||||
mask = (1 << nr_bits) - 1;
|
||||
|
||||
if (ticks > mask) {
|
||||
pr_err("%s: GPMC error! CS%d: %s: %d ns, %d ticks > %d\n",
|
||||
__func__, cs, name, time, ticks, mask);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
mask = (1 << nr_bits) - 1;
|
||||
l = gpmc_cs_read_reg(cs, reg);
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO
|
||||
@ -322,16 +444,10 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define GPMC_SET_ONE(reg, st, end, field) \
|
||||
if (set_gpmc_timing_reg(cs, (reg), (st), (end), \
|
||||
t->field, #field) < 0) \
|
||||
return -1
|
||||
#else
|
||||
#define GPMC_SET_ONE(reg, st, end, field) \
|
||||
if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
|
||||
return -1
|
||||
#endif
|
||||
|
||||
int gpmc_calc_divider(unsigned int sync_clk)
|
||||
{
|
||||
@ -353,6 +469,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
|
||||
int div;
|
||||
u32 l;
|
||||
|
||||
gpmc_cs_show_timings(cs, "before gpmc_cs_set_timings");
|
||||
div = gpmc_calc_divider(t->sync_clk);
|
||||
if (div < 0)
|
||||
return div;
|
||||
@ -402,11 +519,12 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
|
||||
}
|
||||
|
||||
gpmc_cs_bool_timings(cs, &t->bool_timings);
|
||||
gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
|
||||
static int gpmc_cs_set_memconf(int cs, u32 base, u32 size)
|
||||
{
|
||||
u32 l;
|
||||
u32 mask;
|
||||
@ -430,6 +548,15 @@ static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpmc_cs_enable_mem(int cs)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
|
||||
l |= GPMC_CONFIG7_CSVALID;
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
|
||||
}
|
||||
|
||||
static void gpmc_cs_disable_mem(int cs)
|
||||
{
|
||||
u32 l;
|
||||
@ -460,13 +587,30 @@ static int gpmc_cs_mem_enabled(int cs)
|
||||
|
||||
static void gpmc_cs_set_reserved(int cs, int reserved)
|
||||
{
|
||||
gpmc_cs_map &= ~(1 << cs);
|
||||
gpmc_cs_map |= (reserved ? 1 : 0) << cs;
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
gpmc->flags |= GPMC_CS_RESERVED;
|
||||
}
|
||||
|
||||
static bool gpmc_cs_reserved(int cs)
|
||||
{
|
||||
return gpmc_cs_map & (1 << cs);
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
return gpmc->flags & GPMC_CS_RESERVED;
|
||||
}
|
||||
|
||||
static void gpmc_cs_set_name(int cs, const char *name)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
gpmc->name = name;
|
||||
}
|
||||
|
||||
const char *gpmc_cs_get_name(int cs)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
return gpmc->name;
|
||||
}
|
||||
|
||||
static unsigned long gpmc_mem_align(unsigned long size)
|
||||
@ -485,7 +629,8 @@ static unsigned long gpmc_mem_align(unsigned long size)
|
||||
|
||||
static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
struct resource *res = &gpmc->mem;
|
||||
int r;
|
||||
|
||||
size = gpmc_mem_align(size);
|
||||
@ -500,7 +645,8 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
|
||||
|
||||
static int gpmc_cs_delete_mem(int cs)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
struct resource *res = &gpmc->mem;
|
||||
int r;
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
@ -541,23 +687,24 @@ static int gpmc_cs_remap(int cs, u32 base)
|
||||
gpmc_cs_get_memconf(cs, &old_base, &size);
|
||||
if (base == old_base)
|
||||
return 0;
|
||||
gpmc_cs_disable_mem(cs);
|
||||
|
||||
ret = gpmc_cs_delete_mem(cs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_insert_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gpmc_cs_enable_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
ret = gpmc_cs_set_memconf(cs, base, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
struct resource *res = &gpmc->mem;
|
||||
int r = -1;
|
||||
|
||||
if (cs > gpmc_cs_num) {
|
||||
@ -581,12 +728,17 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
|
||||
/* Disable CS while changing base address and size mask */
|
||||
gpmc_cs_disable_mem(cs);
|
||||
|
||||
r = gpmc_cs_set_memconf(cs, res->start, resource_size(res));
|
||||
if (r < 0) {
|
||||
release_resource(res);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Enable CS */
|
||||
gpmc_cs_enable_mem(cs);
|
||||
*base = res->start;
|
||||
gpmc_cs_set_reserved(cs, 1);
|
||||
out:
|
||||
@ -597,7 +749,8 @@ EXPORT_SYMBOL(gpmc_cs_request);
|
||||
|
||||
void gpmc_cs_free(int cs)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
struct resource *res = &gpmc->mem;
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
|
||||
@ -1511,7 +1664,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||
struct gpmc_timings gpmc_t;
|
||||
struct resource res;
|
||||
unsigned long base;
|
||||
const char *name;
|
||||
int ret, cs;
|
||||
u32 val;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &cs) < 0) {
|
||||
dev_err(&pdev->dev, "%s has no 'reg' property\n",
|
||||
@ -1525,28 +1680,41 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we have multiple instances of the same device
|
||||
* on a single chip select. If so, use the already initialized
|
||||
* timings.
|
||||
*/
|
||||
name = gpmc_cs_get_name(cs);
|
||||
if (name && child->name && of_node_cmp(child->name, name) == 0)
|
||||
goto no_timings;
|
||||
|
||||
ret = gpmc_cs_request(cs, resource_size(&res), &base);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
|
||||
return ret;
|
||||
}
|
||||
gpmc_cs_set_name(cs, child->name);
|
||||
|
||||
gpmc_read_settings_dt(child, &gpmc_s);
|
||||
gpmc_read_timings_dt(child, &gpmc_t);
|
||||
|
||||
/*
|
||||
* For some GPMC devices we still need to rely on the bootloader
|
||||
* timings because the devices can be connected via FPGA. So far
|
||||
* the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
|
||||
* REVISIT: Add timing support from slls644g.pdf and from the
|
||||
* lan91c96 manual.
|
||||
* timings because the devices can be connected via FPGA.
|
||||
* REVISIT: Add timing support from slls644g.pdf.
|
||||
*/
|
||||
if (of_device_is_compatible(child, "ns16550a") ||
|
||||
of_device_is_compatible(child, "smsc,lan91c94") ||
|
||||
of_device_is_compatible(child, "smsc,lan91c111")) {
|
||||
dev_warn(&pdev->dev,
|
||||
"%s using bootloader timings on CS%d\n",
|
||||
child->name, cs);
|
||||
if (!gpmc_t.cs_rd_off) {
|
||||
WARN(1, "enable GPMC debug to configure .dts timings for CS%i\n",
|
||||
cs);
|
||||
gpmc_cs_show_timings(cs,
|
||||
"please add GPMC bootloader timings to .dts");
|
||||
goto no_timings;
|
||||
}
|
||||
|
||||
/* CS must be disabled while making changes to gpmc configuration */
|
||||
gpmc_cs_disable_mem(cs);
|
||||
|
||||
/*
|
||||
* FIXME: gpmc_cs_request() will map the CS to an arbitary
|
||||
* location in the gpmc address space. When booting with
|
||||
@ -1562,8 +1730,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||
goto err;
|
||||
}
|
||||
|
||||
gpmc_read_settings_dt(child, &gpmc_s);
|
||||
|
||||
ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
@ -1572,8 +1738,20 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
gpmc_read_timings_dt(child, &gpmc_t);
|
||||
gpmc_cs_set_timings(cs, &gpmc_t);
|
||||
ret = gpmc_cs_set_timings(cs, &gpmc_t);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
|
||||
child->name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Clear limited address i.e. enable A26-A11 */
|
||||
val = gpmc_read_reg(GPMC_CONFIG);
|
||||
val &= ~GPMC_CONFIG_LIMITEDADDRESS;
|
||||
gpmc_write_reg(GPMC_CONFIG, val);
|
||||
|
||||
/* Enable CS region */
|
||||
gpmc_cs_enable_mem(cs);
|
||||
|
||||
no_timings:
|
||||
if (of_platform_device_create(child, NULL, &pdev->dev))
|
||||
@ -1670,13 +1848,18 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
else
|
||||
gpmc_irq = res->start;
|
||||
|
||||
gpmc_l3_clk = clk_get(&pdev->dev, "fck");
|
||||
gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(gpmc_l3_clk)) {
|
||||
dev_err(&pdev->dev, "error: clk_get\n");
|
||||
dev_err(&pdev->dev, "Failed to get GPMC fck\n");
|
||||
gpmc_irq = 0;
|
||||
return PTR_ERR(gpmc_l3_clk);
|
||||
}
|
||||
|
||||
if (!clk_get_rate(gpmc_l3_clk)) {
|
||||
dev_err(&pdev->dev, "Invalid GPMC fck clock rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
@ -1708,9 +1891,6 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
if (gpmc_setup_irq() < 0)
|
||||
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
||||
|
||||
/* Now the GPMC is initialised, unreserve the chip-selects */
|
||||
gpmc_cs_map = 0;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
gpmc_cs_num = GPMC_CS_NUM;
|
||||
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
|
||||
@ -1719,7 +1899,6 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
rc = gpmc_probe_dt(pdev);
|
||||
if (rc < 0) {
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
clk_put(gpmc_l3_clk);
|
||||
dev_err(gpmc_dev, "failed to probe DT parameters\n");
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user