📄 1005.sbox-mbus-gpio.patch
字号:
+ return 0;+}++// idx : [0..3]+void em86xx_mbus_init_irq(int idx)+{+ static char *s_irqname[] = {+ "TANGO2 MBUS W0", + "TANGO2 MBUS W1", + "TANGO2 MBUS R0", + "TANGO2 MBUS R1", + };+ + if (!s_mbus_irq_inited[idx]) {+ request_irq(idx + LOG2_CPU_HOST_MBUS_W0_INT + IRQ_CONTROLLER_IRQ_BASE, em86xx_mbus_irq, SA_INTERRUPT, s_irqname[idx], (void *)idx);+ s_mbus_irq_inited[idx] = 1;+ }+}++void em86xx_mbus_irq(int irq, void *devinfo, struct pt_regs *regs)+{+ int idx = irq - (LOG2_CPU_HOST_MBUS_W0_INT + IRQ_CONTROLLER_IRQ_BASE);++ if (s_mbus_irq_handler[idx]) {+ (*s_mbus_irq_handler[idx])(irq, s_mbus_irq_handler_arg[idx]);+ s_mbus_irq_handler[idx] = NULL;+ }+}++// sbox : SBOX_xxx+// fromdev : +// 0 : TANGO2 => device (writing) : use Wx port+// 1 : device => TANGO2 (reading) : use Rx port+unsigned int em86xx_mbus_alloc_dma(int sbox, int fromdev, unsigned int *pregbase, int *pirq)+{+ int port;+ int x;++ if ((port = em86xx_sbox_connect(sbox)) < 0)+ port = -1;+ else+ x = port + (fromdev ? 0 : 2);+ + if (port >= 0) {+ if (pirq) + *pirq = LOG2_CPU_HOST_MBUS_W0_INT + IRQ_CONTROLLER_IRQ_BASE + x;+ if (pregbase) + *pregbase = REG_BASE_host_interface + MIF_W0_ADD + x * 0x40;+ }+ return(port);+}++void em86xx_mbus_free_dma(int port)+{+ em86xx_sbox_disconnect(port);+}++#define MBUS_LINEAR_MAX (0x2000 - 1)++int em86xx_mbus_setup_dma_common(unsigned int regbase, int sbox, unsigned int addr, unsigned int count, mbus_irq_handler_t handler, void *arg)+{+ int idx = (regbase - REG_BASE_host_interface - MIF_W0_ADD) / 0x40;+ int flags;++ if (em86xx_mbus_inuse(regbase) != 0) {+ printk("MBUS Error : previous command is pending\n");+ em86xx_mbus_wait(regbase, sbox); /* Wait for previous one to complete */+ }++ if (handler) {+ em86xx_mbus_init_irq(idx);+ local_irq_save(flags);+ s_mbus_irq_handler[idx] = handler;+ s_mbus_irq_handler_arg[idx] = arg;+ local_irq_restore(flags);++ }++ return 0;+}++void em86xx_mbus_setup_dma_linear(unsigned int regbase, int sbox, unsigned int addr, unsigned int count)+{+#ifndef CONFIG_SD_CDROM_DIRECT_DMA+ if ((addr < CPHYSADDR(em8xxx_kmem_start)) || (addr >= (CPHYSADDR(em8xxx_kmem_start) + em8xxx_kmem_size)))+ printk("MBUS Warning (linear): bad transfer address 0x%08lx\n", addr);+#endif++ if (em86xx_mbus_inuse(regbase) != 0) {+ printk("MBUS Error : previous command is pending (%d)\n",+ gbus_read_uint32(pGBus, regbase + MIF_cmd_offset));+ em86xx_mbus_wait(regbase, sbox); /* Wait for previous one to complete */+ }+ gbus_write_uint32(pGBus, regbase + MIF_add_offset, addr);+ gbus_write_uint32(pGBus, regbase + MIF_cnt_offset, count);+ gbus_write_uint32(pGBus, regbase + MIF_cmd_offset, 0x5);+}++void em86xx_mbus_setup_dma_double(unsigned int regbase, int sbox, unsigned int addr, unsigned int count, unsigned int addr2, unsigned int count2)+{+#ifndef CONFIG_SD_CDROM_DIRECT_DMA+ if ((addr < CPHYSADDR(em8xxx_kmem_start)) || (addr >= (CPHYSADDR(em8xxx_kmem_start) + em8xxx_kmem_size)))+ printk("MBUS Warning (double): bad transfer address 0x%08lx\n", addr);+ if ((addr2 < CPHYSADDR(em8xxx_kmem_start)) || (addr2 >= (CPHYSADDR(em8xxx_kmem_start) + em8xxx_kmem_size)))+ printk("MBUS Warning (double): bad transfer address2 0x%08lx\n", addr2);+#endif++ if (em86xx_mbus_inuse(regbase) != 0) {+ printk("MBUS Error : previous command is pending (%d)\n",+ gbus_read_uint32(pGBus, regbase + MIF_cmd_offset));+ em86xx_mbus_wait(regbase, sbox); /* Wait for previous one to complete */+ }++ gbus_write_uint32(pGBus, regbase + MIF_add_offset, addr);+ gbus_write_uint32(pGBus, regbase + MIF_cnt_offset, (count2 << 16) | count);+ gbus_write_uint32(pGBus, regbase + MIF_add2_skip_offset, addr2);+ gbus_write_uint32(pGBus, regbase + MIF_cmd_offset, 0x6);+}++void em86xx_mbus_setup_dma_rectangle(unsigned int regbase, int sbox, unsigned int addr, unsigned int horiz, unsigned int lines, int skip)+{+#ifndef CONFIG_SD_CDROM_DIRECT_DMA+ if ((addr < CPHYSADDR(em8xxx_kmem_start)) || (addr >= (CPHYSADDR(em8xxx_kmem_start) + em8xxx_kmem_size)))+ printk("MBUS Warning (rectangle): bad transfer address 0x%08lx\n", addr);+#endif++ if (em86xx_mbus_inuse(regbase) != 0) {+ printk("MBUS Error : previous command is pending (%d)\n",+ gbus_read_uint32(pGBus, regbase + MIF_cmd_offset));+ em86xx_mbus_wait(regbase, sbox); /* Wait for previous one to complete */+ }++ gbus_write_uint32(pGBus, regbase + MIF_add_offset, addr);+ gbus_write_uint32(pGBus, regbase + MIF_cnt_offset, (lines << 16) | horiz);+ gbus_write_uint32(pGBus, regbase + MIF_add2_skip_offset, horiz);+ gbus_write_uint32(pGBus, regbase + MIF_cmd_offset, 0x7);+}++int em86xx_mbus_setup_dma(unsigned int regbase, int sbox, unsigned int addr, unsigned int count, mbus_irq_handler_t handler, void *arg)+{+ if (em86xx_mbus_setup_dma_common(regbase, sbox, addr, count, handler, arg))+ return 1;++ if (em86xx_mbus_inuse(regbase) != 0) + em86xx_mbus_wait(regbase, sbox); /* Wait for previous one to complete */++ if (count <= MBUS_LINEAR_MAX) {+ // try linear+ // printk("Linear\n");+ em86xx_mbus_setup_dma_linear(regbase, sbox, addr, count);+ } else if (count <= (MBUS_LINEAR_MAX * 2)) {+ // try double+ // printk("Double (%04x, %004x)\n", MBUS_LINEAR_MAX, count - MBUS_LINEAR_MAX);+ em86xx_mbus_setup_dma_double(regbase, sbox, addr, MBUS_LINEAR_MAX, addr + MBUS_LINEAR_MAX, count - MBUS_LINEAR_MAX);+ } else {+ unsigned int i, horiz, lines, sz;++ // try rectangle+ for (i = 0, horiz = 1, sz = count; (i < 12) && ((sz & 0x01) == 0); ++i, horiz <<= 1, sz >>= 1) + ;+ lines = count >> i;+ if (horiz > MBUS_LINEAR_MAX || lines > MBUS_LINEAR_MAX) {+ printk("MBUS Error : too big to transfer (%d, %d)\n", horiz, lines);+ return 1;+ } else if ((horiz * lines) != count) {+ printk("MBUS Error : indivisible size %d (%d, %d)\n", count, horiz, lines);+ return 1;+ }+ // printk("Rectangle (%d x %d)\n", horiz, lines);+ em86xx_mbus_setup_dma_rectangle(regbase, sbox, addr, horiz, lines, horiz);+ }++ return 0;+}++int em86xx_mbus_inuse(unsigned int regbase)+{+ return ((gbus_read_uint32(pGBus, regbase + MIF_cmd_offset) & 0x7) != 0) ? 1 : 0;+}++/* Note: 06/24/2004 there're errors in the spec. The bit assignments should be+ (* indicates error)+ Bit 0/8: MBUS_R0_SBOX+ Bit 1/9: MBUS_R1_SBOX+ Bit 2/10: PCI_MASTER_SBOX+ Bit 3/11: PCI_SLAVE_SBOX+ Bit 4/12: CIPHER_SBOX+ Bit 5/13: IDE_ISA_SBOX*+ Bit 6/14: IDE_DVD_SBOX*+ Bit 7/15: SFLA_SBOX+ Bit 16/24: SBOX_MBUS_W0*+ Bit 17/25: SBOX_MBUS_W1*+ Bit 18/26: SBOX_PCI_MASTER*+ Bit 19/27: SBOX_PCI_SLAVE*+ Bit 20/28: SBOX_CIPHER*+ Bit 21/29: SBOX_ISA*+ Bit 22/30: SBOX_DVD*+*/+static unsigned int sbox_reset_vals[2][4] = {+ {0x01012020, 0x02022020, 0x20200101, 0x20200202},+ {0x01014040, 0x02024040, 0x40400101, 0x40400202}};+static unsigned int sbox_unreset_vals[2][4] = {+ {0x01002000, 0x02002000, 0x20000100, 0x20000200},+ {0x01004000, 0x02004000, 0x40000100, 0x40000200}};++void em86xx_mbus_reset(unsigned int regbase, int sbox)+{+ /* Clear MBUS transaction */+ int midx = (regbase - REG_BASE_host_interface - MIF_W0_ADD) / 0x40;+ int sidx = sbox - SBOX_IDEFLASH;++ if (em86xx_mbus_inuse(regbase) != 0) {+ int cnt;+ if (((midx < 0) || (midx > 3)) || ((sidx < 0) || (sidx > 2))) {+ printk("MBUS reset: out of range, midx %d, sidx %d\n", midx, sidx);+ return;+ } + gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_FIFO_RESET, sbox_reset_vals[sidx][midx]);+ udelay(1);+ gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_FIFO_RESET, sbox_unreset_vals[sidx][midx]);+ for (cnt = 0; (cnt < 1000) && (em86xx_mbus_inuse(regbase) != 0); cnt++)+ udelay(1);+ if (cnt >= 1000)+ printk("MBUS reset timeout\n");+ }+}++int em86xx_mbus_wait(unsigned int regbase, int sbox)+{+#define MBUS_TIMEOUT 200000 /* Max. 200msec */++ int timeout = MBUS_TIMEOUT, try = 1;++ do {+ if (timeout == 0)+ timeout = MBUS_TIMEOUT;++ while ((em86xx_mbus_inuse(regbase) != 0) && (--timeout != 0))+ udelay(1);++ if (timeout == 0) { /* Timeout happened */+ if (sbox == SBOX_IDEFLASH) {+ printk("MBUS timeout : MBUS CMD = %d, PB Automode = %08x\n", + gbus_read_uint32(pGBus, regbase + MIF_cmd_offset) & 0x7, + gbus_read_uint32(pGBus, REG_BASE_host_interface + PB_automode_control));+ } else if (sbox == SBOX_IDEDVD) {+ printk("MBUS timeout : MBUS CMD = %d, IDE dma len = %d\n", + gbus_read_uint32(pGBus, regbase + MIF_cmd_offset) & 0x7,+ gbus_read_uint32(pGBus, REG_BASE_host_interface + IDECTRL_ide_dmalen));+ } else {+ printk("MBUS timeout : MBUS CMD = %d\n", + gbus_read_uint32(pGBus, regbase + MIF_cmd_offset) & 0x7);+ }+ printk("MBUS registers : %08x %08x %08x %08x\n", + gbus_read_uint32(pGBus, regbase + MIF_add_offset),+ gbus_read_uint32(pGBus, regbase + MIF_cnt_offset),+ gbus_read_uint32(pGBus, regbase + MIF_add2_skip_offset),+ gbus_read_uint32(pGBus, regbase + MIF_cmd_offset));+ if (--try == 0) {+ printk("MBUS fails, resetting %d ..\n", sbox);+ em86xx_mbus_reset(regbase, sbox);++ /* If not able to reset, return 1, so the DMA+ can be disabled accordingly */+ return (em86xx_mbus_inuse(regbase) != 0) ? 1 : 0;+ }+ } else if (sbox == SBOX_IDEFLASH) {+ int i;+ unsigned int automode = gbus_read_uint32(pGBus, REG_BASE_host_interface + PB_automode_control);+ if ((automode & 0xffff) != 0) {+ for (i = 0; (gbus_read_uint32(pGBus, REG_BASE_host_interface + PB_automode_control) & 0xffff) && (i < MBUS_TIMEOUT); i++)+ udelay(1);+ if (i >= MBUS_TIMEOUT) {+ printk("MBUS : automode register is not empty : %08x\n",+ gbus_read_uint32(pGBus, REG_BASE_host_interface + PB_automode_control));+ if (--try == 0)+ return(1);+ else+ timeout = 0;+ }+ }+ break;+ } else+ break;+ } while (timeout == 0);++ return(0);+}++/* Fancy version of memcpy, both dst and src need to be physical address */+int mbus_memcpy(u32 dst, u32 src, u32 size)+{+ /* Save the old SBOX route */+ u32 sbox_route = gbus_read_uint32(pGBus, REG_BASE_host_interface + SBOX_ROUTE) & 0xffffff0f;+ u32 w0_base = REG_BASE_host_interface + MIF_W0_ADD;+ u32 r0_base = REG_BASE_host_interface + MIF_R0_ADD;++ /* Hook up W0/R0 and left W1/R1 the same as before */+ gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_ROUTE, 0xffffff01);+ + if (em86xx_mbus_setup_dma(w0_base, SBOX_MBUS_W0, dst, size, NULL, NULL) != 0) {+ gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_ROUTE, sbox_route);+ return(0);+ } else if (em86xx_mbus_setup_dma(r0_base, SBOX_MBUS_W0 /* HACK */, src, size, NULL, NULL) != 0) {+ /* TODO: should reset W0 */+ printk("MBUS: need to reset W0 channel.\n");+ gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_ROUTE, sbox_route);+ return(0);+ }++ /* TODO: a timeout mechanism should be added to reset W0/R0 */+ while (em86xx_mbus_inuse(r0_base) != 0)+ ;+ while (em86xx_mbus_inuse(w0_base) != 0)+ ;++ /* Restore SBOX route once we're done */+ gbus_write_uint32(pGBus, REG_BASE_host_interface + SBOX_ROUTE, sbox_route);+ return(size);+}++//+// GPIO+//+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -