2 * GPMC support functions
4 * Copyright (C) 2005-2006 Nokia Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/err.h>
15 #include <linux/clk.h>
18 #include <asm/arch/gpmc.h>
22 #define GPMC_BASE 0x6800a000
23 #define GPMC_REVISION 0x00
24 #define GPMC_SYSCONFIG 0x10
25 #define GPMC_SYSSTATUS 0x14
26 #define GPMC_IRQSTATUS 0x18
27 #define GPMC_IRQENABLE 0x1c
28 #define GPMC_TIMEOUT_CONTROL 0x40
29 #define GPMC_ERR_ADDRESS 0x44
30 #define GPMC_ERR_TYPE 0x48
31 #define GPMC_CONFIG 0x50
32 #define GPMC_STATUS 0x54
33 #define GPMC_PREFETCH_CONFIG1 0x1e0
34 #define GPMC_PREFETCH_CONFIG2 0x1e4
35 #define GPMC_PREFETCH_CONTROL 0x1e8
36 #define GPMC_PREFETCH_STATUS 0x1f0
37 #define GPMC_ECC_CONFIG 0x1f4
38 #define GPMC_ECC_CONTROL 0x1f8
39 #define GPMC_ECC_SIZE_CONFIG 0x1fc
42 #define GPMC_CS_SIZE 0x30
44 static void __iomem
*gpmc_base
=
45 (void __iomem
*) IO_ADDRESS(GPMC_BASE
);
46 static void __iomem
*gpmc_cs_base
=
47 (void __iomem
*) IO_ADDRESS(GPMC_BASE
) + GPMC_CS0
;
49 static struct clk
*gpmc_l3_clk
;
51 static void gpmc_write_reg(int idx
, u32 val
)
53 __raw_writel(val
, gpmc_base
+ idx
);
56 static u32
gpmc_read_reg(int idx
)
58 return __raw_readl(gpmc_base
+ idx
);
61 void gpmc_cs_write_reg(int cs
, int idx
, u32 val
)
63 void __iomem
*reg_addr
;
65 reg_addr
= gpmc_cs_base
+ (cs
* GPMC_CS_SIZE
) + idx
;
66 __raw_writel(val
, reg_addr
);
69 u32
gpmc_cs_read_reg(int cs
, int idx
)
71 return __raw_readl(gpmc_cs_base
+ (cs
* GPMC_CS_SIZE
) + idx
);
74 /* TODO: Add support for gpmc_fck to clock framework and use it */
75 static unsigned long gpmc_get_fclk_period(void)
78 return 1000000000 / ((clk_get_rate(gpmc_l3_clk
)) / 1000);
81 unsigned int gpmc_ns_to_ticks(unsigned int time_ns
)
83 unsigned long tick_ps
;
85 /* Calculate in picosecs to yield more exact results */
86 tick_ps
= gpmc_get_fclk_period();
88 return (time_ns
* 1000 + tick_ps
- 1) / tick_ps
;
92 static int set_gpmc_timing_reg(int cs
, int reg
, int st_bit
, int end_bit
,
93 int time
, const char *name
)
95 static int set_gpmc_timing_reg(int cs
, int reg
, int st_bit
, int end_bit
,
100 int ticks
, mask
, nr_bits
;
105 ticks
= gpmc_ns_to_ticks(time
);
106 nr_bits
= end_bit
- st_bit
+ 1;
107 if (ticks
>= 1 << nr_bits
)
110 mask
= (1 << nr_bits
) - 1;
111 l
= gpmc_cs_read_reg(cs
, reg
);
113 printk(KERN_INFO
"GPMC CS%d: %-10s: %d ticks, %3lu ns (was %i ticks)\n",
114 cs
, name
, ticks
, gpmc_get_fclk_period() * ticks
/ 1000,
115 (l
>> st_bit
) & mask
);
117 l
&= ~(mask
<< st_bit
);
118 l
|= ticks
<< st_bit
;
119 gpmc_cs_write_reg(cs
, reg
, l
);
125 #define GPMC_SET_ONE(reg, st, end, field) \
126 if (set_gpmc_timing_reg(cs, (reg), (st), (end), \
127 t->field, #field) < 0) \
130 #define GPMC_SET_ONE(reg, st, end, field) \
131 if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
135 int gpmc_cs_calc_divider(int cs
, unsigned int sync_clk
)
140 l
= sync_clk
* 1000 + (gpmc_get_fclk_period() - 1);
141 div
= l
/ gpmc_get_fclk_period();
150 int gpmc_cs_set_timings(int cs
, const struct gpmc_timings
*t
)
155 div
= gpmc_cs_calc_divider(cs
, t
->sync_clk
);
159 GPMC_SET_ONE(GPMC_CS_CONFIG2
, 0, 3, cs_on
);
160 GPMC_SET_ONE(GPMC_CS_CONFIG2
, 8, 12, cs_rd_off
);
161 GPMC_SET_ONE(GPMC_CS_CONFIG2
, 16, 20, cs_wr_off
);
163 GPMC_SET_ONE(GPMC_CS_CONFIG3
, 0, 3, adv_on
);
164 GPMC_SET_ONE(GPMC_CS_CONFIG3
, 8, 12, adv_rd_off
);
165 GPMC_SET_ONE(GPMC_CS_CONFIG3
, 16, 20, adv_wr_off
);
167 GPMC_SET_ONE(GPMC_CS_CONFIG4
, 0, 3, oe_on
);
168 GPMC_SET_ONE(GPMC_CS_CONFIG4
, 8, 12, oe_off
);
169 GPMC_SET_ONE(GPMC_CS_CONFIG4
, 16, 19, we_on
);
170 GPMC_SET_ONE(GPMC_CS_CONFIG4
, 24, 28, we_off
);
172 GPMC_SET_ONE(GPMC_CS_CONFIG5
, 0, 4, rd_cycle
);
173 GPMC_SET_ONE(GPMC_CS_CONFIG5
, 8, 12, wr_cycle
);
174 GPMC_SET_ONE(GPMC_CS_CONFIG5
, 16, 20, access
);
176 GPMC_SET_ONE(GPMC_CS_CONFIG5
, 24, 27, page_burst_access
);
179 printk(KERN_INFO
"GPMC CS%d CLK period is %lu (div %d)\n",
180 cs
, gpmc_get_fclk_period(), div
);
183 l
= gpmc_cs_read_reg(cs
, GPMC_CS_CONFIG1
);
190 unsigned long gpmc_cs_get_base_addr(int cs
)
192 return (gpmc_cs_read_reg(cs
, GPMC_CS_CONFIG7
) & 0x1f) << 24;
195 void __init
gpmc_init(void)
199 gpmc_l3_clk
= clk_get(NULL
, "core_l3_ck");
200 BUG_ON(IS_ERR(gpmc_l3_clk
));
202 l
= gpmc_read_reg(GPMC_REVISION
);
203 printk(KERN_INFO
"GPMC revision %d.%d\n", (l
>> 4) & 0x0f, l
& 0x0f);
204 /* Set smart idle mode and automatic L3 clock gating */
205 l
= gpmc_read_reg(GPMC_SYSCONFIG
);
207 l
|= (0x02 << 3) | (1 << 0);
208 gpmc_write_reg(GPMC_SYSCONFIG
, l
);