LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   Power PC PSC UART Kernel Object just not working (https://www.linuxquestions.org/questions/linux-software-2/power-pc-psc-uart-kernel-object-just-not-working-802894/)

DamOTclese 04-19-2010 12:48 PM

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");

smoker 05-03-2010 06:16 AM

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.