Rename almost all occurences of LinuxBIOS to coreboot.
[coreboot.git] / src / southbridge / ricoh / rl5c476 / rl5c476.c
1 /*
2  * (C) Copyright 2004 Nick Barker <nick.barker9@btinternet.com>
3  *
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  */
20 /* (C) Copyright 2005 Nick Barker <nick.barker@btinternet.com
21    brought into line with the current architecture of coreboot */ 
22
23
24 #include <arch/io.h>
25 #include <device/device.h>
26 #include <device/pci.h>
27 #include <device/pci_ops.h>
28 #include <device/pci_ids.h>
29 #include <console/console.h>
30 #include <device/cardbus.h>
31 #include "rl5c476.h"
32 #include "chip.h"
33
34 static int enable_cf_boot = 0;
35 static unsigned int cf_base;
36
37 static void udelay(int i){
38         for(; i > 0 ; i--)
39                 inb(0x80);
40
41 }
42
43 static void rl5c476_init(device_t dev)
44 {
45         //unsigned char enables;
46         pc16reg_t *pc16;
47
48         unsigned char *base;
49
50         /* cardbus controller function 1 for CF Socket */
51         printk_debug("rl5c476 init\n");
52
53         printk_debug("CF Base = %0x\n",cf_base);
54
55         /* misc control register */
56         pci_write_config16(dev,0x82,0x00a0);
57
58         /* set up second slot as compact flash port if asked to do so */
59         if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){ 
60
61                 /* make sure isa interrupts are enabled */
62                 pci_write_config16(dev,0x3e,0x0780);
63
64                 /* pick up where 16 bit card control structure is (0x800 bytes into config structure) */
65                 base = (unsigned char *)pci_read_config32(dev,0x10);
66                 pc16 = (pc16reg_t *)(base + 0x800);
67
68                 /* disable memory and io windows and turn off socket power */
69                 pc16->pwctrl = 0;
70
71                 /* disable irq lines */
72                 pc16->igctrl = 0;
73
74                 /* disable memory and I/O windows */
75                 pc16->awinen = 0;
76
77                 /* reset card, configure for I/O and set IRQ line */
78                 pc16->igctrl = 0x69;
79
80                 // set io window 0 for 1e0 - 1ef
81                 /* note this now sets CF up on a contiguous I/O window of 16 bytes, 0x1e0 to 0x1ef
82                    Be warned that this is not a standard IDE address as automatically detected by the likes
83                    of Filo, and would need patching to recognise these addresses as an IDE drive */
84                 /* an earlier version of this driver set up 2 io windows to emulate the expected addresses
85                    for IDE2, however the pcmcia package within Linux then could not re-initiailse the
86                    device as it tried to take control of it. So I belive it is easier to patch Filo or the like
87                    to pick up this drive rather than playing silly games as the kernel tries to boot.
88                 */
89                 pc16->iostl0 = 0xe0;
90                 pc16->iosth0 = 1;
91
92                 pc16->iospl0 = 0xef;
93                 pc16->iosph0 = 1;
94
95                 pc16->ioffl0 = 0;
96                 pc16->ioffh0 = 0;
97
98                 // clear window 1
99                 pc16->iostl1 = 0;
100                 pc16->iosth1 = 0;
101
102                 pc16->iospl1 = 0;
103                 pc16->iosph1 = 0;
104
105                 pc16->ioffl1 = 0x0;
106                 pc16->ioffh1 = 0;
107
108
109
110                 // set up CF config window
111                 pc16->smpga0 = cf_base>>24;
112                 pc16->smsth0 = (cf_base>>20)&0x0f;
113                 pc16->smstl0 = (cf_base>>12)&0xff;
114                 pc16->smsph0 = ((cf_base>>20)&0x0f) | 0x80;
115                 pc16->smspl0 = (cf_base>>12)&0xff;
116                 pc16->moffl0 = 0;
117                 pc16->moffh0 = 0x40;
118
119
120                 // set I/O width for Auto Data width
121                 pc16->ioctrl = 0x22;
122
123
124                 // enable I/O window 0 and 1
125                 pc16->awinen = 0xc1;
126
127
128                 pc16->miscc1 = 1;
129
130                 // apply power and enable outputs
131                 pc16->pwctrl = 0xb0;
132         
133
134                 // delay could be optimised, but this works
135                 udelay(100000);
136         
137                 pc16->igctrl = 0x69;
138
139
140                 // 16 bit CF always have first config byte at 0x200 into Config structure,
141                 // but CF+ May Not according to spec - should locate through reading tuple data,
142                 // but this will do for now !!!
143                 unsigned char *cptr;
144                 cptr = (unsigned char *)(cf_base + 0x200);
145                 printk_debug("CF Config = %x\n",*cptr);
146
147                 // set CF to decode 16 IO bytes on any 16 byte boundary - rely on the io
148                 // windows of the bridge set up above to map those bytes into the 
149                 // addresses for ide controller 3 (0x1e8 - 0x1ef and 0x3ed - 0x3ee)
150                 *cptr = 0x41;
151         }
152
153 }
154
155 void rl5c476_read_resources(device_t dev)
156 {
157
158         struct resource *resource;
159
160          /* for cf socket we need an extra memory window for the control structure of the cf itself */
161         if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){ 
162                 resource = new_resource(dev,1);    /* fake index as it isn't in pci config space */
163                 resource->flags |= IORESOURCE_MEM ;
164                 resource->size = 0x1000;
165                 resource->align = resource->gran = 12;
166                 resource->limit= 0xffff0000;
167                 //compute_allocate_resource(&dev->link[0],resource,resource->flags,resource->flags);
168         }
169         cardbus_read_resources(dev);
170
171 }
172
173 void rl5c476_set_resources(device_t dev)
174 {
175
176         struct resource *resource;
177         printk_debug("%s In set resources \n",dev_path(dev));
178         if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){
179                 resource = find_resource(dev,1);
180                 if( !(resource->flags & IORESOURCE_STORED) ){
181                         resource->flags |= IORESOURCE_STORED ;
182                         compute_allocate_resource(&dev->link[0],resource,resource->flags,resource->flags);
183                         printk_debug("%s 1 ==> %x\n",dev_path(dev),resource->base); 
184                         cf_base = resource->base;
185                 }
186         }
187
188         pci_dev_set_resources(dev);
189
190 }
191
192 static struct device_operations ricoh_rl5c476_ops = {
193         .read_resources   = rl5c476_read_resources,
194         .set_resources    = rl5c476_set_resources,
195         .enable_resources = cardbus_enable_resources,
196         .init             = rl5c476_init,
197         .scan_bus         = cardbus_scan_bridge,
198 };
199
200 static const struct pci_driver ricoh_rl5c476_driver __pci_driver = {
201         .ops    = &ricoh_rl5c476_ops,
202         .vendor = PCI_VENDOR_ID_RICOH,
203         .device = PCI_DEVICE_ID_RICOH_RL5C476,
204 };
205
206 void southbridge_init(device_t dev)
207 {
208
209         struct southbridge_ricoh_rl5c476_config *conf = dev->chip_info;
210         enable_cf_boot = conf->enable_cf;
211
212 }
213
214 struct chip_operations southbridge_ricoh_rl5c476_ops = {
215         CHIP_NAME("Ricoh RL5C476 CardBus Controller")
216         .enable_dev    = southbridge_init,
217 };