From: Henrik Brix Andersen The current SCx200 drivers use a fixed base address of 0x9000 for the Configuration Block, but some systems (at least the Soekris net4801) uses a base address of 0x6000. This patch first tries the fixed address then - if no configuration block could be found - tries the address written to the Configuration Block Address Scratchpad register by the BIOS. Signed-off-by: Henrik Brix Andersen Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/scx200.c | 51 +++++++++++++++++++++-------- 25-akpm/drivers/char/watchdog/Kconfig | 4 +- 25-akpm/drivers/char/watchdog/scx200_wdt.c | 42 +++++++---------------- 25-akpm/drivers/mtd/maps/Kconfig | 2 - 25-akpm/drivers/mtd/maps/scx200_docflash.c | 13 +++---- 25-akpm/include/linux/pci_ids.h | 2 + 25-akpm/include/linux/scx200.h | 10 +++-- 7 files changed, 69 insertions(+), 55 deletions(-) diff -puN arch/i386/kernel/scx200.c~determine-scx200-cb-address-at-run-time arch/i386/kernel/scx200.c --- 25/arch/i386/kernel/scx200.c~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/arch/i386/kernel/scx200.c 2005-02-28 14:45:16.000000000 -0800 @@ -13,6 +13,9 @@ #include +/* Verify that the configuration block really is there */ +#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base)) + #define NAME "scx200" MODULE_AUTHOR("Christer Weinigel "); @@ -22,9 +25,13 @@ MODULE_LICENSE("GPL"); unsigned scx200_gpio_base = 0; long scx200_gpio_shadow[2]; +unsigned scx200_cb_base = 0; + static struct pci_device_id scx200_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS) }, { }, }; MODULE_DEVICE_TABLE(pci,scx200_tbl); @@ -45,22 +52,39 @@ static int __devinit scx200_probe(struct int bank; unsigned base; - base = pci_resource_start(pdev, 0); - printk(KERN_INFO NAME ": GPIO base 0x%x\n", base); - - if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) { - printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n"); - return -EBUSY; + if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE || + pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) { + base = pci_resource_start(pdev, 0); + printk(KERN_INFO NAME ": GPIO base 0x%x\n", base); + + if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) { + printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n"); + return -EBUSY; + } + + scx200_gpio_base = base; + + /* read the current values driven on the GPIO signals */ + for (bank = 0; bank < 2; ++bank) + scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank); + + } else { + /* find the base of the Configuration Block */ + if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) { + scx200_cb_base = SCx200_CB_BASE_FIXED; + } else { + pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base); + if (scx200_cb_probe(base)) { + scx200_cb_base = base; + } else { + printk(KERN_WARNING NAME ": Configuration Block not found\n"); + return -ENODEV; + } + } + printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base); } - scx200_gpio_base = base; - - /* read the current values driven on the GPIO signals */ - for (bank = 0; bank < 2; ++bank) - scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank); - return 0; - } u32 scx200_gpio_configure(int index, u32 mask, u32 bits) @@ -134,6 +158,7 @@ EXPORT_SYMBOL(scx200_gpio_shadow); EXPORT_SYMBOL(scx200_gpio_lock); EXPORT_SYMBOL(scx200_gpio_configure); EXPORT_SYMBOL(scx200_gpio_dump); +EXPORT_SYMBOL(scx200_cb_base); /* Local variables: diff -puN drivers/char/watchdog/Kconfig~determine-scx200-cb-address-at-run-time drivers/char/watchdog/Kconfig --- 25/drivers/char/watchdog/Kconfig~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/drivers/char/watchdog/Kconfig 2005-02-28 14:45:16.000000000 -0800 @@ -278,12 +278,12 @@ config SC1200_WDT config SCx200_WDT tristate "National Semiconductor SCx200 Watchdog" - depends on WATCHDOG && X86 && PCI + depends on WATCHDOG && SCx200 && PCI help Enable the built-in watchdog timer support on the National Semiconductor SCx200 processors. - If compiled as a module, it will be called scx200_watchdog. + If compiled as a module, it will be called scx200_wdt. config 60XX_WDT tristate "SBC-60XX Watchdog Timer" diff -puN drivers/char/watchdog/scx200_wdt.c~determine-scx200-cb-address-at-run-time drivers/char/watchdog/scx200_wdt.c --- 25/drivers/char/watchdog/scx200_wdt.c~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/drivers/char/watchdog/scx200_wdt.c 2005-02-28 14:46:28.000000000 -0800 @@ -4,7 +4,7 @@ Copyright (c) 2001,2002 Christer Weinigel - Som code taken from: + Some code taken from: National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver (c) Copyright 2002 Zwane Mwaikambo @@ -64,7 +64,7 @@ static char expect_close; static void scx200_wdt_ping(void) { - outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO); + outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); } static void scx200_wdt_update_margin(void) @@ -78,9 +78,9 @@ static void scx200_wdt_enable(void) printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", wdto_restart); - outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); - outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); - outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); + outw(0, scx200_cb_base + SCx200_WDT_WDTO); + outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); + outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG); scx200_wdt_ping(); } @@ -89,9 +89,9 @@ static void scx200_wdt_disable(void) { printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); - outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); - outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); - outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); + outw(0, scx200_cb_base + SCx200_WDT_WDTO); + outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); + outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG); } static int scx200_wdt_open(struct inode *inode, struct file *file) @@ -217,28 +217,14 @@ static struct miscdevice scx200_wdt_misc static int __init scx200_wdt_init(void) { int r; - static struct pci_device_id ns_sc[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, - { }, - }; printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n"); - /* - * First check that this really is a NatSemi SCx200 CPU or a Geode - * SC1100 processor - */ - if (!pci_dev_present(ns_sc)) - return -ENODEV; - - /* More sanity checks, verify that the configuration block is there */ - if (!scx200_cb_probe(SCx200_CB_BASE)) { - printk(KERN_WARNING NAME ": no configuration block found\n"); + /* check that we have found the configuration block */ + if (!scx200_cb_present()) return -ENODEV; - } - if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE, "NatSemi SCx200 Watchdog")) { printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); @@ -252,7 +238,7 @@ static int __init scx200_wdt_init(void) r = misc_register(&scx200_wdt_miscdev); if (r) { - release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); return r; } @@ -261,7 +247,7 @@ static int __init scx200_wdt_init(void) if (r) { printk(KERN_ERR NAME ": unable to register reboot notifier"); misc_deregister(&scx200_wdt_miscdev); - release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); return r; } @@ -273,7 +259,7 @@ static void __exit scx200_wdt_cleanup(vo { unregister_reboot_notifier(&scx200_wdt_notifier); misc_deregister(&scx200_wdt_miscdev); - release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); } diff -puN drivers/mtd/maps/Kconfig~determine-scx200-cb-address-at-run-time drivers/mtd/maps/Kconfig --- 25/drivers/mtd/maps/Kconfig~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/drivers/mtd/maps/Kconfig 2005-02-28 14:45:16.000000000 -0800 @@ -159,7 +159,7 @@ config MTD_VMAX config MTD_SCx200_DOCFLASH tristate "Flash device mapped with DOCCS on NatSemi SCx200" - depends on X86 && MTD_CFI && MTD_PARTITIONS + depends on SCx200 && MTD_CFI && MTD_PARTITIONS help Enable support for a flash chip mapped using the DOCCS signal on a National Semiconductor SCx200 processor. diff -puN drivers/mtd/maps/scx200_docflash.c~determine-scx200-cb-address-at-run-time drivers/mtd/maps/scx200_docflash.c --- 25/drivers/mtd/maps/scx200_docflash.c~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/drivers/mtd/maps/scx200_docflash.c 2005-02-28 14:45:16.000000000 -0800 @@ -92,17 +92,16 @@ static int __init init_scx200_docflash(v PCI_DEVICE_ID_NS_SCx200_BRIDGE, NULL)) == NULL) return -ENODEV; - - if (!scx200_cb_probe(SCx200_CB_BASE)) { - printk(KERN_WARNING NAME ": no configuration block found\n"); + + /* check that we have found the configuration block */ + if (!scx200_cb_present()) return -ENODEV; - } if (probe) { /* Try to use the present flash mapping if any */ pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base); pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl); - pmr = inl(SCx200_CB_BASE + SCx200_PMR); + pmr = inl(scx200_cb_base + SCx200_PMR); if (base == 0 || (ctrl & 0x07000000) != 0x07000000 @@ -155,14 +154,14 @@ static int __init init_scx200_docflash(v pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); - pmr = inl(SCx200_CB_BASE + SCx200_PMR); + pmr = inl(scx200_cb_base + SCx200_PMR); if (width == 8) { pmr &= ~(1<<6); } else { pmr |= (1<<6); } - outl(pmr, SCx200_CB_BASE + SCx200_PMR); + outl(pmr, scx200_cb_base + SCx200_PMR); } printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", diff -puN include/linux/pci_ids.h~determine-scx200-cb-address-at-run-time include/linux/pci_ids.h --- 25/include/linux/pci_ids.h~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/include/linux/pci_ids.h 2005-02-28 14:45:16.000000000 -0800 @@ -389,6 +389,8 @@ #define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504 #define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505 #define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510 +#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 +#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 #define PCI_DEVICE_ID_NS_87410 0xd001 #define PCI_VENDOR_ID_TSENG 0x100c diff -puN include/linux/scx200.h~determine-scx200-cb-address-at-run-time include/linux/scx200.h --- 25/include/linux/scx200.h~determine-scx200-cb-address-at-run-time 2005-02-28 14:45:16.000000000 -0800 +++ 25-akpm/include/linux/scx200.h 2005-02-28 14:45:16.000000000 -0800 @@ -7,6 +7,10 @@ /* Interesting stuff for the National Semiconductor SCx200 CPU */ +extern unsigned scx200_cb_base; + +#define scx200_cb_present() (scx200_cb_base!=0) + /* F0 PCI Header/Bridge Configuration Registers */ #define SCx200_DOCCS_BASE 0x78 /* DOCCS Base Address Register */ #define SCx200_DOCCS_CTRL 0x7c /* DOCCS Control Register */ @@ -15,7 +19,7 @@ #define SCx200_GPIO_SIZE 0x2c /* Size of GPIO register block */ /* General Configuration Block */ -#define SCx200_CB_BASE 0x9000 /* Base fixed at 0x9000 according to errata */ +#define SCx200_CB_BASE_FIXED 0x9000 /* Base fixed at 0x9000 according to errata? */ /* Watchdog Timer */ #define SCx200_WDT_OFFSET 0x00 /* offset within configuration block */ @@ -44,9 +48,7 @@ #define SCx200_IID 0x3c /* IA On a Chip Identification Number Reg */ #define SCx200_REV 0x3d /* Revision Register */ #define SCx200_CBA 0x3e /* Configuration Base Address Register */ - -/* Verify that the configuration block really is there */ -#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base)) +#define SCx200_CBA_SCRATCH 0x64 /* Configuration Base Address Scratchpad */ /* Local variables: _