aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2006-09-26 02:32:16 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:54 -0400
commitbc157b75960f1f33566074e820342690216629b9 (patch)
tree3f494ec585eb4bf3e7def5de2b2455b13b5c42c8 /arch/avr32
parent5f97f7f9400de47ae837170bb274e90ad3934386 (diff)
[PATCH] AVR32 MTD: Static Memory Controller driver
This patchset adds the necessary drivers and infrastructure to access the external flash on the ATSTK1000 board through the MTD subsystem. With this stuff in place, it will be possible to use a jffs2 filesystem stored in the external flash as a root filesystem. It might also be possible to update the boot loader if you drop the write protection of partition 0. As suggested by David Woodhouse, I reworked the patches to use the physmap driver instead of introducing a separate mapping driver for the ATSTK1000. I've also cleaned up the hsmc header by removing useless comments and converting spaces to tabs (my headerfile generator needs some work.) Unfortunately, I couldn't unlock the flash in fixup_use_atmel_lock because the erase regions hadn't been set up yet, so I had to do it from cfi_amdstd_setup instead. This patch: This adds a simple API for configuring the static memory controller along with an implementation for the Atmel HSMC. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/avr32')
-rw-r--r--arch/avr32/mach-at32ap/Makefile2
-rw-r--r--arch/avr32/mach-at32ap/at32ap7000.c10
-rw-r--r--arch/avr32/mach-at32ap/hsmc.c164
-rw-r--r--arch/avr32/mach-at32ap/hsmc.h127
4 files changed, 302 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 @@
1obj-y += at32ap.o clock.o pio.o intc.o extint.o 1obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o
2obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o 2obj-$(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
453static struct resource smc0_resource[] = {
454 PBMEM(0xfff03400),
455};
456DEFINE_DEV(smc, 0);
457DEV_CLK(pclk, smc0, pbb, 13);
458DEV_CLK(mck, smc0, hsb, 0);
459
453static struct platform_device pdc_device = { 460static 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
24struct hsmc {
25 void __iomem *regs;
26 struct clk *pclk;
27 struct clk *mck;
28};
29
30static struct hsmc *hsmc;
31
32int 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}
97EXPORT_SYMBOL(smc_set_configuration);
98
99static 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
141out_disable_clocks:
142 clk_disable(mck);
143 clk_disable(pclk);
144 kfree(hsmc);
145out_put_clocks:
146 clk_put(mck);
147out_put_pclk:
148 clk_put(pclk);
149 hsmc = NULL;
150 return ret;
151}
152
153static struct platform_driver hsmc_driver = {
154 .probe = hsmc_probe,
155 .driver = {
156 .name = "smc",
157 },
158};
159
160static int __init hsmc_init(void)
161{
162 return platform_driver_register(&hsmc_driver);
163}
164arch_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__ */