📄 cpm_uart_core.c
字号:
bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; /* Get next BD. */ if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; pinfo->tx_cur = bdp; port->icount.tx++; port->x_char = 0; return 1; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { cpm_uart_stop_tx(port); return 0; } /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; p = cpm2cpu_addr(bdp->cbd_bufaddr); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count++; if (xmit->head == xmit->tail) break; } bdp->cbd_datlen = count; bdp->cbd_sc |= BD_SC_READY; __asm__("eieio"); /* Get next BD. */ if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; } pinfo->tx_cur = bdp; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) { cpm_uart_stop_tx(port); return 0; } return 1;}/* * init buffer descriptors */static void cpm_uart_initbd(struct uart_cpm_port *pinfo){ int i; u8 *mem_addr; volatile cbd_t *bdp; pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; mem_addr += pinfo->rx_fifosize; } bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_INTRPT; mem_addr += pinfo->tx_fifosize; } bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;}static void cpm_uart_init_scc(struct uart_cpm_port *pinfo){ int line = pinfo - cpm_uart_ports; volatile scc_t *scp; volatile scc_uart_t *sup; pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); scp = pinfo->sccp; sup = pinfo->sccup; /* Store address */ pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE; pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE; /* Set up the uart parameters in the * parameter ram. */ cpm_set_scc_fcr(sup); sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize; sup->scc_maxidl = pinfo->rx_fifosize; sup->scc_brkcr = 1; sup->scc_parec = 0; sup->scc_frmec = 0; sup->scc_nosec = 0; sup->scc_brkec = 0; sup->scc_uaddr1 = 0; sup->scc_uaddr2 = 0; sup->scc_toseq = 0; sup->scc_char1 = 0x8000; sup->scc_char2 = 0x8000; sup->scc_char3 = 0x8000; sup->scc_char4 = 0x8000; sup->scc_char5 = 0x8000; sup->scc_char6 = 0x8000; sup->scc_char7 = 0x8000; sup->scc_char8 = 0x8000; sup->scc_rccm = 0xc0ff; /* Send the CPM an initialize command. */ cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ scp->scc_gsmrh = 0; scp->scc_gsmrl = (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); /* Enable rx interrupts and clear all pending events. */ scp->scc_sccm = 0; scp->scc_scce = 0xffff; scp->scc_dsr = 0x7e7e; scp->scc_psmr = 0x3000; scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);}static void cpm_uart_init_smc(struct uart_cpm_port *pinfo){ int line = pinfo - cpm_uart_ports; volatile smc_t *sp; volatile smc_uart_t *up; pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); sp = pinfo->smcp; up = pinfo->smcup; /* Store address */ pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE; pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;/* * In case SMC1 is being relocated... */#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) up->smc_rbptr = pinfo->smcup->smc_rbase; up->smc_tbptr = pinfo->smcup->smc_tbase; up->smc_rstate = 0; up->smc_tstate = 0; up->smc_brkcr = 1; /* number of break chars */ up->smc_brkec = 0;#endif /* Set up the uart parameters in the * parameter ram. */ cpm_set_smc_fcr(up); /* Using idle charater time requires some additional tuning. */ up->smc_mrblr = pinfo->rx_fifosize; up->smc_maxidl = pinfo->rx_fifosize; up->smc_brklen = 0; up->smc_brkec = 0; up->smc_brkcr = 1; cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; /* Enable only rx interrupts clear all pending events. */ sp->smc_smcm = 0; sp->smc_smce = 0xff; sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);}/* * Initialize port. This is called from early_console stuff * so we have to be careful here ! */static int cpm_uart_request_port(struct uart_port *port){ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; int ret; pr_debug("CPM uart[%d]:request port\n", port->line); if (pinfo->flags & FLAG_CONSOLE) return 0; /* * Setup any port IO, connect any baud rate generators, * etc. This is expected to be handled by board * dependant code */ if (pinfo->set_lineif) pinfo->set_lineif(pinfo); if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); } else { pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 0); if (ret) return ret; cpm_uart_initbd(pinfo); if (IS_SMC(pinfo)) cpm_uart_init_smc(pinfo); else cpm_uart_init_scc(pinfo); return 0;}static void cpm_uart_release_port(struct uart_port *port){ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; if (!(pinfo->flags & FLAG_CONSOLE)) cpm_uart_freebuf(pinfo);}/* * Configure/autoconfigure the port. */static void cpm_uart_config_port(struct uart_port *port, int flags){ pr_debug("CPM uart[%d]:config_port\n", port->line); if (flags & UART_CONFIG_TYPE) { port->type = PORT_CPM; cpm_uart_request_port(port); }}static struct uart_ops cpm_uart_pops = { .tx_empty = cpm_uart_tx_empty, .set_mctrl = cpm_uart_set_mctrl, .get_mctrl = cpm_uart_get_mctrl, .stop_tx = cpm_uart_stop_tx, .start_tx = cpm_uart_start_tx, .stop_rx = cpm_uart_stop_rx, .enable_ms = cpm_uart_enable_ms, .break_ctl = cpm_uart_break_ctl, .startup = cpm_uart_startup, .shutdown = cpm_uart_shutdown, .set_termios = cpm_uart_set_termios, .type = cpm_uart_type, .release_port = cpm_uart_release_port, .request_port = cpm_uart_request_port, .config_port = cpm_uart_config_port, .verify_port = cpm_uart_verify_port,};struct uart_cpm_port cpm_uart_ports[UART_NR] = { [UART_SMC1] = { .port = { .irq = SMC1_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc1_lineif, }, [UART_SMC2] = { .port = { .irq = SMC2_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc2_lineif,#ifdef CONFIG_SERIAL_CPM_ALT_SMC2 .is_portb = 1,#endif }, [UART_SCC1] = { .port = { .irq = SCC1_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc1_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC2] = { .port = { .irq = SCC2_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc2_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC3] = { .port = { .irq = SCC3_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc3_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC4] = { .port = { .irq = SCC4_IRQ, .ops = &cpm_uart_pops, .iotype = SERIAL_IO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc4_lineif, .wait_closing = SCC_WAIT_CLOSING, },};#ifdef CONFIG_SERIAL_CPM_CONSOLE/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * Note that this is called with interrupts already disabled */static void cpm_uart_console_write(struct console *co, const char *s, u_int count){ struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]]; unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; bdbase = pinfo->tx_bd_base; /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while ((bdp->cbd_sc & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(bdp->cbd_bufaddr); *cp = *s; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while ((bdp->cbd_sc & BD_SC_READY) != 0) ; cp = cpm2cpu_addr(bdp->cbd_bufaddr); *cp = 13; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((bdp->cbd_sc & BD_SC_READY) != 0) ; pinfo->tx_cur = (volatile cbd_t *) bdp;}/* * Setup console. Be careful is called early ! */static int __init cpm_uart_console_setup(struct console *co, char *options){ struct uart_port *port; struct uart_cpm_port *pinfo; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; port = (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; pinfo = (struct uart_cpm_port *)port; pinfo->flags |= FLAG_CONSOLE; if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); } else { bd_t *bd = (bd_t *) __res; if (bd->bi_baudrate) baud = bd->bi_baudrate; else baud = 9600; } /* * Setup any port IO, connect any baud rate generators, * etc. This is expected to be handled by board * dependant code */ if (pinfo->set_lineif) pinfo->set_lineif(pinfo); if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); } else { pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 1); if (ret) return ret; cpm_uart_initbd(pinfo); if (IS_SMC(pinfo)) cpm_uart_init_smc(pinfo); else cpm_uart_init_scc(pinfo); uart_set_options(port, co, baud, parity, bits, flow); return 0;}static struct uart_driver cpm_reg;static struct console cpm_scc_uart_console = { .name = "ttyCPM", .write = cpm_uart_console_write, .device = uart_console_device, .setup = cpm_uart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &cpm_reg,};int __init cpm_uart_console_init(void){ int ret = cpm_uart_init_portdesc(); if (!ret) register_console(&cpm_scc_uart_console); return ret;}console_initcall(cpm_uart_console_init);#define CPM_UART_CONSOLE &cpm_scc_uart_console#else#define CPM_UART_CONSOLE NULL#endifstatic struct uart_driver cpm_reg = { .owner = THIS_MODULE, .driver_name = "ttyCPM", .dev_name = "ttyCPM", .major = SERIAL_CPM_MAJOR, .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE,};static int __init cpm_uart_init(void){ int ret, i; printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n");#ifndef CONFIG_SERIAL_CPM_CONSOLE ret = cpm_uart_init_portdesc(); if (ret) return ret;#endif cpm_reg.nr = cpm_uart_nr; ret = uart_register_driver(&cpm_reg); if (ret) return ret; for (i = 0; i < cpm_uart_nr; i++) { int con = cpm_uart_port_map[i]; cpm_uart_ports[con].port.line = i; cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); } return ret;}static void __exit cpm_uart_exit(void){ int i; for (i = 0; i < cpm_uart_nr; i++) { int con = cpm_uart_port_map[i]; uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port); } uart_unregister_driver(&cpm_reg);}module_init(cpm_uart_init);module_exit(cpm_uart_exit);MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -