⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1005.sbox-mbus-gpio.patch

📁 sm86xx内核源包括补丁( GPL )的
💻 PATCH
📖 第 1 页 / 共 3 页
字号:
+	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 + -