#include #include #include #include #include #include #include #include #include "chip.h" // prototypes here, avoid warnings void setup_i8259(void); void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4]); void print_conf(void); #define PIN_OPT_IDE (1ULL<<0) /* 0 for flash, 1 for IDE */ /* Intended value for LBAR_FLSH0: 4KiB, enabled, MMIO, NAND, @0x20000000 */ /* NOTE: no longer used, prune at some point */ /* OOPS: steve's changes don't work, so we have to keep this */ msr_t flsh1 = { .hi=0xFFFFF007, .lo=0x20000000}; // ide is ENABLED by default (in early init), this disables it if neccesary // and enables flash static void enable_ide_nand_flash() { msr_t msr; printk_debug("cs5536: %s\n", __FUNCTION__); #if 1 printk_err("WARNING: using deprecated flash enable mechanism\n"); /* steve took this one out ... not sure if needed or not */ msr = rdmsr(MDD_LBAR_FLSH1); if ( ((msr.hi) & 7) != 7) { printk_debug("MDD_LBAR_FLSH1 was 0x%08x%08x\n", msr.hi,msr.lo); wrmsr(MDD_LBAR_FLSH1, flsh1); } msr = rdmsr(MDD_LBAR_FLSH1); printk_debug("MDD_LBAR_FLSH1 is 0x%08x%08x\n", msr.hi,msr.lo); #endif msr = rdmsr(MDD_PIN_OPT); if (msr.lo & PIN_OPT_IDE) { printk_debug("MDD_PIN_OPT was 0x%08x%08x\n", msr.hi,msr.lo); msr.lo &= ~PIN_OPT_IDE; wrmsr(MDD_PIN_OPT, msr); } msr = rdmsr(MDD_PIN_OPT); printk_debug("MDD_PIN_OPT is 0x%08x%08x\n", msr.hi,msr.lo); msr = rdmsr(MDD_NANDF_DATA); if (msr.lo != 0x00100010) { printk_debug("MDD_NANDF_DATA was 0x%08x%08x\n", msr.hi,msr.lo); msr.lo = 0x00100010; wrmsr(MDD_NANDF_DATA, msr); } msr = rdmsr(MDD_NANDF_DATA); printk_debug("MDD_NANDF_DATA is 0x%08x%08x\n", msr.hi,msr.lo); msr = rdmsr(MDD_NADF_CNTL); if (msr.lo != 0x0010) { printk_debug("MDD_NADF_CNTL was 0x%08x%08x\n", msr.hi,msr.lo); msr.lo = 0x0010; wrmsr(MDD_NADF_CNTL, msr); } msr = rdmsr(MDD_NADF_CNTL); printk_debug("MDD_NADF_CNTL is 0x%08x%08x\n", msr.hi,msr.lo); printk_debug("cs5536: EXIT %s\n", __FUNCTION__); } /* note: this is a candidate for inclusion in src/devices/pci_device.c */ // set pci headers to indicate correct IRQ number of the device void setup_irq(unsigned irq, unsigned level, unsigned bus, unsigned device, unsigned fn) { if (irq) { unsigned devfn = PCI_DEVFN(device,fn); device_t dev = dev_find_slot(bus, devfn); if (dev) { printk_debug("%s: assigning IRQ %d to %x.%x (0x%x)\n", __FUNCTION__, irq, device, fn, devfn); pci_write_config8(dev, PCI_INTERRUPT_LINE, irq); if (level) pci_level_irq(irq); } else printk_err("%s: Can't find PCI device function 0x%x\n", __FUNCTION__, devfn); } } // map an Y or Z irq source in programmable irq controller // dev 0..15 Y, 16...31 Z void map_pic_irq(unsigned int dev, unsigned int irq){ msr_t msr; unsigned long mask; unsigned long val; mask = ~(0xF<<((dev&7)<<2)); val = irq<<((dev&7)<<2); printk_debug("%s: mapping %d to src %d: mask %x val %x\n", __FUNCTION__, irq, dev,mask,val); switch (dev & 0x18){ case 0: msr=rdmsr(MDD_IRQM_YLOW); msr.lo = (msr.lo & mask) | val; wrmsr(MDD_IRQM_YLOW,msr); break; case 8: msr=rdmsr(MDD_IRQM_YHIGH); msr.lo = (msr.lo & mask) | val; wrmsr(MDD_IRQM_YHIGH,msr); break; case 16: msr=rdmsr(MDD_IRQM_ZLOW); msr.lo = (msr.lo & mask) | val; wrmsr(MDD_IRQM_ZLOW,msr); break; case 24: msr=rdmsr(MDD_IRQM_ZHIGH); msr.lo = (msr.lo & mask) | val; wrmsr(MDD_IRQM_ZHIGH,msr); } } // map an GPIO pin to PIC Z source and that to an IRQ. void map_gpio_irq(unsigned int pin, unsigned int gpioirq, unsigned int irq, unsigned int invert){ unsigned long temp; unsigned long mask; unsigned long val; mask = ~(0xF<<((pin&7)<<2)); val = gpioirq<<((pin&7)<<2); // configure GPIO pin as INT source outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_ENABLE:GPIOH_INPUT_ENABLE); outl(1<<(pin&0x0F), (pin<16)?GPIOL_EVENTS_ENABLE:GPIOH_EVENTS_ENABLE); if (invert) outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_INVERT_ENABLE:GPIOH_INPUT_INVERT_ENABLE); // map current GPIO pin to PIC unrestricted Z GPIO irq source gpioirq temp = inl((pin<16)? ((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y): ((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W)); outl((temp & mask)|val, (pin<16)? ((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y): ((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W)); // map PIC unrestricted Z GPIO source i to IRQ needed map_pic_irq(gpioirq+24,irq); } static void southbridge_init(struct device *dev) { struct southbridge_amd_cs5536_lx_config *sb = (struct southbridge_amd_cs5536_lx_config *)dev->chip_info; msr_t msr; int i; printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__); /* * struct device *gpiodev; * unsigned short gpiobase = MDD_GPIO; */ setup_i8259(); // at first, disable all primary IRQ inputs except timer, RTC and FPU msr.lo=0x2101; msr.hi=0; wrmsr(MDD_IRQM_PRIM, msr); // LPC bus IRQs are enabled here if (sb->lpc_serirq_enable) { msr.lo = sb->lpc_serirq_enable; msr.hi = 0; wrmsr(MDD_LPC_SIRQ, msr); } if (sb->lpc_irq) { msr.lo = sb->lpc_irq; msr.hi = 0; wrmsr(MDD_IRQM_LPC, msr); } // GPIO to IRQ mapping (meant for PCI IRQs) // here, only physical mapping is done. // pci headers should be configured for all pci slots available in mainboard.c // so that operating system can read correct irq number from there for (i=0; i<3; i++){ if (sb->pci_int[i]){ printk_debug("cs5536: %s: Configuring PCI INT%c from GPIO %d to INT %d.\n", __FUNCTION__, 'A'+i, sb->pci_int_pin[i], sb->pci_int[i]); map_gpio_irq(sb->pci_int_pin[i], i, sb->pci_int[i], 1); } } /* // PCI IRQ mapping should work like this through vsa, but it doesn't outl(0xAC1C, 0xFC53); //magic word to enable hidden register outl(0xAC1C, 0x0009); //command: PCI_INT_AB outl(0xAC1E, (sb->pci_int[0]>0)?(sb->pci_int_pin[0]):0x21 | (sb->pci_int[1]>0)?(sb->pci_int_pin[1]<<8):(0x21<<8) ); outl(0x785C, sb->pci_int[0]|(sb->pci_int[1]<<8)); */ printk_debug("cs5536: %s: enable_ide_nand_flash is %d\n", __FUNCTION__, sb->enable_ide_nand_flash); if (sb->enable_ide_nand_flash) { enable_ide_nand_flash(); } /* irq handling */ // setup_irq sets irq in pci headers only, no configuration is done. // pci headers must be set, operating system reads IRQ numbers there. // to disable, set IRQ=0 if (sb->isa_irq){ setup_irq(sb->isa_irq, 1, 0, 0xf, 0); } if (sb->flash_irq){ setup_irq(sb->flash_irq, 1, 0, 0xf, 1); map_pic_irq(6,sb->flash_irq); map_pic_irq(7,sb->flash_irq); } // IDE IRQ 14 (GPIO pin 2) can only be enabled or disabled if (sb->enable_ide_irq){ setup_irq(14, 1, 0, 0xf, 2); // set up IDE GPIO IRQ pin outl(1<<2, GPIOL_INPUT_ENABLE); outl(1<<2, GPIOL_IN_AUX1_SELECT); // enable IDE IRQ in primary IRQ mask msr=rdmsr(MDD_IRQM_PRIM); msr.lo |= 0x4000; wrmsr(MDD_IRQM_PRIM, msr); } if (sb->audio_irq){ map_pic_irq(4,sb->audio_irq); setup_irq(sb->audio_irq, 1, 0, 0xf, 3); } if (sb->uart0_irq){ map_pic_irq(14,sb->uart0_irq); } if (sb->uart1_irq){ map_pic_irq(15,sb->uart1_irq); } if (sb->usb_irq){ setup_irq(sb->usb_irq, 1, 0, 0xf, 4); setup_irq(sb->usb_irq, 1, 0, 0xf, 5); setup_irq(sb->usb_irq, 1, 0, 0xf, 6); setup_irq(sb->usb_irq, 1, 0, 0xf, 7); map_pic_irq(2,sb->usb_irq); } // KEL (Keyboard Emulation Logic) IRQs if (sb->enable_kel_keyb_irq){ msr=rdmsr(MDD_IRQM_PRIM); msr.lo |= 0x0002; wrmsr(MDD_IRQM_PRIM, msr); } if (sb->enable_kel_mouse_irq){ msr=rdmsr(MDD_IRQM_PRIM); msr.lo |= 0x1000; wrmsr(MDD_IRQM_PRIM, msr); } if (sb->kel_emul_irq){ map_pic_irq(13,sb->kel_emul_irq); } /* disable unwanted virtual PCI devices */ for (i = 0; (i < MAX_UNWANTED_VPCI) && (0 != sb->unwanted_vpci[i]); i++) { printk_debug("Disabling VPCI device: 0x%08X\n", sb->unwanted_vpci[i]); outl(sb->unwanted_vpci[i] + 0x7C, 0xCF8); outl(0xDEADBEEF, 0xCFC); } /* What do we have there? */ printk_debug("\nChipset config after southbridge_init():\n"); print_conf(); } void southbridge_enable(struct device *dev) { } static void cs5536_pci_dev_enable_resources(device_t dev) { printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__); pci_dev_enable_resources(dev); enable_childrens_resources(dev); } static struct device_operations southbridge_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = cs5536_pci_dev_enable_resources, .init = southbridge_init, .scan_bus = scan_static_bus, }; static struct pci_driver cs5536_lx_pci_driver __pci_driver = { .ops = &southbridge_ops, .vendor = PCI_VENDOR_ID_AMD, .device = PCI_DEVICE_ID_AMD_CS5536_ISA }; struct chip_operations southbridge_amd_cs5536_lx_ops = { CHIP_NAME("AMD Geode CS5536 (LX) Southbridge") /* This only called when this device is listed in the * static device tree. */ .enable_dev = southbridge_enable, };