diff options
-rw-r--r-- | arch/avr32/mach-at32ap/Makefile | 2 | ||||
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap7000.c | 10 | ||||
-rw-r--r-- | arch/avr32/mach-at32ap/hsmc.c | 164 | ||||
-rw-r--r-- | arch/avr32/mach-at32ap/hsmc.h | 127 | ||||
-rw-r--r-- | include/asm-avr32/arch-at32ap/smc.h | 60 |
5 files changed, 362 insertions, 1 deletions
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile index 4b10853eb614..f62eb6915510 100644 --- a/arch/avr32/mach-at32ap/Makefile +++ b/arch/avr32/mach-at32ap/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-y += at32ap.o clock.o pio.o intc.o extint.o | 1 | obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o |
2 | obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o | 2 | obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o |
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index e8c6893a1c23..37982b60398e 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c | |||
@@ -450,6 +450,13 @@ static struct clk hramc_clk = { | |||
450 | .users = 1, | 450 | .users = 1, |
451 | }; | 451 | }; |
452 | 452 | ||
453 | static struct resource smc0_resource[] = { | ||
454 | PBMEM(0xfff03400), | ||
455 | }; | ||
456 | DEFINE_DEV(smc, 0); | ||
457 | DEV_CLK(pclk, smc0, pbb, 13); | ||
458 | DEV_CLK(mck, smc0, hsb, 0); | ||
459 | |||
453 | static struct platform_device pdc_device = { | 460 | static struct platform_device pdc_device = { |
454 | .name = "pdc", | 461 | .name = "pdc", |
455 | .id = 0, | 462 | .id = 0, |
@@ -503,6 +510,7 @@ void __init at32_add_system_devices(void) | |||
503 | 510 | ||
504 | platform_device_register(&at32_sm_device); | 511 | platform_device_register(&at32_sm_device); |
505 | platform_device_register(&at32_intc0_device); | 512 | platform_device_register(&at32_intc0_device); |
513 | platform_device_register(&smc0_device); | ||
506 | platform_device_register(&pdc_device); | 514 | platform_device_register(&pdc_device); |
507 | 515 | ||
508 | platform_device_register(&pio0_device); | 516 | platform_device_register(&pio0_device); |
@@ -796,6 +804,8 @@ struct clk *at32_clock_list[] = { | |||
796 | &at32_intc0_pclk, | 804 | &at32_intc0_pclk, |
797 | &ebi_clk, | 805 | &ebi_clk, |
798 | &hramc_clk, | 806 | &hramc_clk, |
807 | &smc0_pclk, | ||
808 | &smc0_mck, | ||
799 | &pdc_hclk, | 809 | &pdc_hclk, |
800 | &pdc_pclk, | 810 | &pdc_pclk, |
801 | &pico_clk, | 811 | &pico_clk, |
diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c new file mode 100644 index 000000000000..7691721928a7 --- /dev/null +++ b/arch/avr32/mach-at32ap/hsmc.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * Static Memory Controller for AT32 chips | ||
3 | * | ||
4 | * Copyright (C) 2006 Atmel Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #define DEBUG | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | |||
17 | #include <asm/io.h> | ||
18 | #include <asm/arch/smc.h> | ||
19 | |||
20 | #include "hsmc.h" | ||
21 | |||
22 | #define NR_CHIP_SELECTS 6 | ||
23 | |||
24 | struct hsmc { | ||
25 | void __iomem *regs; | ||
26 | struct clk *pclk; | ||
27 | struct clk *mck; | ||
28 | }; | ||
29 | |||
30 | static struct hsmc *hsmc; | ||
31 | |||
32 | int smc_set_configuration(int cs, const struct smc_config *config) | ||
33 | { | ||
34 | unsigned long mul; | ||
35 | unsigned long offset; | ||
36 | u32 setup, pulse, cycle, mode; | ||
37 | |||
38 | if (!hsmc) | ||
39 | return -ENODEV; | ||
40 | if (cs >= NR_CHIP_SELECTS) | ||
41 | return -EINVAL; | ||
42 | |||
43 | /* | ||
44 | * cycles = x / T = x * f | ||
45 | * = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536 | ||
46 | * = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536 | ||
47 | */ | ||
48 | mul = (clk_get_rate(hsmc->mck) / 10000) << 16; | ||
49 | mul /= 100000; | ||
50 | |||
51 | #define ns2cyc(x) ((((x) * mul) + 65535) >> 16) | ||
52 | |||
53 | setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup)) | ||
54 | | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup)) | ||
55 | | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup)) | ||
56 | | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup))); | ||
57 | pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse)) | ||
58 | | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse)) | ||
59 | | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse)) | ||
60 | | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse))); | ||
61 | cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle)) | ||
62 | | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle))); | ||
63 | |||
64 | switch (config->bus_width) { | ||
65 | case 1: | ||
66 | mode = HSMC_BF(DBW, HSMC_DBW_8_BITS); | ||
67 | break; | ||
68 | case 2: | ||
69 | mode = HSMC_BF(DBW, HSMC_DBW_16_BITS); | ||
70 | break; | ||
71 | case 4: | ||
72 | mode = HSMC_BF(DBW, HSMC_DBW_32_BITS); | ||
73 | break; | ||
74 | default: | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | |||
78 | if (config->nrd_controlled) | ||
79 | mode |= HSMC_BIT(READ_MODE); | ||
80 | if (config->nwe_controlled) | ||
81 | mode |= HSMC_BIT(WRITE_MODE); | ||
82 | if (config->byte_write) | ||
83 | mode |= HSMC_BIT(BAT); | ||
84 | |||
85 | pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n", | ||
86 | cs, setup, pulse, cycle, mode); | ||
87 | |||
88 | offset = cs * 0x10; | ||
89 | hsmc_writel(hsmc, SETUP0 + offset, setup); | ||
90 | hsmc_writel(hsmc, PULSE0 + offset, pulse); | ||
91 | hsmc_writel(hsmc, CYCLE0 + offset, cycle); | ||
92 | hsmc_writel(hsmc, MODE0 + offset, mode); | ||
93 | hsmc_readl(hsmc, MODE0); /* I/O barrier */ | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | EXPORT_SYMBOL(smc_set_configuration); | ||
98 | |||
99 | static int hsmc_probe(struct platform_device *pdev) | ||
100 | { | ||
101 | struct resource *regs; | ||
102 | struct clk *pclk, *mck; | ||
103 | int ret; | ||
104 | |||
105 | if (hsmc) | ||
106 | return -EBUSY; | ||
107 | |||
108 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
109 | if (!regs) | ||
110 | return -ENXIO; | ||
111 | pclk = clk_get(&pdev->dev, "pclk"); | ||
112 | if (IS_ERR(pclk)) | ||
113 | return PTR_ERR(pclk); | ||
114 | mck = clk_get(&pdev->dev, "mck"); | ||
115 | if (IS_ERR(mck)) { | ||
116 | ret = PTR_ERR(mck); | ||
117 | goto out_put_pclk; | ||
118 | } | ||
119 | |||
120 | ret = -ENOMEM; | ||
121 | hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL); | ||
122 | if (!hsmc) | ||
123 | goto out_put_clocks; | ||
124 | |||
125 | clk_enable(pclk); | ||
126 | clk_enable(mck); | ||
127 | |||
128 | hsmc->pclk = pclk; | ||
129 | hsmc->mck = mck; | ||
130 | hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1); | ||
131 | if (!hsmc->regs) | ||
132 | goto out_disable_clocks; | ||
133 | |||
134 | dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n", | ||
135 | (unsigned long)regs->start); | ||
136 | |||
137 | platform_set_drvdata(pdev, hsmc); | ||
138 | |||
139 | return 0; | ||
140 | |||
141 | out_disable_clocks: | ||
142 | clk_disable(mck); | ||
143 | clk_disable(pclk); | ||
144 | kfree(hsmc); | ||
145 | out_put_clocks: | ||
146 | clk_put(mck); | ||
147 | out_put_pclk: | ||
148 | clk_put(pclk); | ||
149 | hsmc = NULL; | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static struct platform_driver hsmc_driver = { | ||
154 | .probe = hsmc_probe, | ||
155 | .driver = { | ||
156 | .name = "smc", | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static int __init hsmc_init(void) | ||
161 | { | ||
162 | return platform_driver_register(&hsmc_driver); | ||
163 | } | ||
164 | arch_initcall(hsmc_init); | ||
diff --git a/arch/avr32/mach-at32ap/hsmc.h b/arch/avr32/mach-at32ap/hsmc.h new file mode 100644 index 000000000000..5681276fafdb --- /dev/null +++ b/arch/avr32/mach-at32ap/hsmc.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Register definitions for Atmel Static Memory Controller (SMC) | ||
3 | * | ||
4 | * Copyright (C) 2006 Atmel Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #ifndef __ASM_AVR32_HSMC_H__ | ||
11 | #define __ASM_AVR32_HSMC_H__ | ||
12 | |||
13 | /* HSMC register offsets */ | ||
14 | #define HSMC_SETUP0 0x0000 | ||
15 | #define HSMC_PULSE0 0x0004 | ||
16 | #define HSMC_CYCLE0 0x0008 | ||
17 | #define HSMC_MODE0 0x000c | ||
18 | #define HSMC_SETUP1 0x0010 | ||
19 | #define HSMC_PULSE1 0x0014 | ||
20 | #define HSMC_CYCLE1 0x0018 | ||
21 | #define HSMC_MODE1 0x001c | ||
22 | #define HSMC_SETUP2 0x0020 | ||
23 | #define HSMC_PULSE2 0x0024 | ||
24 | #define HSMC_CYCLE2 0x0028 | ||
25 | #define HSMC_MODE2 0x002c | ||
26 | #define HSMC_SETUP3 0x0030 | ||
27 | #define HSMC_PULSE3 0x0034 | ||
28 | #define HSMC_CYCLE3 0x0038 | ||
29 | #define HSMC_MODE3 0x003c | ||
30 | #define HSMC_SETUP4 0x0040 | ||
31 | #define HSMC_PULSE4 0x0044 | ||
32 | #define HSMC_CYCLE4 0x0048 | ||
33 | #define HSMC_MODE4 0x004c | ||
34 | #define HSMC_SETUP5 0x0050 | ||
35 | #define HSMC_PULSE5 0x0054 | ||
36 | #define HSMC_CYCLE5 0x0058 | ||
37 | #define HSMC_MODE5 0x005c | ||
38 | |||
39 | /* Bitfields in SETUP0 */ | ||
40 | #define HSMC_NWE_SETUP_OFFSET 0 | ||
41 | #define HSMC_NWE_SETUP_SIZE 6 | ||
42 | #define HSMC_NCS_WR_SETUP_OFFSET 8 | ||
43 | #define HSMC_NCS_WR_SETUP_SIZE 6 | ||
44 | #define HSMC_NRD_SETUP_OFFSET 16 | ||
45 | #define HSMC_NRD_SETUP_SIZE 6 | ||
46 | #define HSMC_NCS_RD_SETUP_OFFSET 24 | ||
47 | #define HSMC_NCS_RD_SETUP_SIZE 6 | ||
48 | |||
49 | /* Bitfields in PULSE0 */ | ||
50 | #define HSMC_NWE_PULSE_OFFSET 0 | ||
51 | #define HSMC_NWE_PULSE_SIZE 7 | ||
52 | #define HSMC_NCS_WR_PULSE_OFFSET 8 | ||
53 | #define HSMC_NCS_WR_PULSE_SIZE 7 | ||
54 | #define HSMC_NRD_PULSE_OFFSET 16 | ||
55 | #define HSMC_NRD_PULSE_SIZE 7 | ||
56 | #define HSMC_NCS_RD_PULSE_OFFSET 24 | ||
57 | #define HSMC_NCS_RD_PULSE_SIZE 7 | ||
58 | |||
59 | /* Bitfields in CYCLE0 */ | ||
60 | #define HSMC_NWE_CYCLE_OFFSET 0 | ||
61 | #define HSMC_NWE_CYCLE_SIZE 9 | ||
62 | #define HSMC_NRD_CYCLE_OFFSET 16 | ||
63 | #define HSMC_NRD_CYCLE_SIZE 9 | ||
64 | |||
65 | /* Bitfields in MODE0 */ | ||
66 | #define HSMC_READ_MODE_OFFSET 0 | ||
67 | #define HSMC_READ_MODE_SIZE 1 | ||
68 | #define HSMC_WRITE_MODE_OFFSET 1 | ||
69 | #define HSMC_WRITE_MODE_SIZE 1 | ||
70 | #define HSMC_EXNW_MODE_OFFSET 4 | ||
71 | #define HSMC_EXNW_MODE_SIZE 2 | ||
72 | #define HSMC_BAT_OFFSET 8 | ||
73 | #define HSMC_BAT_SIZE 1 | ||
74 | #define HSMC_DBW_OFFSET 12 | ||
75 | #define HSMC_DBW_SIZE 2 | ||
76 | #define HSMC_TDF_CYCLES_OFFSET 16 | ||
77 | #define HSMC_TDF_CYCLES_SIZE 4 | ||
78 | #define HSMC_TDF_MODE_OFFSET 20 | ||
79 | #define HSMC_TDF_MODE_SIZE 1 | ||
80 | #define HSMC_PMEN_OFFSET 24 | ||
81 | #define HSMC_PMEN_SIZE 1 | ||
82 | #define HSMC_PS_OFFSET 28 | ||
83 | #define HSMC_PS_SIZE 2 | ||
84 | |||
85 | /* Constants for READ_MODE */ | ||
86 | #define HSMC_READ_MODE_NCS_CONTROLLED 0 | ||
87 | #define HSMC_READ_MODE_NRD_CONTROLLED 1 | ||
88 | |||
89 | /* Constants for WRITE_MODE */ | ||
90 | #define HSMC_WRITE_MODE_NCS_CONTROLLED 0 | ||
91 | #define HSMC_WRITE_MODE_NWE_CONTROLLED 1 | ||
92 | |||
93 | /* Constants for EXNW_MODE */ | ||
94 | #define HSMC_EXNW_MODE_DISABLED 0 | ||
95 | #define HSMC_EXNW_MODE_RESERVED 1 | ||
96 | #define HSMC_EXNW_MODE_FROZEN 2 | ||
97 | #define HSMC_EXNW_MODE_READY 3 | ||
98 | |||
99 | /* Constants for BAT */ | ||
100 | #define HSMC_BAT_BYTE_SELECT 0 | ||
101 | #define HSMC_BAT_BYTE_WRITE 1 | ||
102 | |||
103 | /* Constants for DBW */ | ||
104 | #define HSMC_DBW_8_BITS 0 | ||
105 | #define HSMC_DBW_16_BITS 1 | ||
106 | #define HSMC_DBW_32_BITS 2 | ||
107 | |||
108 | /* Bit manipulation macros */ | ||
109 | #define HSMC_BIT(name) \ | ||
110 | (1 << HSMC_##name##_OFFSET) | ||
111 | #define HSMC_BF(name,value) \ | ||
112 | (((value) & ((1 << HSMC_##name##_SIZE) - 1)) \ | ||
113 | << HSMC_##name##_OFFSET) | ||
114 | #define HSMC_BFEXT(name,value) \ | ||
115 | (((value) >> HSMC_##name##_OFFSET) \ | ||
116 | & ((1 << HSMC_##name##_SIZE) - 1)) | ||
117 | #define HSMC_BFINS(name,value,old) \ | ||
118 | (((old) & ~(((1 << HSMC_##name##_SIZE) - 1) \ | ||
119 | << HSMC_##name##_OFFSET)) | HSMC_BF(name,value)) | ||
120 | |||
121 | /* Register access macros */ | ||
122 | #define hsmc_readl(port,reg) \ | ||
123 | readl((port)->regs + HSMC_##reg) | ||
124 | #define hsmc_writel(port,reg,value) \ | ||
125 | writel((value), (port)->regs + HSMC_##reg) | ||
126 | |||
127 | #endif /* __ASM_AVR32_HSMC_H__ */ | ||
diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h new file mode 100644 index 000000000000..3732b328303d --- /dev/null +++ b/include/asm-avr32/arch-at32ap/smc.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Static Memory Controller for AT32 chips | ||
3 | * | ||
4 | * Copyright (C) 2006 Atmel Corporation | ||
5 | * | ||
6 | * Inspired by the OMAP2 General-Purpose Memory Controller interface | ||
7 | * | ||
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. | ||
11 | */ | ||
12 | #ifndef __ARCH_AT32AP_SMC_H | ||
13 | #define __ARCH_AT32AP_SMC_H | ||
14 | |||
15 | /* | ||
16 | * All timing parameters are in nanoseconds. | ||
17 | */ | ||
18 | struct smc_config { | ||
19 | /* Delay from address valid to assertion of given strobe */ | ||
20 | u16 ncs_read_setup; | ||
21 | u16 nrd_setup; | ||
22 | u16 ncs_write_setup; | ||
23 | u16 nwe_setup; | ||
24 | |||
25 | /* Pulse length of given strobe */ | ||
26 | u16 ncs_read_pulse; | ||
27 | u16 nrd_pulse; | ||
28 | u16 ncs_write_pulse; | ||
29 | u16 nwe_pulse; | ||
30 | |||
31 | /* Total cycle length of given operation */ | ||
32 | u16 read_cycle; | ||
33 | u16 write_cycle; | ||
34 | |||
35 | /* Bus width in bytes */ | ||
36 | u8 bus_width; | ||
37 | |||
38 | /* | ||
39 | * 0: Data is sampled on rising edge of NCS | ||
40 | * 1: Data is sampled on rising edge of NRD | ||
41 | */ | ||
42 | unsigned int nrd_controlled:1; | ||
43 | |||
44 | /* | ||
45 | * 0: Data is driven on falling edge of NCS | ||
46 | * 1: Data is driven on falling edge of NWR | ||
47 | */ | ||
48 | unsigned int nwe_controlled:1; | ||
49 | |||
50 | /* | ||
51 | * 0: Byte select access type | ||
52 | * 1: Byte write access type | ||
53 | */ | ||
54 | unsigned int byte_write:1; | ||
55 | }; | ||
56 | |||
57 | extern int smc_set_configuration(int cs, const struct smc_config *config); | ||
58 | extern struct smc_config *smc_get_configuration(int cs); | ||
59 | |||
60 | #endif /* __ARCH_AT32AP_SMC_H */ | ||