diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-04-11 08:51:27 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-04-11 08:51:27 +0000 |
commit | 0b1d7e76d751b9659f4d25be72143cd491704b7e (patch) | |
tree | 0197590c2f32ab7927df1360b86c2fff7902d20f /firmware/target/arm | |
parent | f46a7533a4b53de235c8adf78103e9754909ec7d (diff) | |
download | rockbox-0b1d7e76d751b9659f4d25be72143cd491704b7e.tar.gz rockbox-0b1d7e76d751b9659f4d25be72143cd491704b7e.zip |
Serial driver for imx31. Perhaps not 100% but maybe 80-90% (future developments will tell). Factor-out the mc13783 stuff and make that driver a layer above the SPI. TODO: start processing PMIC interrupts. Start a clkctl API for imx31 (we'll see if this sticks around but it seems reasonable here). Misc. stuff for convenience/neatness.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17070 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c | 10 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c | 45 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h | 86 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c | 19 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | 173 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/spi-imx31.c | 355 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/spi-imx31.h | 56 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-target.h | 3 |
8 files changed, 687 insertions, 60 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c index fc9abdb0e9..051b1c8479 100644 --- a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include "backlight.h" | 23 | #include "backlight.h" |
24 | #include "lcd.h" | 24 | #include "lcd.h" |
25 | #include "power.h" | 25 | #include "power.h" |
26 | #include "spi-imx31.h" | 26 | #include "mc13783.h" |
27 | #include "debug.h" | 27 | #include "debug.h" |
28 | 28 | ||
29 | bool _backlight_init(void) | 29 | bool _backlight_init(void) |
@@ -33,14 +33,14 @@ bool _backlight_init(void) | |||
33 | 33 | ||
34 | void _backlight_on(void) | 34 | void _backlight_on(void) |
35 | { | 35 | { |
36 | // This relies on the SPI interface being initialised already | 36 | /* LEDEN=1 */ |
37 | spi_send(51, 1); | 37 | mc13783_set(MC13783_LED_CONTROL0, (1 << 0)); |
38 | } | 38 | } |
39 | 39 | ||
40 | void _backlight_off(void) | 40 | void _backlight_off(void) |
41 | { | 41 | { |
42 | // This relies on the SPI interface being initialised already | 42 | /* LEDEN=0 */ |
43 | spi_send(51, 0); | 43 | mc13783_clear(MC13783_LED_CONTROL0, (1 << 0)); |
44 | } | 44 | } |
45 | 45 | ||
46 | /* Assumes that the backlight has been initialized */ | 46 | /* Assumes that the backlight has been initialized */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c b/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c new file mode 100644 index 0000000000..a01fab07d0 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (c) 2008 Michael Sevakis | ||
11 | * | ||
12 | * Clock control functions for IMX31 processor | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "system.h" | ||
22 | #include "cpu.h" | ||
23 | #include "clkctl-imx31.h" | ||
24 | |||
25 | void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg, | ||
26 | enum IMX31_CG_MODES mode) | ||
27 | { | ||
28 | volatile unsigned long *reg; | ||
29 | unsigned long mask; | ||
30 | int shift; | ||
31 | int oldlevel; | ||
32 | |||
33 | if (cg >= CG_NUM_CLOCKS) | ||
34 | return; | ||
35 | |||
36 | reg = &CLKCTL_CGR0 + cg / 16; /* Select CGR0, CGR1, CGR2 */ | ||
37 | shift = 2*(cg % 16); /* Get field shift */ | ||
38 | mask = CG_MASK << shift; /* Select field */ | ||
39 | |||
40 | oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS); | ||
41 | |||
42 | *reg = (*reg & ~mask) | ((mode << shift) & mask); | ||
43 | |||
44 | restore_interrupt(oldlevel); | ||
45 | } | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h b/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h new file mode 100644 index 0000000000..da15ef2706 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (c) 2008 Michael Sevakis | ||
11 | * | ||
12 | * Clock control functions for IMX31 processor | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _CLKCTL_IMX31_H_ | ||
22 | #define _CLKCTL_IMX31_H_ | ||
23 | |||
24 | enum IMX31_CG_LIST | ||
25 | { | ||
26 | /* CGR0 */ | ||
27 | CG_SD_MMC1 = 0, | ||
28 | CG_SD_MMC2, | ||
29 | CG_GPT, | ||
30 | CG_EPIT1, | ||
31 | CG_EPIT2, | ||
32 | CG_IIM, | ||
33 | CG_ATA, | ||
34 | CG_SDMA, | ||
35 | CG_CSPI3, | ||
36 | CG_RNG, | ||
37 | CG_UART1, | ||
38 | CG_UART2, | ||
39 | CG_SSI1, | ||
40 | CG_I2C1, | ||
41 | CG_I2C2, | ||
42 | CG_I2C3, | ||
43 | /* CGR1 */ | ||
44 | CG_HANTRO, | ||
45 | CG_MEMSTICK1, | ||
46 | CG_MEMSTICK2, | ||
47 | CG_CSI, | ||
48 | CG_RTC, | ||
49 | CG_WDOG, | ||
50 | CG_PWM, | ||
51 | CG_SIM, | ||
52 | CG_ECT, | ||
53 | CG_USBOTG, | ||
54 | CG_KPP, | ||
55 | CG_IPU, | ||
56 | CG_UART3, | ||
57 | CG_UART4, | ||
58 | CG_UART5, | ||
59 | CG_1_WIRE, | ||
60 | /* CGR2 */ | ||
61 | CG_SSI2, | ||
62 | CG_CSPI1, | ||
63 | CG_CSPI2, | ||
64 | CG_GACC, | ||
65 | CG_EMI, | ||
66 | CG_RTIC, | ||
67 | CG_FIR, | ||
68 | CG_NUM_CLOCKS | ||
69 | }; | ||
70 | |||
71 | enum IMX31_CG_MODES | ||
72 | { | ||
73 | CGM_OFF = 0x0, /* Always off */ | ||
74 | CGM_ON_RUN = 0x1, /* On in run mode, off in wait and doze */ | ||
75 | CGM_ON_RUN_WAIT = 0x2, /* On in run and wait modes, off in doze */ | ||
76 | CGM_ON_ALL = 0x3, /* Always on */ | ||
77 | }; | ||
78 | |||
79 | #define CG_MASK 0x3 /* bitmask */ | ||
80 | |||
81 | /* Enable or disable module clocks independently - module must _not_ be | ||
82 | * active! */ | ||
83 | void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg, | ||
84 | enum IMX31_CG_MODES mode); | ||
85 | |||
86 | #endif /* _CLKCTL_IMX31_H_ */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c b/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c index aaa4bde0eb..f0f578b03e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include "config.h" | 19 | #include "config.h" |
20 | #include "system.h" | 20 | #include "system.h" |
21 | #include "avic-imx31.h" | 21 | #include "avic-imx31.h" |
22 | #include "spi-imx31.h" | ||
23 | #include "mc13783.h" | ||
24 | #include "clkctl-imx31.h" | ||
22 | #include "kernel.h" | 25 | #include "kernel.h" |
23 | #include "thread.h" | 26 | #include "thread.h" |
24 | 27 | ||
@@ -42,10 +45,11 @@ static __attribute__((interrupt("IRQ"))) void EPIT1_HANDLER(void) | |||
42 | 45 | ||
43 | void tick_start(unsigned int interval_in_ms) | 46 | void tick_start(unsigned int interval_in_ms) |
44 | { | 47 | { |
45 | CLKCTL_CGR0 |= CGR0_EPIT1(CG_ON_ALL); /* EPIT1 module clock ON - | 48 | imx31_clkctl_module_clock_gating(CG_EPIT1, CGM_ON_ALL); /* EPIT1 module |
46 | before writing regs! */ | 49 | clock ON - before writing |
50 | regs! */ | ||
47 | EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable the counter */ | 51 | EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable the counter */ |
48 | CLKCTL_WIMR0 &= ~(1 << 23); /* Clear wakeup mask */ | 52 | CLKCTL_WIMR0 &= ~WIM_IPI_INT_EPIT1; /* Clear wakeup mask */ |
49 | 53 | ||
50 | /* mcu_main_clk = 528MHz = 27MHz * 2 * ((9 + 7/9) / 1) | 54 | /* mcu_main_clk = 528MHz = 27MHz * 2 * ((9 + 7/9) / 1) |
51 | * CLKSRC = ipg_clk = 528MHz / 4 / 2 = 66MHz, | 55 | * CLKSRC = ipg_clk = 528MHz / 4 / 2 = 66MHz, |
@@ -66,11 +70,18 @@ void tick_start(unsigned int interval_in_ms) | |||
66 | EPITCR1 |= EPITCR_EN; /* Enable the counter */ | 70 | EPITCR1 |= EPITCR_EN; /* Enable the counter */ |
67 | } | 71 | } |
68 | 72 | ||
73 | void kernel_device_init(void) | ||
74 | { | ||
75 | spi_init(); | ||
76 | mc13783_init(); | ||
77 | } | ||
78 | |||
69 | #ifdef BOOTLOADER | 79 | #ifdef BOOTLOADER |
70 | void tick_stop(void) | 80 | void tick_stop(void) |
71 | { | 81 | { |
72 | avic_disable_int(EPIT1); /* Disable insterrupt */ | 82 | avic_disable_int(EPIT1); /* Disable insterrupt */ |
73 | EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable counter */ | 83 | EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable counter */ |
74 | CLKCTL_CGR0 &= ~CGR0_EPIT1(CG_MASK); /* EPIT1 module clock OFF */ | 84 | EPITSR1 = EPITSR_OCIF; /* Clear pending */ |
85 | imx31_clkctl_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */ | ||
75 | } | 86 | } |
76 | #endif | 87 | #endif |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c new file mode 100644 index 0000000000..3af8f35f69 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (c) 2008 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "system.h" | ||
20 | #include "cpu.h" | ||
21 | #include "spi-imx31.h" | ||
22 | #include "mc13783.h" | ||
23 | #include "debug.h" | ||
24 | #include "kernel.h" | ||
25 | |||
26 | /* This is all based on communicating with the MC13783 PMU which is on | ||
27 | * CSPI2 with the chip select at 0. The LCD controller resides on | ||
28 | * CSPI3 cs1, but we have no idea how to communicate to it */ | ||
29 | static struct spi_node mc13783_spi = | ||
30 | { | ||
31 | CSPI2_NUM, /* CSPI module 2 */ | ||
32 | CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */ | ||
33 | CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */ | ||
34 | CSPI_CONREG_DATA_RATE_DIV_4 | /* Clock = IPG_CLK/4 - 16.5MHz */ | ||
35 | CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */ | ||
36 | CSPI_CONREG_SSPOL | /* SS active high */ | ||
37 | CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */ | ||
38 | CSPI_CONREG_MODE, /* Master mode */ | ||
39 | 0, /* SPI clock - no wait states */ | ||
40 | }; | ||
41 | |||
42 | static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; | ||
43 | static const char *mc13783_thread_name = "pmic"; | ||
44 | static struct wakeup mc13783_wake; | ||
45 | |||
46 | static __attribute__((noreturn)) void mc13783_interrupt_thread(void) | ||
47 | { | ||
48 | while (1) | ||
49 | { | ||
50 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | static __attribute__((interrupt("IRQ"))) void mc13783_interrupt(void) | ||
55 | { | ||
56 | wakeup_signal(&mc13783_wake); | ||
57 | } | ||
58 | |||
59 | void mc13783_init(void) | ||
60 | { | ||
61 | /* Serial interface must have been initialized first! */ | ||
62 | wakeup_init(&mc13783_wake); | ||
63 | |||
64 | /* Enable the PMIC SPI module */ | ||
65 | spi_enable_module(&mc13783_spi); | ||
66 | |||
67 | create_thread(mc13783_interrupt_thread, mc13783_thread_stack, | ||
68 | sizeof(mc13783_thread_stack), 0, mc13783_thread_name | ||
69 | IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); | ||
70 | } | ||
71 | |||
72 | void mc13783_set(unsigned address, uint32_t bits) | ||
73 | { | ||
74 | spi_lock(&mc13783_spi); | ||
75 | uint32_t data = mc13783_read(address); | ||
76 | mc13783_write(address, data | bits); | ||
77 | spi_unlock(&mc13783_spi); | ||
78 | } | ||
79 | |||
80 | void mc13783_clear(unsigned address, uint32_t bits) | ||
81 | { | ||
82 | spi_lock(&mc13783_spi); | ||
83 | uint32_t data = mc13783_read(address); | ||
84 | mc13783_write(address, data & ~bits); | ||
85 | spi_unlock(&mc13783_spi); | ||
86 | } | ||
87 | |||
88 | int mc13783_write(unsigned address, uint32_t data) | ||
89 | { | ||
90 | struct spi_transfer xfer; | ||
91 | uint32_t packet; | ||
92 | |||
93 | if (address >= MC13783_NUM_REGS) | ||
94 | return -1; | ||
95 | |||
96 | packet = (1 << 31) | (address << 25) | (data & 0xffffff); | ||
97 | xfer.txbuf = &packet; | ||
98 | xfer.rxbuf = &packet; | ||
99 | xfer.count = 1; | ||
100 | |||
101 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
102 | return -1; | ||
103 | |||
104 | return 1 - xfer.count; | ||
105 | } | ||
106 | |||
107 | int mc13783_write_multiple(unsigned start, const uint32_t *data, int count) | ||
108 | { | ||
109 | int i; | ||
110 | struct spi_transfer xfer; | ||
111 | uint32_t packets[64]; | ||
112 | |||
113 | if (start + count > MC13783_NUM_REGS) | ||
114 | return -1; | ||
115 | |||
116 | /* Prepare payload */ | ||
117 | for (i = 0; i < count; i++, start++) | ||
118 | { | ||
119 | packets[i] = (1 << 31) | (start << 25) | (data[i] & 0xffffff); | ||
120 | } | ||
121 | |||
122 | xfer.txbuf = packets; | ||
123 | xfer.rxbuf = packets; | ||
124 | xfer.count = count; | ||
125 | |||
126 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
127 | return -1; | ||
128 | |||
129 | return count - xfer.count; | ||
130 | } | ||
131 | |||
132 | uint32_t mc13783_read(unsigned address) | ||
133 | { | ||
134 | uint32_t packet; | ||
135 | struct spi_transfer xfer; | ||
136 | |||
137 | if (address >= MC13783_NUM_REGS) | ||
138 | return (uint32_t)-1; | ||
139 | |||
140 | packet = address << 25; | ||
141 | |||
142 | xfer.txbuf = &packet; | ||
143 | xfer.rxbuf = &packet; | ||
144 | xfer.count = 1; | ||
145 | |||
146 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
147 | return (uint32_t)-1; | ||
148 | |||
149 | return packet & 0xffffff; | ||
150 | } | ||
151 | |||
152 | int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count) | ||
153 | { | ||
154 | int i; | ||
155 | uint32_t packets[64]; | ||
156 | struct spi_transfer xfer; | ||
157 | |||
158 | if (start + count > MC13783_NUM_REGS) | ||
159 | return -1; | ||
160 | |||
161 | xfer.txbuf = packets; | ||
162 | xfer.rxbuf = buffer; | ||
163 | xfer.count = count; | ||
164 | |||
165 | /* Prepare TX payload */ | ||
166 | for (i = 0; i < count; i++, start++) | ||
167 | packets[i] = start << 25; | ||
168 | |||
169 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
170 | return -1; | ||
171 | |||
172 | return count - xfer.count; | ||
173 | } | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c index 10ee3f44c0..bcbe85a76b 100644 --- a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c | |||
@@ -18,66 +18,325 @@ | |||
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include "cpu.h" | 19 | #include "cpu.h" |
20 | #include "spi-imx31.h" | 20 | #include "spi-imx31.h" |
21 | #include "avic-imx31.h" | ||
22 | #include "clkctl-imx31.h" | ||
21 | #include "debug.h" | 23 | #include "debug.h" |
22 | #include "kernel.h" | 24 | #include "kernel.h" |
23 | 25 | ||
24 | /* This is all based on communicating with the MC13783 PMU which is on | 26 | /* Forward interrupt handler declarations */ |
25 | * CSPI2 with the chip select at 0. The LCD controller resides on | 27 | #if (SPI_MODULE_MASK & USE_CSPI1_MODULE) |
26 | * CSPI3 cs1, but we have no idea how to communicate to it */ | 28 | static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void); |
27 | 29 | #endif | |
28 | void spi_init(void) { | 30 | #if (SPI_MODULE_MASK & USE_CSPI2_MODULE) |
29 | CSPI_CONREG2 |= (2 << 20); // Burst will be triggered at SPI_RDY low | 31 | static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void); |
30 | CSPI_CONREG2 |= (2 << 16); // Clock = IPG_CLK/16 - we want about 20mhz | 32 | #endif |
31 | CSPI_CONREG2 |= (31 << 8); // All 32 bits are to be transferred | 33 | #if (SPI_MODULE_MASK & USE_CSPI3_MODULE) |
32 | CSPI_CONREG2 |= (1 << 3); // Start burst on TXFIFO write. | 34 | static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void); |
33 | CSPI_CONREG2 |= (1 << 1); // Master mode. | 35 | #endif |
34 | CSPI_CONREG2 |= 1; // Enable CSPI2; | 36 | |
37 | /* State data associatated with each CSPI module */ | ||
38 | static struct spi_module_descriptor | ||
39 | { | ||
40 | volatile unsigned long *base; | ||
41 | int enab; | ||
42 | struct spi_node *last; | ||
43 | enum IMX31_CG_LIST cg; | ||
44 | enum IMX31_INT_LIST ints; | ||
45 | int byte_size; | ||
46 | void (*handler)(void); | ||
47 | struct mutex m; | ||
48 | struct wakeup w; | ||
49 | struct spi_transfer *trans; | ||
50 | int rxcount; | ||
51 | } spi_descs[SPI_NUM_CSPI] = | ||
52 | /* Init non-zero members */ | ||
53 | { | ||
54 | #if (SPI_MODULE_MASK & USE_CSPI1_MODULE) | ||
55 | { | ||
56 | .base = (unsigned long *)CSPI1_BASE_ADDR, | ||
57 | .cg = CG_CSPI1, | ||
58 | .ints = CSPI1, | ||
59 | .handler = CSPI1_HANDLER, | ||
60 | }, | ||
61 | #endif | ||
62 | #if (SPI_MODULE_MASK & USE_CSPI2_MODULE) | ||
63 | { | ||
64 | .base = (unsigned long *)CSPI2_BASE_ADDR, | ||
65 | .cg = CG_CSPI2, | ||
66 | .ints = CSPI2, | ||
67 | .handler = CSPI2_HANDLER, | ||
68 | }, | ||
69 | #endif | ||
70 | #if (SPI_MODULE_MASK & USE_CSPI3_MODULE) | ||
71 | { | ||
72 | .base = (unsigned long *)CSPI3_BASE_ADDR, | ||
73 | .cg = CG_CSPI3, | ||
74 | .ints = CSPI3, | ||
75 | .handler = CSPI3_HANDLER, | ||
76 | }, | ||
77 | #endif | ||
78 | }; | ||
79 | |||
80 | /* Common code for interrupt handlers */ | ||
81 | static void spi_interrupt(enum spi_module_number spi) | ||
82 | { | ||
83 | struct spi_module_descriptor *desc = &spi_descs[spi]; | ||
84 | volatile unsigned long * const base = desc->base; | ||
85 | struct spi_transfer *trans = desc->trans; | ||
86 | int inc = desc->byte_size + 1; | ||
87 | |||
88 | if (desc->rxcount > 0) | ||
89 | { | ||
90 | /* Data received - empty out RXFIFO */ | ||
91 | while ((base[CSPI_STATREG_I] & CSPI_STATREG_RR) != 0) | ||
92 | { | ||
93 | uint32_t word = base[CSPI_RXDATA_I]; | ||
94 | |||
95 | switch (desc->byte_size & 3) | ||
96 | { | ||
97 | case 3: | ||
98 | *(unsigned char *)(trans->rxbuf + 3) = word >> 24; | ||
99 | case 2: | ||
100 | *(unsigned char *)(trans->rxbuf + 2) = word >> 16; | ||
101 | case 1: | ||
102 | *(unsigned char *)(trans->rxbuf + 1) = word >> 8; | ||
103 | case 0: | ||
104 | *(unsigned char *)(trans->rxbuf + 0) = word; | ||
105 | } | ||
106 | |||
107 | trans->rxbuf += inc; | ||
108 | |||
109 | if (--desc->rxcount < 4) | ||
110 | { | ||
111 | unsigned long intreg = base[CSPI_INTREG_I]; | ||
112 | |||
113 | if (desc->rxcount <= 0) | ||
114 | { | ||
115 | /* No more to receive - stop RX interrupts */ | ||
116 | intreg &= ~(CSPI_INTREG_RHEN | CSPI_INTREG_RREN); | ||
117 | base[CSPI_INTREG_I] = intreg; | ||
118 | break; | ||
119 | } | ||
120 | else if (!(intreg & CSPI_INTREG_RREN)) | ||
121 | { | ||
122 | /* < 4 words expected - switch to RX ready */ | ||
123 | intreg &= ~CSPI_INTREG_RHEN; | ||
124 | base[CSPI_INTREG_I] = intreg | CSPI_INTREG_RREN; | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if (trans->count > 0) | ||
131 | { | ||
132 | /* Data to transmit - fill TXFIFO or write until exhausted */ | ||
133 | while ((base[CSPI_STATREG_I] & CSPI_STATREG_TF) == 0) | ||
134 | { | ||
135 | uint32_t word = 0; | ||
136 | |||
137 | switch (desc->byte_size & 3) | ||
138 | { | ||
139 | case 3: | ||
140 | word = *(unsigned char *)(trans->txbuf + 3) << 24; | ||
141 | case 2: | ||
142 | word |= *(unsigned char *)(trans->txbuf + 2) << 16; | ||
143 | case 1: | ||
144 | word |= *(unsigned char *)(trans->txbuf + 1) << 8; | ||
145 | case 0: | ||
146 | word |= *(unsigned char *)(trans->txbuf + 0); | ||
147 | } | ||
148 | |||
149 | trans->txbuf += inc; | ||
150 | |||
151 | base[CSPI_TXDATA_I] = word; | ||
152 | |||
153 | if (--trans->count <= 0) | ||
154 | { | ||
155 | /* Out of data - stop TX interrupts */ | ||
156 | base[CSPI_INTREG_I] &= ~CSPI_INTREG_THEN; | ||
157 | break; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /* If all interrupts have been remasked - we're done */ | ||
163 | if (base[CSPI_INTREG_I] == 0) | ||
164 | { | ||
165 | base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO; | ||
166 | wakeup_signal(&desc->w); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /* Interrupt handlers for each CSPI module */ | ||
171 | #if (SPI_MODULE_MASK & USE_CSPI1_MODULE) | ||
172 | static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void) | ||
173 | { | ||
174 | spi_interrupt(CSPI1_NUM); | ||
175 | } | ||
176 | #endif | ||
177 | |||
178 | #if (SPI_MODULE_MASK & USE_CSPI2_MODULE) | ||
179 | static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void) | ||
180 | { | ||
181 | spi_interrupt(CSPI2_NUM); | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | #if (SPI_MODULE_MASK & USE_CSPI3_MODULE) | ||
186 | static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void) | ||
187 | { | ||
188 | spi_interrupt(CSPI3_NUM); | ||
189 | } | ||
190 | #endif | ||
191 | |||
192 | /* Write the context for the node and remember it to avoid unneeded reconfigure */ | ||
193 | static bool spi_set_context(struct spi_node *node, | ||
194 | struct spi_module_descriptor *desc) | ||
195 | { | ||
196 | volatile unsigned long * const base = desc->base; | ||
197 | |||
198 | if ((base[CSPI_CONREG_I] & CSPI_CONREG_EN) == 0) | ||
199 | return false; | ||
200 | |||
201 | if (node != desc->last) | ||
202 | { | ||
203 | /* Switch the module's node */ | ||
204 | desc->last = node; | ||
205 | desc->byte_size = (((node->conreg >> 8) & 0x1f) + 1 + 7) / 8 - 1; | ||
206 | |||
207 | /* Keep reserved and start bits cleared. Keep enabled bit. */ | ||
208 | base[CSPI_CONREG_I] = | ||
209 | (node->conreg & ~(0xfcc8e000 | CSPI_CONREG_XCH | CSPI_CONREG_SMC)) | ||
210 | | CSPI_CONREG_EN; | ||
211 | /* Set the wait-states */ | ||
212 | base[CSPI_PERIODREG_I] = node->periodreg & 0xffff; | ||
213 | /* Clear out any spuriously-pending interrupts */ | ||
214 | base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO; | ||
215 | } | ||
216 | |||
217 | return true; | ||
35 | } | 218 | } |
36 | 219 | ||
37 | static int spi_transfer(int address, long data, long* buffer, bool read) { | 220 | /* Initialize each of the used SPI descriptors */ |
38 | return -1; /* Disable for now - hangs - and we'll use interrupts */ | 221 | void spi_init(void) |
222 | { | ||
223 | int i; | ||
39 | 224 | ||
40 | unsigned long packet = 0; | 225 | for (i = 0; i < SPI_NUM_CSPI; i++) |
41 | if(!read) { | 226 | { |
42 | /* Set the appropriate bit in the packet to indicate a write */ | 227 | struct spi_module_descriptor * const desc = &spi_descs[i]; |
43 | packet |= (1<<31); | 228 | mutex_init(&desc->m); |
229 | wakeup_init(&desc->w); | ||
44 | } | 230 | } |
45 | /* Set the address of the packet */ | 231 | } |
46 | packet |= (address << 25); | 232 | |
47 | 233 | /* Get mutually-exclusive access to the node */ | |
48 | /* Ensure data only occupies 24 bits, then mash the data into the packet */ | 234 | void spi_lock(struct spi_node *node) |
49 | data &= ~(DATAMASK); | 235 | { |
50 | packet |= data; | 236 | mutex_lock(&spi_descs[node->num].m); |
51 | 237 | } | |
52 | /* Wait for some room in TXFIFO */ | 238 | |
53 | while(CSPI_STATREG2 & (1<<2)); | 239 | /* Release mutual exclusion */ |
54 | 240 | void spi_unlock(struct spi_node *node) | |
55 | /* Send the packet */ | 241 | { |
56 | CSPI_TXDATA2 = packet; | 242 | mutex_unlock(&spi_descs[node->num].m); |
57 | 243 | } | |
58 | /* Poll the XCH bit to wait for the end of the transfer, with | 244 | |
59 | * a one second timeout */ | 245 | /* Enable the specified module for the node */ |
60 | int newtick = current_tick + HZ; | 246 | void spi_enable_module(struct spi_node *node) |
61 | while((CSPI_CONREG2 & (1<<2)) && (current_tick < newtick)); | 247 | { |
62 | 248 | struct spi_module_descriptor * const desc = &spi_descs[node->num]; | |
63 | if(newtick > current_tick) { | 249 | |
64 | *buffer = CSPI_RXDATA2; | 250 | mutex_lock(&desc->m); |
65 | return 0; | 251 | |
66 | } else { | 252 | if (++desc->enab == 1) |
67 | /* Indicate the fact that the transfer timed out */ | 253 | { |
68 | return -1; | 254 | /* First enable for this module */ |
255 | volatile unsigned long * const base = desc->base; | ||
256 | |||
257 | /* Enable clock-gating register */ | ||
258 | imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL); | ||
259 | |||
260 | /* Reset */ | ||
261 | base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN; | ||
262 | base[CSPI_CONREG_I] |= CSPI_CONREG_EN; | ||
263 | base[CSPI_INTREG_I] = 0; | ||
264 | base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO; | ||
265 | |||
266 | /* Enable interrupt at controller level */ | ||
267 | avic_enable_int(desc->ints, IRQ, 6, desc->handler); | ||
69 | } | 268 | } |
269 | |||
270 | mutex_unlock(&desc->m); | ||
70 | } | 271 | } |
71 | 272 | ||
72 | void spi_send(int address, unsigned long data) { | 273 | /* Disabled the specified module for the node */ |
73 | long dummy; | 274 | void spi_disable_module(struct spi_node *node) |
74 | if(spi_transfer(address, data, &dummy, false)) { | 275 | { |
75 | DEBUGF("SPI Send timed out"); | 276 | struct spi_module_descriptor * const desc = &spi_descs[node->num]; |
277 | |||
278 | mutex_lock(&desc->m); | ||
279 | |||
280 | if (desc->enab > 0 && --desc->enab == 0) | ||
281 | { | ||
282 | /* Last enable for this module */ | ||
283 | volatile unsigned long * const base = desc->base; | ||
284 | |||
285 | /* Disable interrupt at controller level */ | ||
286 | avic_disable_int(desc->ints); | ||
287 | |||
288 | /* Disable interface */ | ||
289 | base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN; | ||
290 | |||
291 | /* Disable interface clock */ | ||
292 | imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF); | ||
76 | } | 293 | } |
294 | |||
295 | mutex_unlock(&desc->m); | ||
77 | } | 296 | } |
78 | 297 | ||
79 | void spi_read(int address, unsigned long* buffer) { | 298 | /* Send and/or receive data on the specified node */ |
80 | if(spi_transfer(address, 0, buffer, true)) { | 299 | int spi_transfer(struct spi_node *node, struct spi_transfer *trans) |
81 | DEBUGF("SPI read timed out"); | 300 | { |
301 | struct spi_module_descriptor * const desc = &spi_descs[node->num]; | ||
302 | int retval; | ||
303 | |||
304 | if (trans->count <= 0) | ||
305 | return true; | ||
306 | |||
307 | mutex_lock(&desc->m); | ||
308 | |||
309 | retval = spi_set_context(node, desc); | ||
310 | |||
311 | if (retval) | ||
312 | { | ||
313 | volatile unsigned long * const base = desc->base; | ||
314 | unsigned long intreg; | ||
315 | |||
316 | desc->trans = trans; | ||
317 | desc->rxcount = trans->count; | ||
318 | |||
319 | /* Enable needed interrupts - FIFOs will start filling */ | ||
320 | intreg = CSPI_INTREG_THEN; | ||
321 | |||
322 | intreg |= (trans->count < 4) ? | ||
323 | CSPI_INTREG_RREN : /* Must grab data on every word */ | ||
324 | CSPI_INTREG_RHEN; /* Enough data to wait for half-full */ | ||
325 | |||
326 | base[CSPI_INTREG_I] = intreg; | ||
327 | |||
328 | /* Start transfer */ | ||
329 | base[CSPI_CONREG_I] |= CSPI_CONREG_XCH; | ||
330 | |||
331 | if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) | ||
332 | { | ||
333 | base[CSPI_INTREG_I] = 0; | ||
334 | base[CSPI_CONREG_I] &= ~CSPI_CONREG_XCH; | ||
335 | retval = false; | ||
336 | } | ||
82 | } | 337 | } |
338 | |||
339 | mutex_unlock(&desc->m); | ||
340 | |||
341 | return retval; | ||
83 | } | 342 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.h b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.h index 5f6cfc984f..c17a272aaa 100644 --- a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.h +++ b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.h | |||
@@ -16,8 +16,58 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #define DATAMASK 0xFF000000 | 19 | #ifndef _SPI_IMX31_H_ |
20 | #define _SPI_IMX31_H_ | ||
20 | 21 | ||
22 | #define USE_CSPI1_MODULE (1 << 0) | ||
23 | #define USE_CSPI2_MODULE (1 << 1) | ||
24 | #define USE_CSPI3_MODULE (1 << 2) | ||
25 | |||
26 | /* SPI_MODULE_MASK is set in target's config */ | ||
27 | enum spi_module_number | ||
28 | { | ||
29 | #if (SPI_MODULE_MASK & USE_CSPI1_MODULE) | ||
30 | CSPI1_NUM = 0, | ||
31 | #endif | ||
32 | #if (SPI_MODULE_MASK & USE_CSPI2_MODULE) | ||
33 | CSPI2_NUM, | ||
34 | #endif | ||
35 | #if (SPI_MODULE_MASK & USE_CSPI3_MODULE) | ||
36 | CSPI3_NUM, | ||
37 | #endif | ||
38 | SPI_NUM_CSPI, | ||
39 | }; | ||
40 | |||
41 | struct spi_node | ||
42 | { | ||
43 | enum spi_module_number num; /* Module number (CSPIx_NUM) */ | ||
44 | unsigned long conreg; /* CSPI conreg setup */ | ||
45 | unsigned long periodreg; /* CSPI periodreg setup */ | ||
46 | }; | ||
47 | |||
48 | struct spi_transfer | ||
49 | { | ||
50 | const void *txbuf; | ||
51 | void *rxbuf; | ||
52 | int count; | ||
53 | }; | ||
54 | |||
55 | /* One-time init of SPI driver */ | ||
21 | void spi_init(void); | 56 | void spi_init(void); |
22 | void spi_send(int address, unsigned long data); | 57 | |
23 | void spi_read(int address, unsigned long* buffer); | 58 | /* Enable the specified module for the node */ |
59 | void spi_enable_module(struct spi_node *node); | ||
60 | |||
61 | /* Disabled the specified module for the node */ | ||
62 | void spi_disable_module(struct spi_node *node); | ||
63 | |||
64 | /* Lock module mutex */ | ||
65 | void spi_lock(struct spi_node *node); | ||
66 | |||
67 | /* Unlock module mutex */ | ||
68 | void spi_unlock(struct spi_node *node); | ||
69 | |||
70 | /* Send and/or receive data on the specified node */ | ||
71 | int spi_transfer(struct spi_node *node, struct spi_transfer *trans); | ||
72 | |||
73 | #endif /* _SPI_IMX31_H_ */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h index 327d72b7bc..8db0c78eb7 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h | |||
@@ -35,6 +35,9 @@ static inline void udelay(unsigned int usecs) | |||
35 | 35 | ||
36 | void system_prepare_fw_start(void); | 36 | void system_prepare_fw_start(void); |
37 | void tick_stop(void); | 37 | void tick_stop(void); |
38 | void kernel_device_init(void); | ||
39 | |||
40 | #define KDEV_INIT | ||
38 | 41 | ||
39 | #define HAVE_INVALIDATE_ICACHE | 42 | #define HAVE_INVALIDATE_ICACHE |
40 | static inline void invalidate_icache(void) | 43 | static inline void invalidate_icache(void) |