diff options
author | Roman Yeryomin <roman@advem.lv> | 2012-09-13 00:40:35 +0300 |
---|---|---|
committer | Roman Yeryomin <roman@advem.lv> | 2012-12-03 00:13:21 +0200 |
commit | 5deb3317cb51ac52de922bb55f8492624018906d (patch) | |
tree | c2fbe6346699d9bb0f2100490c3029519bb8fde8 /target/linux/realtek/files/arch/mips/rtl8196b | |
parent | 0239d37124f9184b478a42de8a7fa1bc85a6a6fe (diff) |
Add realtek target files
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Diffstat (limited to 'target/linux/realtek/files/arch/mips/rtl8196b')
8 files changed, 1346 insertions, 0 deletions
diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/Makefile b/target/linux/realtek/files/arch/mips/rtl8196b/Makefile new file mode 100644 index 000000000..f7e8766ca --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the RTL8652 specific parts of the kernel +# +DIR_RTLASIC = $(DIR_LINUX)/drivers/net/rtl819x/ + +obj-y := setup.o printf.o int.o mem.o +obj-$(CONFIG_PCI) += pci.o +EXTRA_AFLAGS := $(CFLAGS) +EXTRA_CFLAGS += -I$(DIR_RTLASIC) diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/int.c b/target/linux/realtek/files/arch/mips/rtl8196b/int.c new file mode 100644 index 000000000..fd8699a23 --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/int.c @@ -0,0 +1,281 @@ +#include <linux/config.h>
+#include <linux/irq.h>
+
+#include <asm/irq_cpu.h>
+#include <prom.h>
+#include <platform.h>
+#include <linux/hardirq.h>
+#if defined(CONFIG_RTL_819X)
+#include <common/rtl_types.h>
+#endif
+
+spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;
+
+static void rtl8196_enable_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ REG32(GIMR) = REG32(GIMR) | (1 << irq);
+ spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+static unsigned int rtl8196_startup_irq(unsigned int irq)
+{
+ rtl8196_enable_irq(irq);
+
+ return 0;
+}
+
+static void rtl8196_disable_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ REG32(GIMR) = REG32(GIMR) & (~(1 << irq));
+ spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+static void rtl8196_end_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ REG32(GIMR) = REG32(GIMR) | (1 << irq);
+ spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+#define rtl8196_shutdown_irq rtl8196_disable_irq
+#define rtl8196_mask_and_ack_irq rtl8196_disable_irq
+
+static struct irq_chip irq_type = {
+ .typename = "RTL8196",
+ .startup = rtl8196_startup_irq,
+ .shutdown = rtl8196_shutdown_irq,
+ .enable = rtl8196_enable_irq,
+ .disable = rtl8196_disable_irq,
+ .ack = rtl8196_mask_and_ack_irq,
+ .end = rtl8196_end_irq,
+ .mask = rtl8196_disable_irq,
+ .mask_ack = rtl8196_mask_and_ack_irq,
+ .unmask = rtl8196_enable_irq,
+};
+
+
+/*
+ * RTL8196b Interrupt Scheme (Subject to change)
+ *
+ * Source EXT_INT IRQ CPU INT
+ * -------- ------- ------ -------
+ * PCIB0TO 0 0 2
+ * PCIB1TO 1 1 2
+ * LBCTMOm0 2 2 2
+ * LBCTMOm1 3 3 2
+ * LBCTMOs 4 4 2
+ * TIMER0 8 8 7
+ * TIMER1 9 9 2
+ * USB 10 10 4
+ * UART0 12 12 3
+ * UART1 13 13 2
+ * PCI 14 14 5
+ * SWCORE 15 15 6
+ * GPIO_ABCD 16 16 2
+ * GPIO_EFGH 17 17 2
+ * HCI 18 18 2
+ * PCM 19 19 2
+ * CRYPTO 20 20 2
+ * GDMA 21 21 2
+ */
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ /* Initialize for IRQ: 0~31 */
+ for (i = 0; i < 32; i++) {
+ //irq_desc[i].chip = &irq_type;
+ set_irq_chip_and_handler(i, &irq_type, handle_level_irq);
+ }
+
+ /* Enable all interrupt mask of CPU */
+ write_c0_status(read_c0_status() | ST0_IM);
+
+ /* Set GIMR, IRR */
+ REG32(GIMR) = TC0_IE | UART0_IE |SW_IE ;
+
+ REG32(IRR0) = IRR0_SETTING;
+ REG32(IRR1) = IRR1_SETTING;
+ REG32(IRR2) = IRR2_SETTING;
+ REG32(IRR3) = IRR3_SETTING;
+}
+
+#define ST0_USED_IM (_ULCAST_(0xfc00)) /* interrupt 2/3/4/5/6/7 */
+#define ST0_REENTRY_IM (_ULCAST_(0xe000)) /* interrupt 5/6/7 */
+
+__IRAM_GEN asmlinkage void plat_irq_dispatch(void)
+{
+#if 0
+ unsigned int cpuint_ip;
+ unsigned int cpuint_mask;
+ unsigned int extint_ip;
+
+ cpuint_mask = read_c0_status() & ST0_IM;
+ cpuint_ip = read_c0_cause() & read_c0_status() & ST0_IM;
+
+#if 1
+ write_c0_status(read_c0_status()&(~ST0_IM));
+#else
+ write_c0_status((read_c0_status()&(~ST0_IM))|(cpuint_mask&(~(STATUSF_IP6|STATUSF_IP5))));
+#endif
+
+ do
+ {
+ if (cpuint_ip & CAUSEF_IP7)
+ {
+ /* Timer 0 */
+ do_IRQ(TC0_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP5)
+ {
+ /* PCIE */
+ do_IRQ(PCIE_IRQ);
+ }
+ if (cpuint_ip & CAUSEF_IP6)
+ {
+ /* switch core*/
+ do_IRQ(SWCORE_IRQ);
+
+ }
+ else if (cpuint_ip & CAUSEF_IP3)
+ {
+ /* pci */
+ do_IRQ(PCI_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP4)
+ {
+ /*USB*/
+ do_IRQ(USB_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP2)
+ {
+ /* For shared interrupts */
+ unsigned int extint_ip = REG32(GIMR) & REG32(GISR);
+
+ if (extint_ip & UART0_IP)
+ {
+ /* UART 0 */
+ do_IRQ(UART0_IRQ);
+ }
+ else if (extint_ip & TC1_IP)
+ {
+ do_IRQ(TC1_IRQ);
+ }
+#if 0
+ /* currently we do not use uart1 */
+ else if (extint_ip & UART1_IP)
+ {
+ do_IRQ(UART1_IRQ);
+ }
+#endif
+ else
+ {
+ prom_printf("Unknown Interrupt2:%x\n",extint_ip);
+ REG32(GISR) = extint_ip;
+ }
+ }
+
+ cpuint_ip = read_c0_cause() & (STATUSF_IP6|STATUSF_IP5|STATUSF_IP7);
+ } while(cpuint_ip);
+
+#if 0 /* patch for wds+wep hang up issue */
+ write_c0_status((read_c0_status()&(~ST0_IM))|(cpuint_mask));
+#else
+ write_c0_status((read_c0_status()|(ST0_IM)));
+#endif
+#else
+ unsigned int cpuint_ip;
+ unsigned int extint_ip;
+
+ cpuint_ip = read_c0_cause() & ST0_USED_IM;
+ write_c0_status(read_c0_status()&(~ST0_IM));
+
+#if 0
+ if ( ST0_REENTRY_IM & cpuint_ip )
+ {
+ do
+ {
+ if (cpuint_ip & CAUSEF_IP7)
+ {
+ /* Timer 0 */
+ do_IRQ(TC0_IRQ);
+ }
+ if (cpuint_ip & CAUSEF_IP6)
+ {
+ /* switch core*/
+ do_IRQ(SWCORE_IRQ);
+ }
+ if (cpuint_ip & CAUSEF_IP5)
+ {
+ /* PCIE */
+ do_IRQ(PCIE_IRQ);
+ }
+ cpuint_ip = read_c0_cause() & ST0_REENTRY_IM;
+ } while(cpuint_ip);
+ }
+#else
+ if (cpuint_ip & CAUSEF_IP6)
+ {
+ /* switch core*/
+ do_IRQ(SWCORE_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP5)
+ {
+ /* PCIE */
+ do_IRQ(PCIE_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP7)
+ {
+ /* Timer 0 */
+ do_IRQ(TC0_IRQ);
+ }
+#endif
+ else if(cpuint_ip & CAUSEF_IP3)
+ {
+ /* pci */
+ do_IRQ(PCI_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP4)
+ {
+ /*USB*/
+ do_IRQ(USB_IRQ);
+ }
+ else if (cpuint_ip & CAUSEF_IP2)
+ {
+ /* For shared interrupts */
+ extint_ip = REG32(GIMR) & REG32(GISR);
+
+ if (extint_ip & UART0_IP)
+ {
+ /* UART 0 */
+ do_IRQ(UART0_IRQ);
+ }
+#if 0
+ else if (extint_ip & TC1_IP)
+ {
+ do_IRQ(TC1_IRQ);
+ }
+ /* currently we do not use uart1 */
+ else if (extint_ip & UART1_IP)
+ {
+ do_IRQ(UART1_IRQ);
+ }
+ else
+ {
+ prom_printf("Unknown Interrupt2:%x\n",extint_ip);
+ REG32(GISR) = extint_ip;
+ }
+#endif
+ }
+ write_c0_status((read_c0_status()|(ST0_USED_IM)));
+#endif
+}
diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/mem.c b/target/linux/realtek/files/arch/mips/rtl8196b/mem.c new file mode 100644 index 000000000..98644d98b --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/mem.c @@ -0,0 +1,133 @@ +#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+#include <prom.h>
+#include <platform.h>
+
+#define DCR 0xb8001004
+
+void __init prom_meminit(void)
+{
+ //char *ptr;
+ unsigned int memsize;
+
+ memsize = 0x02000000; /* Default to 32MB */
+ /* Check the command line first for a memsize directive */
+ //ptr = strstr(arcs_cmdline, "mem=");
+#if 1
+ /*now: alway believe DRAM configuration register*/
+ {
+ unsigned int DCRvalue = 0;
+ unsigned int bus_width = 0, chip_sel = 0, row_cnt = 0, col_cnt = 0,bank_cnt = 0;
+
+ DCRvalue = ( (*(volatile unsigned int *)DCR));
+
+ /*bit 19,0:2 bank; 1: 4 bank*/
+ switch(DCRvalue & 0x080000)
+ {
+ case 0x0:
+ bank_cnt = 2;
+ break;
+ case 0x080000:
+ bank_cnt = 4;
+ break;
+ default:
+ bank_cnt = 0;
+ break;
+ }
+
+ /*bit 22~24: colomn count*/
+ switch(DCRvalue & 0x01C00000)
+ {
+ case 0x00000000:
+ col_cnt = 256;
+ break;
+ case 0x00400000:
+ col_cnt = 512;
+ break;
+ case 0x00800000:
+ col_cnt = 1024;
+ break;
+ case 0x00C00000:
+ col_cnt = 2048;
+ break;
+ case 0x01000000:
+ col_cnt = 4096;
+ break;
+ default:
+ printk("unknow colomn count(0x%x)\n",DCRvalue & 0x01C00000);
+ break;
+ }
+
+ /*bit 25~26: row count*/
+ switch(DCRvalue & 0x06000000)
+ {
+ case 0x00000000:
+ row_cnt = 2048;
+ break;
+ case 0x02000000:
+ row_cnt = 4096;
+ break;
+ case 0x04000000:
+ row_cnt = 8192;
+ break;
+ case 0x06000000:
+ row_cnt = 16384;
+ break;
+ }
+
+ /*bit 27: chip select*/
+ switch(DCRvalue & 0x08000000)
+ {
+ case 0x0:
+ chip_sel = 1;
+ break;
+ case 0x08000000:
+ chip_sel = 2;
+ break;
+ }
+
+ /*bit 28~29: bus width*/
+ switch(DCRvalue & 0x30000000)
+ {
+ case 0x0:
+ bus_width = 8;
+ break;
+ case 0x10000000:
+ bus_width = 16;
+ break;
+ case 0x20000000:
+ bus_width = 32;
+ break;
+ default:
+ printk("bus width is reseved!\n");
+ break;
+ }
+
+ /*total size(Byte)*/
+ memsize = (row_cnt * col_cnt *bank_cnt) * (bus_width >> 3) * chip_sel;
+
+ }
+#endif
+
+ /*
+ * call <add_memory_region> to register boot_mem_map
+ * add_memory_region(base, size, type);
+ * type: BOOT_MEM_RAM, BOOT_MEM_ROM_DATA or BOOT_MEM_RESERVED
+ */
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+//unsigned long __init prom_free_prom_memory(void)
+void prom_free_prom_memory(void)
+{
+ //unsigned long freed = 0;
+
+ return;// freed;
+}
diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/pci-rtl8196.c b/target/linux/realtek/files/arch/mips/rtl8196b/pci-rtl8196.c new file mode 100644 index 000000000..fffd6d58f --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/pci-rtl8196.c @@ -0,0 +1,526 @@ +/* + * RTL8196B PCIE Host Controller Glue Driver + * Author: ghhuang@realtek.com.tw + * + * Notes: + * - Two host controllers available. + * - Each host direcly connects to one device + * - Supports PCI devices through PCIE-to-PCI bridges + * - If no PCI devices are connected to RC. Timeout monitor shall be + * enabled to prevent bus hanging. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <asm/mipsregs.h> + +#include <platform.h> + + +#define PCI_8BIT_ACCESS 1 +#define PCI_16BIT_ACCESS 2 +#define PCI_32BIT_ACCESS 4 +#define PCI_ACCESS_READ 8 +#define PCI_ACCESS_WRITE 16 + +#define MAX_NUM_DEV 4 + +#define DEBUG_PRINTK 0 + + +static int pci0_bus_number = 0xff; +static int pci1_bus_number = 0xff; + + +static struct resource rtl8196b_pci0_io_resource = { + .name = "RTL8196B PCI0 IO", + .flags = IORESOURCE_IO, + .start = PADDR(PCIE0_D_IO), + .end = PADDR(PCIE0_D_IO + 0x1FFFFF) +}; + +static struct resource rtl8196b_pci0_mem_resource = { + .name = "RTL8196B PCI0 MEM", + .flags = IORESOURCE_MEM, + .start = PADDR(PCIE0_D_MEM), + .end = PADDR(PCIE0_D_MEM + 0xFFFFFF) +}; + +static struct resource rtl8196b_pci1_io_resource = { + .name = "RTL8196B PCI1 IO", + .flags = IORESOURCE_IO, + .start = PADDR(PCIE1_D_IO), + .end = PADDR(PCIE1_D_IO + 0x1FFFFFF) +}; + +static struct resource rtl8196b_pci1_mem_resource = { + .name = "RTL8196B PCI1 MEM", + .flags = IORESOURCE_MEM, + .start = PADDR(PCIE1_D_MEM), + .end = PADDR(PCIE1_D_MEM + 0xFFFFFF) +}; +//#define PIN_208 +#define DEMO_8196 +static int rtl8196b_pci_reset(void) +{ + cli(); + /* If PCI needs to be reset, put code here. + * Note: + * Software may need to do hot reset for a period of time, say ~100us. + * Here we put 2ms. + */ +#if 1 +#ifdef PIN_208 +WRITE_MEM32(0xb8000044, 0x358);//Disable PCIE EX-PLL +#else +//#ifdef DEMO_8196 +//WRITE_MEM32(0xb8000044, 0x358);//Disable PCIE EX-PLL +//#else +//Modified for PHY parameter for RD center 12292008 +WRITE_MEM32(0xb8000044, 0x9);//Enable PCIE IN-PLL +//#endif +#endif +mdelay(100); +WRITE_MEM32(0xb8000010, 0x00FFFFD6);//Active LX & PCIE Clock in 8196B system register +mdelay(100); +WRITE_MEM32(0xb800003C, 0x1);//PORT0 PCIE PHY MDIO Reset +mdelay(100); +WRITE_MEM32(0xb800003C, 0x3);//PORT0 PCIE PHY MDIO Reset +mdelay(100); +WRITE_MEM32(0xb8000040, 0x1);//PORT1 PCIE PHY MDIO Reset +mdelay(100); +WRITE_MEM32(0xb8000040, 0x3);//PORT1 PCIE PHY MDIO Reset +mdelay(100); +WRITE_MEM32(0xb8b01008, 0x1);// PCIE PHY Reset Close:Port 0 +mdelay(100); +WRITE_MEM32(0xb8b01008, 0x81);// PCIE PHY Reset On:Port 0 +mdelay(100); +#ifdef PIN_208 +WRITE_MEM32(0xb8b21008, 0x1);// PCIE PHY Reset Close:Port 1 +mdelay(100); +WRITE_MEM32(0xb8b21008, 0x81);// PCIE PHY Reset On:Port 1 +mdelay(100); +#endif +#if 0//1//1// 1//def OUT_CYSTALL +WRITE_MEM32(0xb8b01000, 0xcc011901);// PCIE Close Port 0 +mdelay(10); +#ifdef PIN_208 +WRITE_MEM32(0xb8b21000, 0xcc011901);// PCIE Close Port 1 +mdelay(10); +#endif +#endif +WRITE_MEM32(0xb8000010, 0x01FFFFD6);// PCIE PHY Reset On:Port 1 +mdelay(100); +#endif + WRITE_MEM32(PCIE0_H_PWRCR, READ_MEM32(PCIE0_H_PWRCR) & 0xFFFFFF7F); +#ifdef PIN_208 + WRITE_MEM32(PCIE1_H_PWRCR, READ_MEM32(PCIE1_H_PWRCR) & 0xFFFFFF7F); +#endif + mdelay(100); + WRITE_MEM32(PCIE0_H_PWRCR, READ_MEM32(PCIE0_H_PWRCR) | 0x00000080); +#ifdef PIN_208 + WRITE_MEM32(PCIE1_H_PWRCR, READ_MEM32(PCIE1_H_PWRCR) | 0x00000080); +#endif + sti(); + return 0; +} + + +static int rtl8196b_pcibios_config_access(unsigned char access_type, + unsigned int addr, unsigned int *data) +{ + /* Do 8bit/16bit/32bit access */ + if (access_type & PCI_ACCESS_WRITE) + { + if (access_type & PCI_8BIT_ACCESS) + WRITE_MEM8(addr, *data); + else if (access_type & PCI_16BIT_ACCESS) + WRITE_MEM16(addr, *data); + else + WRITE_MEM32(addr, *data); + } + else if (access_type & PCI_ACCESS_READ) + { + if (access_type & PCI_8BIT_ACCESS) + *data = READ_MEM8(addr); + else if (access_type & PCI_16BIT_ACCESS) + *data = READ_MEM16(addr); + else + *data = READ_MEM32(addr); + } + + /* If need to check for PCIE access timeout, put code here */ + /* ... */ + + return 0; +} + + + +/* + * RTL8196b supports config word read access for 8/16/32 bit + * + * FIXME: currently only utilize 32bit access + */ +static int rtl8196b_pcibios0_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int *val) +{ + unsigned int data = 0; + unsigned int addr = 0; + + if (pci0_bus_number == 0xff) + pci0_bus_number = bus->number; + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + #endif + + if (bus->number == pci0_bus_number) + { + /* PCIE host controller */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE0_H_CFG + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else if (bus->number == (pci0_bus_number + 1)) + { + /* PCIE devices directly connected */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE0_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + { + /* Devices connected through bridge */ + if (PCI_SLOT(devfn) < MAX_NUM_DEV) + { + WRITE_MEM32(PCIE0_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); + addr = PCIE0_D_CFG1 + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Read Value: 0x%08X\n", *val); + #endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int rtl8196b_pcibios0_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int val) +{ + unsigned int data = 0; + unsigned int addr = 0; + + static int pci0_bus_number = 0xff; + + if (pci0_bus_number == 0xff) + pci0_bus_number = bus->number; + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + #endif + + if (bus->number == pci0_bus_number) + { + /* PCIE host controller */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE0_H_CFG + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | (val << ((where & 3) << 3)); + else + data = val; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE, addr, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else if (bus->number == (pci0_bus_number + 1)) + { + /* PCIE devices directly connected */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE0_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + { + /* Devices connected through bridge */ + if (PCI_SLOT(devfn) < MAX_NUM_DEV) + { + WRITE_MEM32(PCIE0_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); + addr = PCIE0_D_CFG1 + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + + +/* + * RTL8196b supports config word read access for 8/16/32 bit + * + * FIXME: currently only utilize 32bit access + */ +static int rtl8196b_pcibios1_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int *val) +{ + unsigned int data = 0; + unsigned int addr = 0; + + if (pci1_bus_number == 0xff) + pci1_bus_number = bus->number; + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + #endif + + if (bus->number == pci1_bus_number) + { + /* PCIE host controller */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE1_H_CFG + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else if (bus->number == (pci1_bus_number + 1)) + { + /* PCIE devices directly connected */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE1_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + { + /* Devices connected through bridge */ + if (PCI_SLOT(devfn) < MAX_NUM_DEV) + { + WRITE_MEM32(PCIE1_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); + addr = PCIE1_D_CFG1 + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Read Value: 0x%08X\n", *val); + #endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int rtl8196b_pcibios1_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int val) +{ + unsigned int data = 0; + unsigned int addr = 0; + + static int pci1_bus_number = 0xff; + + if (pci1_bus_number == 0xff) + pci1_bus_number = bus->number; + + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + #endif + + + if (bus->number == pci1_bus_number) + { + /* PCIE host controller */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE1_H_CFG + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | (val << ((where & 3) << 3)); + else + data = val; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE, addr, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else if (bus->number == (pci1_bus_number + 1)) + { + /* PCIE devices directly connected */ + if (PCI_SLOT(devfn) == 0) + { + addr = PCIE1_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + { + /* Devices connected through bridge */ + if (PCI_SLOT(devfn) < MAX_NUM_DEV) + { + WRITE_MEM32(PCIE1_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); + addr = PCIE1_D_CFG1 + where; + + if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + else + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops rtl8196b_pci0_ops = { + .read = rtl8196b_pcibios0_read, + .write = rtl8196b_pcibios0_write +}; + +struct pci_ops rtl8196b_pci1_ops = { + .read = rtl8196b_pcibios1_read, + .write = rtl8196b_pcibios1_write +}; + + +static struct pci_controller rtl8196b_pci0_controller = { + .pci_ops = &rtl8196b_pci0_ops, + .mem_resource = &rtl8196b_pci0_mem_resource, + .io_resource = &rtl8196b_pci0_io_resource, +}; + +static struct pci_controller rtl8196b_pci1_controller = { + .pci_ops = &rtl8196b_pci1_ops, + .mem_resource = &rtl8196b_pci1_mem_resource, + .io_resource = &rtl8196b_pci1_io_resource, +}; + + +int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + printk("**Slot: %d\n", slot); + printk("**Pin: %d\n", pin); + printk("**Dev->BUS->Number: %d\n", dev->bus->number); + #endif + + if (dev->bus->number < pci1_bus_number) + return PCIE_IRQ; + else + return PCIE2_IRQ; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + #if DEBUG_PRINTK + printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); + #endif + + return 0; +} + + +static __init int rtl8196b_pci_init(void) +{ + rtl8196b_pci_reset(); + + set_io_port_base(KSEG1); + ioport_resource.end = 0xFFFFFFFF; + + #if DEBUG_PRINTK + printk("<<<<<Register 1st PCI Controller>>>>>\n"); + printk("<<<<<Register 2nd PCI Controller>>>>>\n"); + #endif + + register_pci_controller(&rtl8196b_pci0_controller); +#ifdef PIN_208 + register_pci_controller(&rtl8196b_pci1_controller); +#endif + return 0; +} + +arch_initcall(rtl8196b_pci_init); diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/pci.h b/target/linux/realtek/files/arch/mips/rtl8196b/pci.h new file mode 100644 index 000000000..1c8dca8b9 --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/pci.h @@ -0,0 +1,75 @@ +#ifndef PCI_H +#define PCI_H + + + +struct pci_slot_baseaddr_s { + u32 slotNum; + u32 addr; +}; + +#ifdef CONFIG_RTL865XC + +#define PCI_SLOT0_CONFIG_BASE 0xB8B40000 +#define PCI_SLOT1_CONFIG_BASE 0xB8B80000 +#define PCI_SLOT2_CONFIG_BASE 0xB8B10000 +#define PCI_SLOT3_CONFIG_BASE 0xB8B20000 + +#define PCI_SLOT_MEM_BASE0 0xB9000000 +#define PCI_SLOT_IO_BASE0 0xB8C00000 +#define PCI_MEM_SPACE_SIZE0 0x01000000 +#define PCI_IO_SPACE_SIZE0 0x00200000 + +#define PCI_SLOT_MEM_BASE1 0xBA000000 +#define PCI_SLOT_IO_BASE1 0xB8E00000 +#define PCI_MEM_SPACE_SIZE1 0x01000000 +#define PCI_IO_SPACE_SIZE1 0x00200000 + + +#else + +#define PCI_SLOT0_CONFIG_BASE 0xBBD40000 +#define PCI_SLOT1_CONFIG_BASE 0xBBD80000 +#define PCI_SLOT2_CONFIG_BASE 0xBBD10000 +#define PCI_SLOT3_CONFIG_BASE 0xBBD20000 + +#define PCI_SLOT_MEM_BASE 0xBBF00000 +#define PCI_SLOT_IO_BASE 0xBBE00000 +#define PCI_MEM_SPACE_SIZE 0x00100000 +#define PCI_IO_SPACE_SIZE 0x00100000 +#endif + + +//PCI configuration space +#define PCI_CONFIG_VENDER_DEV 0x0000 +#define PCI_CONFIG_COMMAND 0x0004 +#define PCI_CONFIG_STATUS 0x0006 +#define PCI_CONFIG_CLASS_REVISION 0x0008 +#define PCI_CONFIG_CACHE 0x000c +#define PCI_CONFIG_LATENCY 0x000d +#define PCI_CONFIG_HEADER_TYPE 0x000e +#define PCI_CONFIG_BASE0 0x0010 +#define PCI_CONFIG_BASE1 0x0014 +#define PCI_CONFIG_BASE2 0x0018 +#define PCI_CONFIG_BASE3 0x001c +#define PCI_CONFIG_BASE4 0x0020 +#define PCI_CONFIG_BASE5 0x0024 +#define PCI_CONFIG_SUBSYSTEMVENDOR 0x002c +#define PCI_CONFIG_INT_LINE 0x003c +#define PCI_CONFIG_INT_PIN 0x003d +#define PCI_CONFIG_MAXLAN 0x003f +#define PCI_CONFIG_MINGNT 0x003e + +//PCI command register flag +#define CMD_FAST_BACK_TO_BACK (1<<9) +#define CMD_SERR (1<<8) +#define CMD_STEP_CONTROL (1<<7) +#define CMD_PARITY_ERROR_RESPONSE (1<<6) +#define CMD_VGA_PALLETE_SNOOP (1<<5) +#define CMD_WRITE_AND_INVALIDATE (1<<4) +#define CMD_SPECIAL_CYCLE (1<<3) +#define CMD_BUS_MASTER (1<<2) +#define CMD_MEM_SPACE (1<<1) +#define CMD_IO_SPACE (1<<0) + +#endif diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/printf.c b/target/linux/realtek/files/arch/mips/rtl8196b/printf.c new file mode 100644 index 000000000..650f46d27 --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/printf.c @@ -0,0 +1,51 @@ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <prom.h> +#include <platform.h> + +void __init prom_console_init(void) +{ + /* 8 bits, 1 stop bit, no parity. */ + REG8(UART0_LCR) = CHAR_LEN_8 | ONE_STOP | PARITY_DISABLE; + + /* Reset/Enable the FIFO */ + REG8(UART0_FCR) = FCR_EN | RXRST | TXRST | CHAR_TRIGGER_14; + + /* Disable All Interrupts */ + REG8(UART0_IER) = 0x00000000; + + /* Enable Divisor Latch */ + REG8(UART0_LCR) |= DLAB; + + /* Set Divisor */ + REG8(UART0_DLL) = (SYSCLK / (BAUDRATE * 16) - 1) & 0x00FF; + REG8(UART0_DLM) = ((SYSCLK / (BAUDRATE * 16) - 1) & 0xFF00) >> 8; + + /* Disable Divisor Latch */ + REG8(UART0_LCR) &= (~DLAB); +} + +int prom_putchar(char c) +{ + unsigned int busy_cnt = 0; + + do + { + /* Prevent Hanging */ + if (busy_cnt++ >= 30000) + { + /* Reset Tx FIFO */ + REG8(UART0_FCR) = TXRST | CHAR_TRIGGER_14; + return 0; + } + } while ((REG8(UART0_LSR) & LSR_THRE) == TxCHAR_AVAIL); + + /* Send Character */ + REG8(UART0_THR) = c; + + return 1; +} diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/setup.c b/target/linux/realtek/files/arch/mips/rtl8196b/setup.c new file mode 100644 index 000000000..7a2598495 --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/setup.c @@ -0,0 +1,191 @@ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/serial.h> +#include <asm/io.h> +#include <asm/time.h> + +#include <prom.h> +#include <platform.h> + +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/percpu.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/notifier.h> +#include <linux/thread_info.h> +#include <linux/time.h> +#include <linux/jiffies.h> +#include <linux/posix-timers.h> +#include <linux/cpu.h> +#include <linux/syscalls.h> +#include <linux/delay.h> + +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/div64.h> +#include <asm/timex.h> +#include <asm/io.h> + +static void __init serial_init(void); +#if 0 +static void __init rtl8652_time_init(void); +static void rtl8652_timer_ack(void); + +/* + * Called from the timer interrupt handler to charge one tick to the current + * process. user_tick is 1 if the tick is user time, 0 for system. + */ + +void local_timer_interrupt(int irq, void *dev_id) +{ +// profile_tick(CPU_PROFILING); + account_process_tick(current, user_mode(get_irq_regs())); +} +/* + * High-level timer interrupt service routines. This function + * is set as irqaction->handler and is invoked through do_IRQ. + */ + +irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + write_seqlock(&xtime_lock); + +//Add for update flash check + + rtl8652_timer_ack(); + + /* + * call the generic timer interrupt handling + */ + do_timer(1); + + + write_sequnlock(&xtime_lock); + + /* + * In UP mode, we call local_timer_interrupt() to do profiling + * and process accouting. + * + * In SMP mode, local_timer_interrupt() is invoked by appropriate + * low-level local timer interrupt handler. + */ + local_timer_interrupt(irq, dev_id); + + return IRQ_HANDLED; +} +#endif +const char *get_system_type(void) +{ + return "RTL8652"; +} + +void __init prom_init(void) +{ + prom_console_init(); + prom_meminit(); +} + +void __init plat_mem_setup(void) +{ + /* Platform Specific Setup */ + /* define io/mem region */ + ioport_resource.start = 0x18000000; + ioport_resource.end = 0x1fffffff; + + iomem_resource.start = 0x18000000; + iomem_resource.end = 0x1fffffff; + + serial_init(); + +// board_time_init = rtl8652_time_init; +// mips_timer_ack = rtl8652_timer_ack; +} + +#if 0 +static void rtl8652_timer_ack(void) +{ + REG32(TCIR) |= TC0IP; +} + +static void __init rtl8652_time_init(void) +{ + +} +#endif + +extern int rtl_clockevent_init(int irq); +//void __init plat_time_init(struct irqaction *irq) +void __init plat_time_init(void) +{ + /* Setup Timer0 */ + + /* Clear Timer IP status */ + if (REG32(TCIR) & TC0IP) + REG32(TCIR) |= TC0IP; + + /* Here irq->handler is passed from outside */ + // irq->handler = timer_interrupt; + //setup_irq(TC0_IRQ, irq); + + REG32(TCCNR) = 0; /* disable timer before setting CDBR */ + /* extend timer base to 4 times for wireless init process */ +#if 0 + REG32(CDBR) = (DIVISOR) << DIVF_OFFSET; + REG32(TC0DATA) = (MHZ * (1000 / HZ)) << TCD_OFFSET; +#else + REG32(CDBR)=(DIVISOR*4) << DIVF_OFFSET; + REG32(TC0DATA) = ((MHZ * 250) / HZ) << TCD_OFFSET; +#endif + + rtl_clockevent_init(TC0_IRQ); + /* enable timer */ + REG32(TCCNR) = TC0EN | TC0MODE_TIMER; + REG32(TCIR) = TC0IE; + #ifdef CONFIG_RTL865X_WTDOG + *(volatile unsigned long *)(0xb800311C)=0x00600000; + #endif +} + +extern int __init early_serial_setup(struct uart_port *port); +static void __init serial_init(void) +{ +#ifdef CONFIG_SERIAL_8250 + struct uart_port s; + + memset(&s, 0, sizeof(s)); + + s.line = 0; + s.type = PORT_16550A; + //s.membase = (unsigned char *) UART0_BASE; + s.mapbase = UART0_MAP_BASE; + s.membase = ioremap_nocache(s.mapbase, 0x20); + s.irq = UART0_IRQ; + //s.uartclk = SYSCLK - BAUDRATE * 24; + s.uartclk = 200000000; + //s.flags = UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SPD_CUST; + s.flags = UPF_SKIP_TEST | UPF_LOW_LATENCY; + s.iotype = UPIO_MEM; + s.regshift = 2; + //s.fifosize = 1; + s.fifosize = 16; + // s.custom_divisor = SYSCLK / (BAUDRATE * 16) - 1; + + /* Call early_serial_setup() here, to set up 8250 console driver */ + if (early_serial_setup(&s) != 0) { + panic("Serial setup failed!\n"); + } +#endif +} diff --git a/target/linux/realtek/files/arch/mips/rtl8196b/timer.c b/target/linux/realtek/files/arch/mips/rtl8196b/timer.c new file mode 100644 index 000000000..e8d58ebf8 --- /dev/null +++ b/target/linux/realtek/files/arch/mips/rtl8196b/timer.c @@ -0,0 +1,80 @@ +/* + * linux/arch/rlx/rlxocp/time.c + * + * Copyright (C) 1999 Harald Koerfgen + * Copyright (C) 2000 Pavel Machek (pavel@suse.cz) + * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Time handling functinos for Philips Nino. + */ +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <linux/delay.h> + +#include <asm/time.h> +#include <asm/rlxbsp.h> + +#include "bspchip.h" + +#ifdef CONFIG_RTL_TIMER_ADJUSTMENT +#include <rtl_types.h> +#include <rtl865xc_asicregs.h> + +void rtl865x_setupTimer1(void) +{ + WRITE_MEM32( TCCNR, READ_MEM32(TCCNR) & ~TC1EN );/* Disable timer1 */ + WRITE_MEM32( TC1DATA, 0xffffff00); + WRITE_MEM32( TCCNR, ( READ_MEM32(TCCNR) | TC1EN ) | TC1MODE_TIMER );/* Enable timer1 - timer mode */ + WRITE_MEM32( TCIR, READ_MEM32(TCIR) & ~TC1IE ); /* Disable timer1 interrupt */ +} +#endif + +void inline bsp_timer_ack(void) +{ + REG32(BSP_TCIR) |= BSP_TC0IP; +} + +void __init bsp_timer_init(void) +{ + unsigned int sys_clock_rate; + + sys_clock_rate = BSP_SYS_CLK_RATE; + + /* Clear Timer IP status */ + if (REG32(BSP_TCIR) & BSP_TC0IP) + REG32(BSP_TCIR) |= BSP_TC0IP; + + /* disable timer */ + REG32(BSP_TCCNR) = 0; /* disable timer before setting CDBR */ + + /* initialize timer registers */ + REG32(BSP_CDBR)=(BSP_DIVISOR) << BSP_DIVF_OFFSET; + REG32(BSP_TC0DATA) = (((sys_clock_rate/BSP_DIVISOR)/HZ)) << BSP_TCD_OFFSET; + // extend timer base to 4 times + //REG32(BSP_CDBR)=(BSP_DIVISOR*4) << BSP_DIVF_OFFSET; + //REG32(BSP_TC0DATA) = (((sys_clock_rate/(BSP_DIVISOR*4))/HZ)) << BSP_TCD_OFFSET; +#ifdef CONFIG_RTL_TIMER_ADJUSTMENT + rtl865x_setupTimer1(); +#endif +#if defined(CONFIG_RTK_WTDOG) + REG32(BSP_WDTCNR) = 0x00600000; +#endif + + /* hook up timer interrupt handler */ + rlx_clockevent_init(BSP_TC0_IRQ); + + /* enable timer */ + REG32(BSP_TCCNR) = BSP_TC0EN | BSP_TC0MODE_TIMER; + REG32(BSP_TCIR) = BSP_TC0IE; +} |