| /* |
| * (C) Copyright 2004 Nick Barker <nick.barker9@btinternet.com> |
| * |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
| * MA 02110-1301 USA |
| */ |
| /* (C) Copyright 2005 Nick Barker <nick.barker@btinternet.com |
| brought into line with the current architecture of LinuxBios */ |
| |
| |
| #include <arch/io.h> |
| #include <device/device.h> |
| #include <device/pci.h> |
| #include <device/pci_ops.h> |
| #include <device/pci_ids.h> |
| #include <console/console.h> |
| #include <device/cardbus.h> |
| #include "rl5c476.h" |
| #include "chip.h" |
| |
| static int enable_cf_boot = 0; |
| static unsigned int cf_base; |
| |
| static void udelay(int i){ |
| for(; i > 0 ; i--) |
| inb(0x80); |
| |
| } |
| |
| static void rl5c476_init(device_t dev) |
| { |
| //unsigned char enables; |
| pc16reg_t *pc16; |
| |
| unsigned char *base; |
| |
| /* cardbus controller function 1 for CF Socket */ |
| printk_debug("rl5c476 init\n"); |
| |
| printk_debug("CF Base = %0x\n",cf_base); |
| |
| /* misc control register */ |
| pci_write_config16(dev,0x82,0x00a0); |
| |
| /* set up second slot as compact flash port if asked to do so */ |
| if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){ |
| |
| /* make sure isa interrupts are enabled */ |
| pci_write_config16(dev,0x3e,0x0780); |
| |
| /* pick up where 16 bit card control structure is (0x800 bytes into config structure) */ |
| base = (unsigned char *)pci_read_config32(dev,0x10); |
| pc16 = (pc16reg_t *)(base + 0x800); |
| |
| /* disable memory and io windows and turn off socket power */ |
| pc16->pwctrl = 0; |
| |
| /* disable irq lines */ |
| pc16->igctrl = 0; |
| |
| /* disable memory and I/O windows */ |
| pc16->awinen = 0; |
| |
| /* reset card, configure for I/O and set IRQ line */ |
| pc16->igctrl = 0x69; |
| |
| // set io window 0 for 1e0 - 1ef |
| /* note this now sets CF up on a contiguous I/O window of 16 bytes, 0x1e0 to 0x1ef |
| Be warned that this is not a standard IDE address as automatically detected by the likes |
| of Filo, and would need patching to recognise these addresses as an IDE drive */ |
| /* an earlier version of this driver set up 2 io windows to emulate the expected addresses |
| for IDE2, however the pcmcia package within Linux then could not re-initiailse the |
| device as it tried to take control of it. So I belive it is easier to patch Filo or the like |
| to pick up this drive rather than playing silly games as the kernel tries to boot. |
| */ |
| pc16->iostl0 = 0xe0; |
| pc16->iosth0 = 1; |
| |
| pc16->iospl0 = 0xef; |
| pc16->iosph0 = 1; |
| |
| pc16->ioffl0 = 0; |
| pc16->ioffh0 = 0; |
| |
| // clear window 1 |
| pc16->iostl1 = 0; |
| pc16->iosth1 = 0; |
| |
| pc16->iospl1 = 0; |
| pc16->iosph1 = 0; |
| |
| pc16->ioffl1 = 0x0; |
| pc16->ioffh1 = 0; |
| |
| |
| |
| // set up CF config window |
| pc16->smpga0 = cf_base>>24; |
| pc16->smsth0 = (cf_base>>20)&0x0f; |
| pc16->smstl0 = (cf_base>>12)&0xff; |
| pc16->smsph0 = ((cf_base>>20)&0x0f) | 0x80; |
| pc16->smspl0 = (cf_base>>12)&0xff; |
| pc16->moffl0 = 0; |
| pc16->moffh0 = 0x40; |
| |
| |
| // set I/O width for Auto Data width |
| pc16->ioctrl = 0x22; |
| |
| |
| // enable I/O window 0 and 1 |
| pc16->awinen = 0xc1; |
| |
| |
| pc16->miscc1 = 1; |
| |
| // apply power and enable outputs |
| pc16->pwctrl = 0xb0; |
| |
| |
| // delay could be optimised, but this works |
| udelay(100000); |
| |
| pc16->igctrl = 0x69; |
| |
| |
| // 16 bit CF always have first config byte at 0x200 into Config structure, |
| // but CF+ May Not according to spec - should locate through reading tuple data, |
| // but this will do for now !!! |
| unsigned char *cptr; |
| cptr = (unsigned char *)(cf_base + 0x200); |
| printk_debug("CF Config = %x\n",*cptr); |
| |
| // set CF to decode 16 IO bytes on any 16 byte boundary - rely on the io |
| // windows of the bridge set up above to map those bytes into the |
| // addresses for ide controller 3 (0x1e8 - 0x1ef and 0x3ed - 0x3ee) |
| *cptr = 0x41; |
| } |
| |
| } |
| |
| void rl5c476_read_resources(device_t dev) |
| { |
| |
| struct resource *resource; |
| |
| /* for cf socket we need an extra memory window for the control structure of the cf itself */ |
| if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){ |
| resource = new_resource(dev,1); /* fake index as it isn't in pci config space */ |
| resource->flags |= IORESOURCE_MEM ; |
| resource->size = 0x1000; |
| resource->align = resource->gran = 12; |
| resource->limit= 0xffff0000; |
| //compute_allocate_resource(&dev->link[0],resource,resource->flags,resource->flags); |
| } |
| cardbus_read_resources(dev); |
| |
| } |
| |
| void rl5c476_set_resources(device_t dev) |
| { |
| |
| struct resource *resource; |
| printk_debug("%s In set resources \n",dev_path(dev)); |
| if( enable_cf_boot && (PCI_FUNC(dev->path.u.pci.devfn) == 1)){ |
| resource = find_resource(dev,1); |
| if( !(resource->flags & IORESOURCE_STORED) ){ |
| resource->flags |= IORESOURCE_STORED ; |
| compute_allocate_resource(&dev->link[0],resource,resource->flags,resource->flags); |
| printk_debug("%s 1 ==> %x\n",dev_path(dev),resource->base); |
| cf_base = resource->base; |
| } |
| } |
| |
| pci_dev_set_resources(dev); |
| |
| } |
| |
| static struct device_operations ricoh_rl5c476_ops = { |
| .read_resources = rl5c476_read_resources, |
| .set_resources = rl5c476_set_resources, |
| .enable_resources = cardbus_enable_resources, |
| .init = rl5c476_init, |
| .scan_bus = cardbus_scan_bridge, |
| }; |
| |
| static struct pci_driver ricoh_rl5c476_driver __pci_driver = { |
| .ops = &ricoh_rl5c476_ops, |
| .vendor = PCI_VENDOR_ID_RICOH, |
| .device = PCI_DEVICE_ID_RICOH_RL5C476, |
| }; |
| |
| void southbridge_init(device_t dev) |
| { |
| |
| struct southbridge_ricoh_rl5c476_config *conf = dev->chip_info; |
| enable_cf_boot = conf->enable_cf; |
| |
| } |
| |
| struct chip_operations southbridge_ricoh_rl5c476_ops = { |
| CHIP_NAME("RICOH RL5C476") |
| .enable_dev = southbridge_init, |
| }; |