/*
- * (C) Copyright 2004 Nick Barker <nick.barker9@btinternet.com>
- *
+ * (C) Copyright 2004-2005 Nick Barker <nick.barker@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
*
* 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., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
*/
-
-
#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 void udelay(int i){
- for(; i > 0 ; i--)
- inb(0x80);
-
-}
+static int enable_cf_boot = 0;
+static unsigned int cf_base;
-static void
-dump_south(void)
+static void rl5c476_init(device_t dev)
{
- device_t dev0;
- dev0 = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, 0);
- dev0 = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, dev0);
- int i,j;
-
- for(i = 0; i < 256; i += 16) {
- printk_debug("0x%x: ", i);
- for(j = 0; j < 16; j++) {
- printk_debug("%02x ", pci_read_config8(dev0, i+j));
- }
- printk_debug("\n");
- }
- printk_debug("Card32\n");
- for(i = 0 ; i < 256 ; i+=16){
- printk_debug("0x%x: ",i);
- for(j = 0 ; j < 16 ; j++){
- printk_debug(" %02x",*(unsigned char *)(0x80000000+i+j));
- }
- printk_debug("\n");
- }
- printk_debug("Card16\n");
- for(i = 0; i < 256; i += 16) {
- printk_debug("0x%x: ", i);
- for(j = 0; j < 16; j++) {
- printk_debug("%02x ", *(unsigned char *)(0x80000800+ i+j));
- }
- printk_debug("\n");
- }
- printk_debug("CF Config\n");
- for(i = 0 ; i < 256 ; i+=16){
- printk_debug("0x%x: ",i);
- for(j=0 ; j < 16 ; j++){
- printk_debug("%02x ",*(unsigned char *)(0x81000200 + i + j));
- }
- printk_debug("\n");
- }
-}
-
-
-static void rl5c476_init(struct southbridge_rl5c476_config *conf)
-{
- //unsigned char enables;
- device_t dev;
pc16reg_t *pc16;
- int i;
+ unsigned char *base;
- printk_debug("rl5c476 init\n");
/* cardbus controller function 1 for CF Socket */
- dev = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, 0);
+ printk_debug("Ricoh RL5c476: Initializing.\n");
- if (!dev ){
- // probably an epia-m rather than mii
- printk_debug("No rl5c476 found\n");
- return;
- }
-
- /* setup pci header manually because 'pci_device.c' doesn't know how to handle
- * pci to cardbus bridges - (header type 2 I think)
- */
+ printk_debug("CF Base = %0x\n",cf_base);
+ /* misc control register */
+ pci_write_config16(dev,0x82,0x00a0);
- /* initialize function zero - pcmcia socket so it behaves itself */
- /* FIXME - statically put control memory at 0xe0000000 for now
- * one day the pci_device allocator might do this */
- pci_write_config32(dev,0x10,0xe0000000);
- pci_write_config8(dev,0x0d,0x20);
- pci_write_config8(dev,0x19,0x02);
- pci_write_config8(dev,0x1a,0x02);
- pci_write_config8(dev,0x1b,0x20);
- //pci_write_config8(dev,0x3c,0);
- pci_write_config8(dev,0x82,0x00a0);
- pci_write_config16(dev,0x04,0x07);
+ /* set up second slot as compact flash port if asked to do so */
+ if (!enable_cf_boot) {
+ printk_debug("CF boot not enabled.\n");
+ return;
+ }
- /* get second function - i.e. compact flash socket */
- dev = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, dev);
-
-
- /* FIXME - control structure statically declared at 0xe0008000 for now */
- pci_write_config32(dev,0x10,0xe0008000);
- pci_write_config8(dev,0x0d,0x20);
- pci_write_config8(dev,0x19,0x03);
- pci_write_config8(dev,0x1a,0x03);
- pci_write_config8(dev,0x1b,0x20);
+ if (PCI_FUNC(dev->path.pci.devfn) != 1) {
+ // Only configure if second CF slot.
+ return;
+ }
- //pci_write_config8(dev,0x3c,0x0);
+ /* make sure isa interrupts are enabled */
pci_write_config16(dev,0x3e,0x0780);
- pci_write_config16(dev,0x82,0x00a0);
- pci_write_config16(dev,0x04,0x07);
-
-
- /* pick up where 16 bit card control structure is */
- pc16 = (pc16reg_t *)(0xe0008800);
+ /* 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;
/* reset card, configure for I/O and set IRQ line */
pc16->igctrl = 0x69;
-
- // set io window 0 for 1e8 - 1ef
- pc16->iostl0 = 0xe8;
+ /* 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 I/O windows to
+ * emulate the expected addresses for IDE2, however the PCMCIA
+ * package within Linux then could not re-initialize the
+ * device as it tried to take control of it. So I believe 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.
+ *
+ * Nonetheless, FILO needs a special option enabled to boot
+ * from this configuration, and it needs to clean up
+ * afterwards. Please refer to FILO documentation and source
+ * code for more details.
+ */
+ pc16->iostl0 = 0xe0;
pc16->iosth0 = 1;
pc16->iospl0 = 0xef;
pc16->iosph0 = 1;
- // add io offset of 8 so that CF card will decode 0x1e8 as 0x1f0 i.e. the first byte of
- // a 16 byte aligned, 16 byte window etc
- pc16->ioffl0 = 0x8;
+ pc16->ioffl0 = 0;
pc16->ioffh0 = 0;
- // set io window 1 for 3ed - 3ee
- pc16->iostl1 = 0xed;
- pc16->iosth1 = 3;
+ /* clear window 1 */
+ pc16->iostl1 = 0;
+ pc16->iosth1 = 0;
- pc16->iospl1 = 0xee;
- pc16->iosph1 = 3;
+ pc16->iospl1 = 0;
+ pc16->iosph1 = 0;
pc16->ioffl1 = 0x0;
pc16->ioffh1 = 0;
-
- // FIXME statically declare CF config window at 0xe1000000
- pc16->smstl0 = 0;
- pc16->smsth0 = 0;
- pc16->smspl0 = 0;
- pc16->smsph0 = 0x80;
+ /* 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;
- pc16->smpga0 = 0xe1;
- // set I/O width for Auto Data width
+
+ /* set I/O width for Auto Data width */
pc16->ioctrl = 0x22;
- // enable I/O window 0 and 1
+ /* enable I/O window 0 and 1 */
pc16->awinen = 0xc1;
-
pc16->miscc1 = 1;
- // apply power and enable outputs
+ /* 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 should
+ * do for now.
+ */
unsigned char *cptr;
- cptr = (unsigned char *)(0xe1000200);
+ cptr = (unsigned char *)(cf_base + 0x200);
printk_debug("CF Config = %x\n",*cptr);
- // FIX Me 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 !!!
-
-
- // 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)
+ /* 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.pci.devfn) == 1)){
+ /* fake index as it isn't in PCI config space */
+ resource = new_resource(dev, 1);
+ resource->flags |= IORESOURCE_MEM ;
+ resource->size = 0x1000;
+ resource->align = resource->gran = 12;
+ resource->limit= 0xffff0000;
+ }
+ cardbus_read_resources(dev);
}
-static void southbridge_init(struct chip *chip, enum chip_pass pass)
+void rl5c476_set_resources(device_t dev)
{
-
- struct southbridge_rl5c476_config *conf =
- (struct southbridge_rl5c476_config *)chip->chip_info;
-
- switch (pass) {
- case CONF_PASS_PRE_PCI:
- //rl5c476_pci_enable(conf);
- break;
-
- case CONF_PASS_POST_PCI:
- rl5c476_init(conf);
-
- break;
-
- case CONF_PASS_PRE_BOOT:
- //dump_south();
- break;
-
- default:
- /* nothing yet */
- break;
+ struct resource *resource;
+ printk_debug("%s In set resources \n",dev_path(dev));
+ if( enable_cf_boot && (PCI_FUNC(dev->path.pci.devfn) == 1)){
+ resource = find_resource(dev,1);
+ if( !(resource->flags & IORESOURCE_STORED) ){
+ resource->flags |= IORESOURCE_STORED ;
+ printk_debug("%s 1 ==> %x\n",dev_path(dev),resource->base);
+ cf_base = resource->base;
+ }
}
+
+ pci_dev_set_resources(dev);
+
}
-static void enumerate(struct chip *chip)
+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 const 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)
{
- extern struct device_operations default_pci_ops_bus;
- chip_enumerate(chip);
- chip->dev->ops = &default_pci_ops_bus;
+
+ struct southbridge_ricoh_rl5c476_config *conf = dev->chip_info;
+ enable_cf_boot = conf->enable_cf;
+
}
-struct chip_control southbridge_ricoh_rl5c476_control = {
- .enumerate = enumerate,
- .enable = southbridge_init,
- .name = "RICOH RL5C476"
+struct chip_operations southbridge_ricoh_rl5c476_ops = {
+ CHIP_NAME("Ricoh RL5C476 CardBus Controller")
+ .enable_dev = southbridge_init,
};