Power PC PSC UART Kernel Object just not working
This has got me stumped to the point where I have spent 5 days with little sleep trying to find what I did wrong. It should be simple yet it doesn't work.
All I want to do is create a test /dev/fred device driver that will allow me to test my hardware, all I want to do is transmit some bytes out PSC5. It *should* be a simple matter: 1) Make sure PSC5's PADs are configured for Function 0, DS of 1 2) Make sure SCCR1 has PSC4, 5, and 6 ENABLED 3) Configure the PSC's registers for UART mode, transmit/receive enable, all that happy stuff. 4) Have an open, close, read, write, ioctl function What happens is that everything hangs together just fine, when I open(/dev/fred) my open_iproc_psc6_uart2() gets called and everything gets configured -- I request memory, remap it, release memory as needed. When write(/dev/fred) is called, my driver's ech_write() is called and when read(/dev/fred) is called, my ech_read() driver function gets called -- great stuff, it should be *easy*. The problem is, I get nothing out the transmit pin of the PSC. I must be missing a step. Can anyone tell me if I missed a configuration register some where? A clock I need to set? I'll have to sleep on this and maybe inpiration will come but this is such a simple thing I'm trying to do, it should work. In fact I compare my code against three examples on the Internet and it looks functionally the same. Code with debugging / un-needed stuff added to try to figure out whyt nothing comes out the serial transmit pin: // ---------------------------------------------------------------------- // This is a device driver that creates /dev/fred and is used to send // and receive serial data on PSC6. It's just a test driver, something // to verify that the hardware works. // // make CROSS_COMPILE=powerpc-e300c3-linux-gnu- ARCH=powerpc // // ---------------------------------------------------------------------- #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/param.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/mm.h> #include <asm/mpc512x.h> #include <asm/mpc52xx_psc.h> #include "fdriver.h" #define DEBUG_PRN(...) if (1) printk(__VA_ARGS__) // ---------------------------------------------------------------------- // This is the PSC that we will be working with // // ---------------------------------------------------------------------- #define THIS_PSC PSC5 // ---------------------------------------------------------------------- // Local data storage // // ---------------------------------------------------------------------- static void __iomem * test_base_p; static void __iomem * sccr1_base_p; static void * mem_held_p; static void * sccr1_held_p; static ulong sccr1_value; static struct mpc52xx_psc __iomem * psc_p = (struct mpc52xx_psc __iomem *)NULL; static void report_pads(void) { ulong * pads_p = (ulong *)NULL; void __iomem * pad_base_p = (void __iomem *)NULL; int mode1 = 0; mode1 = check_mem_region(0x8000A000UL, 0x1000); if (mode1 < 0) { DEBUG_PRN("<1>Check of PAD address space %lx failed\n", 0x8000A000UL); return; } // See if we can get the address space we want if (! request_mem_region(0x8000A000UL, 0x1000, "test")) { DEBUG_PRN("<1>Unable to get PAD address space %lx\n", 0x8000A000UL); return; } DEBUG_PRN("<1>Got PAD address space %lx\n", 0x8000A000UL); // Remap the CPU registers' physical IO to a local block pad_base_p = ioremap(0x8000A000UL, 0x1000); if ((void __iomem *)NULL == pad_base_p) { DEBUG_PRN("<1>Unable to map PAD address space\n"); // Make sure to release held blocks release_mem_region(0x8000A000UL, 0x1000); return; } DEBUG_PRN("<1>PAD Registers remapped %lx\n", (ulong)pad_base_p); // See what PSC3 is set to pads_p = (pad_base_p + 0x0248); DEBUG_PRN("<1> 0x0248 is %lx\n", *pads_p); pads_p = (pad_base_p + 0x024c); DEBUG_PRN("<1> 0x024C is %lx\n", *pads_p); pads_p = (pad_base_p + 0x0250); DEBUG_PRN("<1> 0x0250 is %lx\n", *pads_p); pads_p = (pad_base_p + 0x0254); DEBUG_PRN("<1> 0x0254 is %lx\n", *pads_p); pads_p = (pad_base_p + 0x0258); DEBUG_PRN("<1> 0x0258 is %lx\n", *pads_p); // PSC4 pads_p = (pad_base_p + 0x025C); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0260); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0264); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0268); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x026C); *pads_p = 0x03UL; // PSC5 pads_p = (pad_base_p + 0x0270); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0274); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0278); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x027C); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0280); *pads_p = 0x03UL; // PSC6 pads_p = (pad_base_p + 0x0284); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0288); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x028C); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0290); *pads_p = 0x03UL; pads_p = (pad_base_p + 0x0294); *pads_p = 0x03UL; // We're done with that block iounmap((void *)pad_base_p); release_mem_region(0x8000A000UL, 0x1000); } static uchar open_iproc_psc6_uart2(void) { int mode1 = 0; int mode2 = 0; // See if we can get the address spaces we want mode1 = check_mem_region(CPU_REG_BASE, 0x1000); if (mode1 < 0) { DEBUG_PRN("<1>Check of CPU address space %lx failed\n", CPU_REG_BASE); } mode2 = check_mem_region(UART_BASE_ADD + THIS_PSC, 0x1000); if (mode2 < 0) { DEBUG_PRN("<1>Check of UART address space %lx failed\n", UART_BASE_ADD + THIS_PSC); } // Are we banned from utilizing either blocks? if (mode1 < 0 || mode2 < 0) { // Don't bother to request them, then. return(10); } // See if we can get the address space we want if (! (sccr1_held_p = request_mem_region(CPU_REG_BASE, 0x1000, "test"))) { DEBUG_PRN("<1>Unable to get CPU address space %lx\n", CPU_REG_BASE); return(10); } DEBUG_PRN("<1>Got CPU address space %lx\n", CPU_REG_BASE); if (! (mem_held_p = request_mem_region(UART_BASE_ADD + THIS_PSC, 0x1000, "test"))) { DEBUG_PRN("<1>Unable to get UART address space %lx\n", UART_BASE_ADD + THIS_PSC); // Since we successfully held the CPU base, release it release_mem_region(CPU_REG_BASE, 0x1000); return(10); } DEBUG_PRN("<1>Got UART address space %lx\n", UART_BASE_ADD + THIS_PSC); // Remap the CPU registers' physical IO to a local block sccr1_base_p = ioremap(CPU_REG_BASE, 0x1000); if ((void __iomem *)NULL == sccr1_base_p) { DEBUG_PRN("<1>Unable to map CPU address space\n"); // Make sure to release both held blocks release_mem_region(CPU_REG_BASE, 0x1000); release_mem_region(UART_BASE_ADD + THIS_PSC, 0x1000); // report the fact that it failed return(10); } DEBUG_PRN("<1>CPU Registers successfully remapped\n"); // Get the current value of the SCCR1 register sccr1_value = ioread32be(sccr1_base_p + CLOCK_BLOCK + SCCR1); DEBUG_PRN("<1>Read bef SCCR1: %lx\n", (ulong)sccr1_value); // Set bit 21, the PSC6 enable bit sccr1_value |= (1 << 21); // Set bit 22, the PSC5 enable bit sccr1_value |= (1 << 22); // Set bit 23, the PSC4 enable bit sccr1_value |= (1 << 23); // Set those bits iowrite32be(sccr1_value, sccr1_base_p + CLOCK_BLOCK + SCCR1); DEBUG_PRN("<1>Read aft SCCR1: %lx\n", (ulong)ioread32be(sccr1_base_p + CLOCK_BLOCK + SCCR1)); // get the value of CCCR sccr1_value = ioread32be(sccr1_base_p + CLOCK_BLOCK + CCCR); DEBUG_PRN("<1>Read bef CCCR: %lx\n", (ulong)sccr1_value); // And set the Clock Control Registers iowrite32be(0xFFFE0000UL, sccr1_base_p + CLOCK_BLOCK + P4SCCR); iowrite32be(0xFFFE0000UL, sccr1_base_p + CLOCK_BLOCK + P5SCCR); iowrite32be(0xFFFE0000UL, sccr1_base_p + CLOCK_BLOCK + P6SCCR); DEBUG_PRN("<1>Read aft P4SCCR: %lx P5SCCR: %lx P6SCCR: %lx\n", (ulong)ioread32be(sccr1_base_p + CLOCK_BLOCK + P4SCCR), (ulong)ioread32be(sccr1_base_p + CLOCK_BLOCK + P5SCCR), (ulong)ioread32be(sccr1_base_p + CLOCK_BLOCK + P6SCCR)); // We're done with that block iounmap((void *)sccr1_base_p); release_mem_region(CPU_REG_BASE, 0x1000); // Remap the THIS_PSCs' physical IO to a local block test_base_p = ioremap(UART_BASE_ADD + THIS_PSC, 0x1000); if ((void __iomem *)NULL == test_base_p) { DEBUG_PRN("<1>Unable to map UART address space %lx\n", UART_BASE_ADD + THIS_PSC); // Be sure to release that release_mem_region(UART_BASE_ADD + THIS_PSC, 0x1000); // Be sure to mark the fact mem_held_p = 0; return(10); } DEBUG_PRN("<1>Base PSC from %lx to %lx\n", (UART_BASE_ADD + THIS_PSC), (ulong)test_base_p); // Point to the PSC 6 psc_p = (struct mpc52xx_psc __iomem *)test_base_p; psc_p->command = MPC52xx_PSC_SEL_MODE_REG_1; psc_p->command = MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_DISABLE; psc_p->mpc52xx_psc_clock_select = 0xdd00; psc_p->sicr = 0UL; psc_p->mode = MPC52xx_PSC_MODE_8_BITS | MPC52xx_PSC_MODE_PARNONE; psc_p->mode = MPC52xx_PSC_MODE_ONE_STOP; // Baud rate psc_p->ctur = 0; psc_p->ctlr = 6; psc_p->isr_imr.imr = 0; psc_p->command = MPC52xx_PSC_RST_RX; psc_p->command = MPC52xx_PSC_RST_TX; psc_p->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE; // Report success return(0); } static void serial_putc(const char c) { if (test_base_p == (void __iomem *)NULL) { DEBUG_PRN("<1>Can not put\n"); return; } while ((psc_p->mpc52xx_psc_status & MPC52xx_PSC_SR_TXEMP) == 0x00) { } psc_p->mpc52xx_psc_buffer_8 = c; } static char serial_getc(void) { if (test_base_p == (void __iomem *)NULL) { DEBUG_PRN("<1>Can not get\n"); return(0); } while ((psc_p->mpc52xx_psc_status & MPC52xx_PSC_SR_RXRDY) == 0x00) { } return(psc_p->mpc52xx_psc_buffer_8); } static int serial_testc(void) { if (test_base_p == (void __iomem *)NULL) { DEBUG_PRN("<1>Can not test\n"); return(0); } __asm__ volatile("sync"); return((psc_p->mpc52xx_psc_status & MPC52xx_PSC_SR_RXRDY) != 0); } static int ech_ioctl(struct inode *inode_p, struct file *file_p, unsigned int cmd, unsigned long arg) { DEBUG_PRN("<1>Test driver ioctl.\n"); return(0); } static int ech_write(struct file *fp, const char *buffp, size_t sz, loff_t *fpos) { int original_size = sz; while(sz-- > 0) { serial_putc(*buffp++); } return(original_size); } static int ech_read(struct file *fp, char *buffp, size_t sz, loff_t *fpos) { ssize_t result = 0; if (test_base_p == (void __iomem *)NULL) { return(0); } while (serial_testc() && result < sz) { *buffp++ = serial_getc(); result++; } if (result > 0) { DEBUG_PRN("<1>Read of %u bytes\n", result); } else { DEBUG_PRN("<1>Read status %x - %x\n", psc_p->mpc52xx_psc_status, psc_p->mpc52xx_psc_buffer_8); } return(result); } static int ech_open(struct inode *inode, struct file *file_p) { DEBUG_PRN("<1>Test driver open.\n"); report_pads(); open_iproc_psc6_uart2(); return(0); } static int ech_release(struct inode *inode, struct file *file) { DEBUG_PRN("<1>Test driver released.\n"); if (test_base_p != (void __iomem *)NULL) { // We're done with the IO block iounmap((void *)test_base_p); test_base_p = (void __iomem *)NULL; } if (0 != mem_held_p) { release_mem_region(UART_BASE_ADD + THIS_PSC, 0x1000); mem_held_p = 0; } return(0); } // ---------------------------------------------------------------------- // Define the file structure, the pointers to the operations that // the device driver will support. // // ---------------------------------------------------------------------- struct file_operations ech_fops = { .owner = THIS_MODULE, .read = ech_read, .write = ech_write, .ioctl = ech_ioctl, .open = ech_open, .release = ech_release } ; int ech_init_module(void) { int stat = 0; test_base_p = (void __iomem *)NULL; sccr1_base_p = (void __iomem *)NULL; mem_held_p = (void *)NULL; sccr1_held_p = (void *)NULL; // Register the device stat = register_chrdev(DEV_MAJOR, DEV_NAME, &ech_fops); // Was that successful? if (stat < 0) { DEBUG_PRN("<1>Error registering test driver\n"); } else { DEBUG_PRN("<1>Successfully registered %s with %u\n", DEV_NAME, stat); } // Return the result of the registration effort return(stat); } void __exit ech_cleanup_module (void) { // Unregister the device unregister_chrdev(DEV_MAJOR, DEV_NAME); // Report the fact that the registration was removed DEBUG_PRN("<1>Test driver removed.\n"); } module_init(ech_init_module); module_exit(ech_cleanup_module); MODULE_LICENSE("Proprietary"); MODULE_DESCRIPTION("Fred Testing"); |
This thread is marked Solved, but I see no explanation here.
Why is that ? |
All times are GMT -5. The time now is 07:08 AM. |