]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/pcmcia/arm/ipaq/v2_0/src/ipaq_pcmcia.c
Initial revision
[karo-tx-redboot.git] / packages / devs / pcmcia / arm / ipaq / v2_0 / src / ipaq_pcmcia.c
1 //==========================================================================
2 //
3 //      devs/pcmcia/ipaq/ipaq_pcmcia.c
4 //
5 //      PCMCIA support (Card Services)
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 //               richard.panton@3glab.com
47 // Date:         2001-02-24
48 // Purpose:      PCMCIA support
49 // Description: 
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55 #include <pkgconf/io_pcmcia.h>
56
57 #include <cyg/hal/hal_io.h>             // IO macros
58 #include <cyg/hal/hal_arch.h>           // Register state info
59 #include <cyg/hal/hal_intr.h>           // HAL interrupt macros
60 #include <cyg/hal/drv_api.h>
61
62 #ifdef CYGPKG_KERNEL
63 #include <pkgconf/kernel.h>   // Configuration header
64 #include <cyg/kernel/kapi.h>
65 #endif
66 #include <cyg/hal/hal_if.h>
67
68 #include <cyg/io/pcmcia.h>
69 #include <cyg/infra/diag.h>
70
71 #include <cyg/hal/hal_sa11x0.h>  // Board definitions
72 #include <cyg/hal/ipaq.h>
73
74 #ifdef CYGPKG_KERNEL
75 static cyg_interrupt cf_detect_interrupt;
76 static cyg_handle_t  cf_detect_interrupt_handle;
77 static cyg_interrupt cf_irq_interrupt;
78 static cyg_handle_t  cf_irq_interrupt_handle;
79
80 // This ISR is called when a CompactFlash board is inserted
81 static int
82 cf_detect_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
83 {
84     cyg_drv_interrupt_mask(SA1110_CF_DETECT);
85     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
86 }
87
88 // This DSR handles the board insertion
89 static void
90 cf_detect_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
91 {
92     unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL;
93     struct cf_slot *slot = (struct cf_slot *)data;
94     if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) {
95         slot->state = CF_SLOT_STATE_Inserted;
96     } else {
97         slot->state = CF_SLOT_STATE_Removed;  // Implies powered up, etc.
98     }
99     cyg_drv_interrupt_acknowledge(SA1110_CF_DETECT);
100     cyg_drv_interrupt_unmask(SA1110_CF_DETECT);
101 }
102
103 // This ISR is called when the card interrupt occurs
104 static int
105 cf_irq_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
106 {
107     cyg_drv_interrupt_mask(SA1110_CF_IRQ);
108     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
109 }
110
111 // This DSR handles the card interrupt
112 static void
113 cf_irq_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
114 {
115     struct cf_slot *slot = (struct cf_slot *)data;
116 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
117     cyg_bool was_ctrlc_int;
118 #endif
119
120     // Clear interrupt [edge indication]
121     cyg_drv_interrupt_acknowledge(SA1110_CF_IRQ);
122 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
123     was_ctrlc_int = HAL_CTRLC_CHECK(vector, data);
124     if (!was_ctrlc_int) // Fall through and run normal code
125 #endif
126     // Process interrupt
127     (slot->irq_handler.handler)(vector, count, slot->irq_handler.param);
128     // Allow interrupts to happen again
129     cyg_drv_interrupt_unmask(SA1110_CF_IRQ);
130 }
131 #endif
132
133 static void
134 do_delay(int ticks)
135 {
136 #ifdef CYGPKG_KERNEL
137     cyg_thread_delay(ticks);
138 #else
139     CYGACC_CALL_IF_DELAY_US(10000*ticks);
140 #endif
141 }
142
143 //
144 // Fill in the details of a PCMCIA slot and initialize the device
145 //
146 void
147 cf_hwr_init(struct cf_slot *slot)
148 {
149     static int int_init = 0;
150     unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL;
151
152     if (!int_init) {
153         int_init = 1;
154 #ifdef CYGPKG_KERNEL
155         // Set up interrupts
156         cyg_drv_interrupt_create(SA1110_CF_DETECT,
157                                  99,                     // Priority - what goes here?
158                                  (cyg_addrword_t) slot,  //  Data item passed to interrupt handler
159                                  (cyg_ISR_t *)cf_detect_isr,
160                                  (cyg_DSR_t *)cf_detect_dsr,
161                                  &cf_detect_interrupt_handle,
162                                  &cf_detect_interrupt);
163         cyg_drv_interrupt_attach(cf_detect_interrupt_handle);
164         cyg_drv_interrupt_configure(SA1110_CF_DETECT, true, true);  // Detect either edge
165         cyg_drv_interrupt_acknowledge(SA1110_CF_DETECT);
166         cyg_drv_interrupt_unmask(SA1110_CF_DETECT);
167
168         cyg_drv_interrupt_create(SA1110_CF_IRQ,
169                                  99,                     // Priority - what goes here?
170                                  (cyg_addrword_t) slot,  //  Data item passed to interrupt handler
171                                  (cyg_ISR_t *)cf_irq_isr,
172                                  (cyg_DSR_t *)cf_irq_dsr,
173                                  &cf_irq_interrupt_handle,
174                                  &cf_irq_interrupt);
175         cyg_drv_interrupt_attach(cf_irq_interrupt_handle);
176         cyg_drv_interrupt_unmask(SA1110_CF_IRQ);
177         cyg_drv_interrupt_configure(SA1110_CF_IRQ, false, false);  // Falling edge
178         cyg_drv_interrupt_acknowledge(SA1110_CF_IRQ);
179 #endif
180     }
181     slot->attr = (unsigned char *)0x28000000;
182     slot->attr_length = 0x200;
183     slot->io = (unsigned char *)0x20000000;
184     slot->io_length = 0x04000000;
185     slot->mem = (unsigned char *)0x2C000000;
186     slot->mem_length = 0x04000000;
187     slot->int_num = SA1110_CF_IRQ;
188 #ifdef CYG_HAL_STARTUP_ROM
189     // Disable CF bus & power (idle/off)
190     ipaq_EGPIO( SA1110_EIO_OPT_PWR | SA1110_EIO_OPT | SA1110_EIO_CF_RESET,
191                 SA1110_EIO_OPT_PWR_ON | SA1110_EIO_OPT_ON | SA1110_EIO_CF_RESET_ENABLE );
192 #endif
193     if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) {
194         if ((_ipaq_EGPIO & SA1110_EIO_OPT_PWR) == SA1110_EIO_OPT_PWR_ON) {
195             // Assume that the ROM environment has turned the bus on
196             slot->state = CF_SLOT_STATE_Ready;
197         } else {
198             slot->state = CF_SLOT_STATE_Inserted;
199         }
200     } else {
201         slot->state = CF_SLOT_STATE_Empty;
202     }
203 }
204
205 void
206 cf_hwr_poll(struct cf_slot *slot)
207 {
208     unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL;
209     if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) {
210         slot->state = CF_SLOT_STATE_Inserted;
211     } else {
212         slot->state = CF_SLOT_STATE_Empty;
213     }
214 }
215
216 //
217 // Transition the card/slot to a new state
218 // note: currently only supports transitions to Ready, Empty
219 //
220 void
221 cf_hwr_change_state(struct cf_slot *slot, int new_state)
222 {    
223     int i, ptr, len;
224     unsigned char buf[256];
225
226     if (new_state == CF_SLOT_STATE_Ready) {
227         if (slot->state == CF_SLOT_STATE_Inserted) {
228             ipaq_EGPIO( SA1110_EIO_OPT_PWR | SA1110_EIO_OPT | SA1110_EIO_CF_RESET,
229                         SA1110_EIO_OPT_PWR_ON | SA1110_EIO_OPT_ON | SA1110_EIO_CF_RESET_DISABLE);
230             do_delay(30);  // At least 300 ms
231             slot->state = CF_SLOT_STATE_Powered;
232             ipaq_EGPIO( SA1110_EIO_CF_RESET, SA1110_EIO_CF_RESET_ENABLE);
233             *(volatile unsigned short *)IPAQ_CF_CTRL = IPAQ_CF_CTRL_V5_DISABLE | 
234                                                        IPAQ_CF_CTRL_V3_ENABLE | 
235                                                        IPAQ_CF_CTRL_RESET_ENABLE | 
236                                                        IPAQ_CF_CTRL_APOE_ENABLE | 
237                                                        IPAQ_CF_CTRL_SOE_ENABLE;
238             do_delay(1);  // At least 10 us
239             slot->state = CF_SLOT_STATE_Reset;
240             ipaq_EGPIO( SA1110_EIO_CF_RESET, SA1110_EIO_CF_RESET_DISABLE);
241             do_delay(5); // At least 20 ms
242             // This is necessary for the two slot sleeve and doesn't seem to
243             // hurt on the single slot versions.  Note: only 3.3V is ever used!
244             *(volatile unsigned short *)IPAQ_CF_CTRL = IPAQ_CF_CTRL_V5_DISABLE | 
245                                                        IPAQ_CF_CTRL_V3_ENABLE | 
246                                                        IPAQ_CF_CTRL_RESET_DISABLE | 
247                                                        IPAQ_CF_CTRL_APOE_ENABLE | 
248                                                        IPAQ_CF_CTRL_SOE_ENABLE;
249             do_delay(5); // At least 20 ms
250             // Wait until the card is ready to talk
251             for (i = 0;  i < 10;  i++) {
252                 ptr = 0;
253                 if (cf_get_CIS(slot, CF_CISTPL_VERS_1, buf, &len, &ptr)) {
254                     slot->state = CF_SLOT_STATE_Ready;
255                     break;
256                 }
257                 do_delay(10); 
258             }
259         }
260     }
261 }
262
263 //
264 // Acknowledge interrupt (used in non-kernel environments)
265 //
266 void
267 cf_hwr_clear_interrupt(struct cf_slot *slot)
268 {
269     // Clear interrupt [edge indication]
270     cyg_drv_interrupt_acknowledge(SA1110_CF_IRQ);
271 }