Writing to a device at a known physical address - Embedded

This is a discussion on Writing to a device at a known physical address - Embedded ; I know this is a pretty basic question but bear with me. I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I ported the Colilo boot loader and made some mods to the kernel to run on a custom ...

+ Reply to Thread
Results 1 to 15 of 15

Thread: Writing to a device at a known physical address

  1. Writing to a device at a known physical address


    I know this is a pretty basic question but bear with me.

    I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I
    ported the Colilo boot loader and made some mods to the kernel to run
    on a custom board and things are working really well. Now I need to
    access particular hardware that are configured (on a Flexbus) at
    particular addresses. A simple example are the LED's that are used for
    indicating life in the system. They are mapped to 0x4200 0000 and I
    can access them easily from the boot loader. However once Linux is up
    and running I get seg faults when I try to write to that address. This
    makes sense since the MMU is remapping where things are but how do I
    work with that? How do I know where these devices are in memory and
    how do I get to them? Must it be done as a driver in kernel space
    rather than user space?

    Any help much appreciated!!

  2. Re: Writing to a device at a known physical address

    James Kimble wrote:

    >
    > I know this is a pretty basic question but bear with me.
    >
    > I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I
    > ported the Colilo boot loader and made some mods to the kernel to run
    > on a custom board and things are working really well. Now I need to
    > access particular hardware that are configured (on a Flexbus) at
    > particular addresses. A simple example are the LED's that are used for
    > indicating life in the system. They are mapped to 0x4200 0000 and I
    > can access them easily from the boot loader. However once Linux is up
    > and running I get seg faults when I try to write to that address. This
    > makes sense since the MMU is remapping where things are but how do I
    > work with that? How do I know where these devices are in memory and
    > how do I get to them? Must it be done as a driver in kernel space
    > rather than user space?


    Open the /dev/mem device node and work with mmap() on it.

    Or switch to a current 2.6.23 kernel and you can use the UIO driver instead,
    to access memory mapped hardware from userspace.

    JB


  3. Re: Writing to a device at a known physical address

    On Dec 11, 4:13 am, Juergen Beisert wrote:
    > James Kimble wrote:
    >
    > > I know this is a pretty basic question but bear with me.

    >
    > > I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I
    > > ported the Colilo boot loader and made some mods to the kernel to run
    > > on a custom board and things are working really well. Now I need to
    > > access particular hardware that are configured (on a Flexbus) at
    > > particular addresses. A simple example are the LED's that are used for
    > > indicating life in the system. They are mapped to 0x4200 0000 and I
    > > can access them easily from the boot loader. However once Linux is up
    > > and running I get seg faults when I try to write to that address. This
    > > makes sense since the MMU is remapping where things are but how do I
    > > work with that? How do I know where these devices are in memory and
    > > how do I get to them? Must it be done as a driver in kernel space
    > > rather than user space?

    >
    > Open the /dev/mem device node and work with mmap() on it.
    >
    > Or switch to a current 2.6.23 kernel and you can use the UIO driver instead,
    > to access memory mapped hardware from userspace.
    >
    > JB


    Can you give an example of this? I've been looking at mmap usage and
    it's
    not real clear...

  4. Re: Writing to a device at a known physical address

    On Dec 12, 2:03 am, James Kimble wrote:
    > On Dec 11, 4:13 am, Juergen Beisert wrote:
    >
    >
    >
    > > James Kimble wrote:

    >
    > > > I know this is a pretty basic question but bear with me.

    >
    > > > I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I
    > > > ported the Colilo boot loader and made some mods to the kernel to run
    > > > on a custom board and things are working really well. Now I need to
    > > > access particular hardware that are configured (on a Flexbus) at
    > > > particular addresses. A simple example are the LED's that are used for
    > > > indicating life in the system. They are mapped to 0x4200 0000 and I
    > > > can access them easily from the boot loader. However once Linux is up
    > > > and running I get seg faults when I try to write to that address. This
    > > > makes sense since the MMU is remapping where things are but how do I
    > > > work with that? How do I know where these devices are in memory and
    > > > how do I get to them? Must it be done as a driver in kernel space
    > > > rather than user space?

    >
    > > Open the /dev/mem device node and work with mmap() on it.

    >
    > > Or switch to a current 2.6.23 kernel and you can use the UIO driver instead,
    > > to access memory mapped hardware from userspace.

    >
    > > JB

    >
    > Can you give an example of this? I've been looking at mmap usage and
    > it's
    > not real clear...


    Full man can be found at
    http://linux.die.net/man/3/mmap

    Example:
    /*
    * Maps real memory address to a virtual address. The virtual address
    * then could be used to read/write the real memory as if it was
    accessed
    * directly.
    * Adapted by Janaka Subhawickrama. Copyright 2007.
    * GPL software.
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include


    //Virtual address that is associated with the physical address
    static char *regmap_addr = NULL;

    //The following is the physical address of memory mapped registers of
    the CPU
    #define REGISTRY_MAP_ADDRESS_OFFSET (0xE0000000)
    #define REGISTRY_MAP_SIZE (0x000FFFFF)
    #define GPIO2_DATA_DIR_REG_OFFSET (0x00000D00)
    #define GPIO2_DATA_REG_OFFSET (0x00000D08)

    #define GPIO2_DONE_PIN (0x00800000)
    #define GPIO2_FAULT_PIN (0x00400000)
    #define GPIO2_PROGB_PIN (0x01000000)


    int main(int argc, char *argv[])
    {
    int devmem; // this is the "/dev/mem" descriptor
    //Registers of the CPU I am using is 32bit
    volatile unsigned int uiGet;
    volatile unsigned int *ptmp = NULL;

    //On embedded systems you may have to mknod /dev/mem
    printf("\nOpening /dev/mem");
    devmem = open("/dev/mem", O_RDWR | O_SYNC);

    if (devmem < 0)
    {
    printf("\nOpening of /dev/mem failed with (%d) %s\n", errno,
    strerror(errno));
    return -1;
    }

    printf("\nMapping Memory mapped registers at %08X with size %08X",
    REGISTRY_MAP_SIZE, REGISTRY_MAP_ADDRESS_OFFSET);
    regmap_addr = (char *)mmap( 0, REGISTRY_MAP_SIZE, PROT_READ|
    PROT_WRITE, MAP_SHARED, devmem, REGISTRY_MAP_ADDRESS_OFFSET);

    if (regmap_addr == (char *)MAP_FAILED)
    {
    printf("\nCould not map registers (%d) %s", errno, strerror(errno));
    close(devmem);
    return -1;
    }

    //Now you can write to CPU registers as if you were from a boot
    loader

    //Setup directions of GPIO pins
    *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_DIR_REG_OFFSET) =
    GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    //Turn some GPIO Pins on
    *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    //Get some values of GPIO lines
    uiGet = *(volatile unsigned int *)(regmap_addr +
    GPIO2_DATA_REG_OFFSET);

    printf("\nGPIO register %08X", uiGet);

    //Cleanup
    munmap((void *)REGISTRY_MAP_ADDRESS_OFFSET, REGISTRY_MAP_SIZE);
    close(devmem);
    return 0;
    }

  5. Re: Writing to a device at a known physical address

    On Dec 11, 6:07 pm, Janaka wrote:
    > On Dec 12, 2:03 am, James Kimble wrote:
    >
    >
    >
    > > On Dec 11, 4:13 am, Juergen Beisert wrote:

    >
    > > > James Kimble wrote:

    >
    > > > > I know this is a pretty basic question but bear with me.

    >
    > > > > I'm running Linux (2.6.10) on a Freescale Coldfire (M5484) chip. I
    > > > > ported the Colilo boot loader and made some mods to the kernel to run
    > > > > on a custom board and things are working really well. Now I need to
    > > > > access particular hardware that are configured (on a Flexbus) at
    > > > > particular addresses. A simple example are the LED's that are used for
    > > > > indicating life in the system. They are mapped to 0x4200 0000 and I
    > > > > can access them easily from the boot loader. However once Linux is up
    > > > > and running I get seg faults when I try to write to that address. This
    > > > > makes sense since the MMU is remapping where things are but how do I
    > > > > work with that? How do I know where these devices are in memory and
    > > > > how do I get to them? Must it be done as a driver in kernel space
    > > > > rather than user space?

    >
    > > > Open the /dev/mem device node and work with mmap() on it.

    >
    > > > Or switch to a current 2.6.23 kernel and you can use the UIO driver instead,
    > > > to access memory mapped hardware from userspace.

    >
    > > > JB

    >
    > > Can you give an example of this? I've been looking at mmap usage and
    > > it's
    > > not real clear...

    >
    > Full man can be found athttp://linux.die.net/man/3/mmap
    >
    > Example:
    > /*
    > * Maps real memory address to a virtual address. The virtual address
    > * then could be used to read/write the real memory as if it was
    > accessed
    > * directly.
    > * Adapted by Janaka Subhawickrama. Copyright 2007.
    > * GPL software.
    > */
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    >
    > //Virtual address that is associated with the physical address
    > static char *regmap_addr = NULL;
    >
    > //The following is the physical address of memory mapped registers of
    > the CPU
    > #define REGISTRY_MAP_ADDRESS_OFFSET (0xE0000000)
    > #define REGISTRY_MAP_SIZE (0x000FFFFF)
    > #define GPIO2_DATA_DIR_REG_OFFSET (0x00000D00)
    > #define GPIO2_DATA_REG_OFFSET (0x00000D08)
    >
    > #define GPIO2_DONE_PIN (0x00800000)
    > #define GPIO2_FAULT_PIN (0x00400000)
    > #define GPIO2_PROGB_PIN (0x01000000)
    >
    > int main(int argc, char *argv[])
    > {
    > int devmem; // this is the "/dev/mem" descriptor
    > //Registers of the CPU I am using is 32bit
    > volatile unsigned int uiGet;
    > volatile unsigned int *ptmp = NULL;
    >
    > //On embedded systems you may have to mknod /dev/mem
    > printf("\nOpening /dev/mem");
    > devmem = open("/dev/mem", O_RDWR | O_SYNC);
    >
    > if (devmem < 0)
    > {
    > printf("\nOpening of /dev/mem failed with (%d) %s\n", errno,
    > strerror(errno));
    > return -1;
    > }
    >
    > printf("\nMapping Memory mapped registers at %08X with size %08X",
    > REGISTRY_MAP_SIZE, REGISTRY_MAP_ADDRESS_OFFSET);
    > regmap_addr = (char *)mmap( 0, REGISTRY_MAP_SIZE, PROT_READ|
    > PROT_WRITE, MAP_SHARED, devmem, REGISTRY_MAP_ADDRESS_OFFSET);
    >
    > if (regmap_addr == (char *)MAP_FAILED)
    > {
    > printf("\nCould not map registers (%d) %s", errno, strerror(errno));
    > close(devmem);
    > return -1;
    > }
    >
    > //Now you can write to CPU registers as if you were from a boot
    > loader
    >
    > //Setup directions of GPIO pins
    > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_DIR_REG_OFFSET) =
    > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > //Turn some GPIO Pins on
    > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > //Get some values of GPIO lines
    > uiGet = *(volatile unsigned int *)(regmap_addr +
    > GPIO2_DATA_REG_OFFSET);
    >
    > printf("\nGPIO register %08X", uiGet);
    >
    > //Cleanup
    > munmap((void *)REGISTRY_MAP_ADDRESS_OFFSET, REGISTRY_MAP_SIZE);
    > close(devmem);
    > return 0;
    >
    > }


    That helps!! Thanks a ton!!

  6. Re: Writing to a device at a known physical address

    Janaka wrote:
    > //Turn some GPIO Pins on
    > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > //Get some values of GPIO lines
    > uiGet = *(volatile unsigned int *)(regmap_addr +
    > GPIO2_DATA_REG_OFFSET);


    As you are talking to hardware, at this point you should consider there are
    architectures in the wild that do some kind of access reordering in
    hardware.
    For example PowerPC: In your example it will do the read access prior the
    (buffered) write access (even if the compiler generates code in the other
    order!). Your program would fail at least on this architecture.

    So: Do not use volatile types in this way. Use the read?()/write?() inline
    functions from the architecture specific part of the linux source instead
    (refer include/asm-/io.h). Its more save, more portable and the
    source is easier to read.

    JB

  7. Re: Writing to a device at a known physical address

    On Dec 12, 2:51 am, Juergen Beisert wrote:
    > Janaka wrote:
    > > //Turn some GPIO Pins on
    > > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > > //Get some values of GPIO lines
    > > uiGet = *(volatile unsigned int *)(regmap_addr +
    > > GPIO2_DATA_REG_OFFSET);

    >
    > As you are talking to hardware, at this point you should consider there are
    > architectures in the wild that do some kind of access reordering in
    > hardware.
    > For example PowerPC: In your example it will do the read access prior the
    > (buffered) write access (even if the compiler generates code in the other
    > order!). Your program would fail at least on this architecture.
    >
    > So: Do not use volatile types in this way. Use the read?()/write?() inline
    > functions from the architecture specific part of the linux source instead
    > (refer include/asm-/io.h). Its more save, more portable and the
    > source is easier to read.
    >
    > JB



    I worked with this simple example:

    #include
    #include
    #include
    #include
    #include
    #include


    void* mmio_map(off_t PhysAddr, unsigned long Size)
    {
    off_t PageOffset, PageAddress;
    void *base;
    int fd;

    PageOffset = PhysAddr % getpagesize();;
    PageAddress = PhysAddr - PageOffset;
    Size += PageOffset;

    if((fd = open("/dev/mem", O_RDWR)) < 0)
    {
    perror("open(/dev/mem)");
    return(NULL);
    }

    base = mmap ((caddr_t)0, Size, PROT_READ|PROT_WRITE, MAP_SHARED,
    fd, PageAddress);

    if (base == MAP_FAILED)
    {
    return((void*)NULL);
    }
    else
    {
    return((void*)((char*)base + PageOffset));
    }
    }

    void mmio_unmap(void* VirtAddr, unsigned long Size)
    {
    off_t PageOffset, PageAddress;

    PageOffset = (off_t)VirtAddr % getpagesize();;
    PageAddress = (off_t)VirtAddr - PageOffset;
    Size += PageOffset;

    munmap((void*)PageAddress, Size);
    }


    // To access your registers, you would do something like this:
    main()
    {
    int i;
    volatile unsigned short *leds;

    leds = (unsigned short*)mmio_map(0x42000000, sizeof(*leds));

    if (!leds)
    {
    perror("mmap");
    exit(1);
    }

    for (i=0; i < 5; i++)
    {
    *leds = 0xa5ff; /* Alternate leds on from 0 */
    sleep(1);
    *leds = 0x5aff; /* Alternate leds on from 1 */
    }

    mmio_unmap((void*)leds, sizeof(*leds));
    }


    Which works to an extent but I have two issues I don't understand.
    Firstly I get an "Illegal instruction" message with each run. I put in
    some comments and the message comes at the end of execution (no
    particular instruction). Secondly the "leds" get set to each
    configuration only once rather than switching back and forth as I
    would expect from the loop. I tried putting in an msync (MS_SYNC flag)
    after each setting of "leds" but it made no difference. Why doesn't
    the memory map update with each change?

    BTW thanks for the help,


  8. Re: Writing to a device at a known physical address

    On Dec 12, 6:51 pm, Juergen Beisert wrote:
    > Janaka wrote:
    > > //Turn some GPIO Pins on
    > > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > > //Get some values of GPIO lines
    > > uiGet = *(volatile unsigned int *)(regmap_addr +
    > > GPIO2_DATA_REG_OFFSET);

    >
    > As you are talking to hardware, at this point you should consider there are
    > architectures in the wild that do some kind of access reordering in
    > hardware.
    > For example PowerPC: In your example it will do the read access prior the
    > (buffered) write access (even if the compiler generates code in the other
    > order!). Your program would fail at least on this architecture.
    >
    > So: Do not use volatile types in this way. Use the read?()/write?() inline
    > functions from the architecture specific part of the linux source instead
    > (refer include/asm-/io.h). Its more save, more portable and the
    > source is easier to read.
    >
    > JB


    Thanks Juergen. Anything else that I should lookout for when
    accessing mmaped space ? I have come up with one HW design flaw where
    some of the registers on the chip are middle-endian while others are
    little-endian.
    BTW I am using MPC8349 in little-endian mode with PowerPC arch type
    (not PPC). And it works as expected so far. Does this re-ordering
    happen with optimized compiler options or is this HW architecture
    cache lining caveat ? As you may be aware of the MPC8349 uses the
    e300 core and its has a beast of a doc.

  9. Re: Writing to a device at a known physical address

    On Dec 13, 1:39 am, James Kimble wrote:
    > On Dec 12, 2:51 am, Juergen Beisert wrote:
    >
    >
    >
    > > Janaka wrote:
    > > > //Turn some GPIO Pins on
    > > > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > > > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > > > //Get some values of GPIO lines
    > > > uiGet = *(volatile unsigned int *)(regmap_addr +
    > > > GPIO2_DATA_REG_OFFSET);

    >
    > > As you are talking to hardware, at this point you should consider there are
    > > architectures in the wild that do some kind of access reordering in
    > > hardware.
    > > For example PowerPC: In your example it will do the read access prior the
    > > (buffered) write access (even if the compiler generates code in the other
    > > order!). Your program would fail at least on this architecture.

    >
    > > So: Do not use volatile types in this way. Use the read?()/write?() inline
    > > functions from the architecture specific part of the linux source instead
    > > (refer include/asm-/io.h). Its more save, more portable and the
    > > source is easier to read.

    >
    > > JB

    >
    > I worked with this simple example:
    >
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    >
    > void* mmio_map(off_t PhysAddr, unsigned long Size)
    > {
    > off_t PageOffset, PageAddress;
    > void *base;
    > int fd;
    >
    > PageOffset = PhysAddr % getpagesize();;
    > PageAddress = PhysAddr - PageOffset;
    > Size += PageOffset;
    >
    > if((fd = open("/dev/mem", O_RDWR)) < 0)
    > {
    > perror("open(/dev/mem)");
    > return(NULL);
    > }
    >
    > base = mmap ((caddr_t)0, Size, PROT_READ|PROT_WRITE, MAP_SHARED,
    > fd, PageAddress);
    >
    > if (base == MAP_FAILED)
    > {
    > return((void*)NULL);
    > }
    > else
    > {
    > return((void*)((char*)base + PageOffset));
    > }
    >
    > }
    >
    > void mmio_unmap(void* VirtAddr, unsigned long Size)
    > {
    > off_t PageOffset, PageAddress;
    >
    > PageOffset = (off_t)VirtAddr % getpagesize();;
    > PageAddress = (off_t)VirtAddr - PageOffset;
    > Size += PageOffset;
    >
    > munmap((void*)PageAddress, Size);
    >
    > }
    >
    > // To access your registers, you would do something like this:
    > main()
    > {
    > int i;
    > volatile unsigned short *leds;
    >
    > leds = (unsigned short*)mmio_map(0x42000000, sizeof(*leds));
    >
    > if (!leds)
    > {
    > perror("mmap");
    > exit(1);
    > }
    >
    > for (i=0; i < 5; i++)
    > {
    > *leds = 0xa5ff; /* Alternate leds on from 0 */
    > sleep(1);
    > *leds = 0x5aff; /* Alternate leds on from 1 */
    > }
    >
    > mmio_unmap((void*)leds, sizeof(*leds));
    >
    > }
    >
    > Which works to an extent but I have two issues I don't understand.
    > Firstly I get an "Illegal instruction" message with each run. I put in
    > some comments and the message comes at the end of execution (no
    > particular instruction). Secondly the "leds" get set to each
    > configuration only once rather than switching back and forth as I
    > would expect from the loop. I tried putting in an msync (MS_SYNC flag)
    > after each setting of "leds" but it made no difference. Why doesn't
    > the memory map update with each change?
    >
    > BTW thanks for the help,


    1. You should munmap the exact memory space (Virtual address and
    size) that you Mmaped. So I would guess that the illigal instruction
    happens when you try to munmap it.
    2. Note that in your loop, you set the leds to 0x5aff and immidiately
    set it to 0xa5ff on the next loop cycle. What this would mean is you
    would not see one of the LED states when the loop is run (too quick
    for your eye). Put another sleep(1) after "*leds = 0x5aff; /*
    Alternate leds on from 1 */" line. Note that depending on how the
    LEDs are wired and how the registers are setup the actual LED state
    could be ON for a 0 and OFF for a 1.

  10. Re: Writing to a device at a known physical address

    Hi Janaka,

    Janaka wrote:
    > On Dec 12, 6:51 pm, Juergen Beisert wrote:
    >> Janaka wrote:
    >> > //Turn some GPIO Pins on
    >> > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    >> > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    >> > //Get some values of GPIO lines
    >> > uiGet = *(volatile unsigned int *)(regmap_addr +
    >> > GPIO2_DATA_REG_OFFSET);

    >>
    >> As you are talking to hardware, at this point you should consider there
    >> are architectures in the wild that do some kind of access reordering in
    >> hardware.
    >> For example PowerPC: In your example it will do the read access prior the
    >> (buffered) write access (even if the compiler generates code in the other
    >> order!). Your program would fail at least on this architecture.
    >>
    >> So: Do not use volatile types in this way. Use the read?()/write?()
    >> inline functions from the architecture specific part of the linux source
    >> instead (refer include/asm-/io.h). Its more save, more
    >> portable and the source is easier to read.
    >>
    >> JB

    >
    > Thanks Juergen. Anything else that I should lookout for when
    > accessing mmaped space ? I have come up with one HW design flaw where
    > some of the registers on the chip are middle-endian while others are
    > little-endian.
    > BTW I am using MPC8349 in little-endian mode with PowerPC arch type
    > (not PPC). And it works as expected so far. Does this re-ordering
    > happen with optimized compiler options or is this HW architecture
    > cache lining caveat ?


    That's the problem. This reordering happens in hardware. So the compiler has
    *no* effect on it. But I'm not sure if it happens on all PPC cores. Its
    easy to understand: A read access would stop program execution, while a
    write access can be done in background later while program execution
    continues. This increases the execution speed when you are working with
    regular RAM (with or without cache). But could crash, when there is no RAM
    and hardware registers instead.
    As the CPU works with the same mnemonics, it cannot differentiate if it
    talks to RAM or hardware. Same is done on x86: But there are chipset
    related register bits to set, that forbits reordering in *some* address
    areas. Don't know if something like this also exists on PPC/PowerPC.

    You need the "sync" command between all hardware access commands.
    The "volatile" keeps command order in assembler in sync with your C code
    and the "sync" command keeps assembler command order and execution order in
    sync. Very easy ;-)

    JB

  11. Re: Writing to a device at a known physical address

    On Dec 12, 6:22 pm, Janaka wrote:
    > On Dec 13, 1:39 am, James Kimble wrote:
    >
    >
    >
    > > On Dec 12, 2:51 am, Juergen Beisert wrote:

    >
    > > > Janaka wrote:
    > > > > //Turn some GPIO Pins on
    > > > > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > > > > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > > > > //Get some values of GPIO lines
    > > > > uiGet = *(volatile unsigned int *)(regmap_addr +
    > > > > GPIO2_DATA_REG_OFFSET);

    >
    > > > As you are talking to hardware, at this point you should consider there are
    > > > architectures in the wild that do some kind of access reordering in
    > > > hardware.
    > > > For example PowerPC: In your example it will do the read access prior the
    > > > (buffered) write access (even if the compiler generates code in the other
    > > > order!). Your program would fail at least on this architecture.

    >
    > > > So: Do not use volatile types in this way. Use the read?()/write?() inline
    > > > functions from the architecture specific part of the linux source instead
    > > > (refer include/asm-/io.h). Its more save, more portable and the
    > > > source is easier to read.

    >
    > > > JB

    >
    > > I worked with this simple example:

    >
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include

    >
    > > void* mmio_map(off_t PhysAddr, unsigned long Size)
    > > {
    > > off_t PageOffset, PageAddress;
    > > void *base;
    > > int fd;

    >
    > > PageOffset = PhysAddr % getpagesize();;
    > > PageAddress = PhysAddr - PageOffset;
    > > Size += PageOffset;

    >
    > > if((fd = open("/dev/mem", O_RDWR)) < 0)
    > > {
    > > perror("open(/dev/mem)");
    > > return(NULL);
    > > }

    >
    > > base = mmap ((caddr_t)0, Size, PROT_READ|PROT_WRITE, MAP_SHARED,
    > > fd, PageAddress);

    >
    > > if (base == MAP_FAILED)
    > > {
    > > return((void*)NULL);
    > > }
    > > else
    > > {
    > > return((void*)((char*)base + PageOffset));
    > > }

    >
    > > }

    >
    > > void mmio_unmap(void* VirtAddr, unsigned long Size)
    > > {
    > > off_t PageOffset, PageAddress;

    >
    > > PageOffset = (off_t)VirtAddr % getpagesize();;
    > > PageAddress = (off_t)VirtAddr - PageOffset;
    > > Size += PageOffset;

    >
    > > munmap((void*)PageAddress, Size);

    >
    > > }

    >
    > > // To access your registers, you would do something like this:
    > > main()
    > > {
    > > int i;
    > > volatile unsigned short *leds;

    >
    > > leds = (unsigned short*)mmio_map(0x42000000, sizeof(*leds));

    >
    > > if (!leds)
    > > {
    > > perror("mmap");
    > > exit(1);
    > > }

    >
    > > for (i=0; i < 5; i++)
    > > {
    > > *leds = 0xa5ff; /* Alternate leds on from 0 */
    > > sleep(1);
    > > *leds = 0x5aff; /* Alternate leds on from 1 */
    > > }

    >
    > > mmio_unmap((void*)leds, sizeof(*leds));

    >
    > > }

    >
    > > Which works to an extent but I have two issues I don't understand.
    > > Firstly I get an "Illegal instruction" message with each run. I put in
    > > some comments and the message comes at the end of execution (no
    > > particular instruction). Secondly the "leds" get set to each
    > > configuration only once rather than switching back and forth as I
    > > would expect from the loop. I tried putting in an msync (MS_SYNC flag)
    > > after each setting of "leds" but it made no difference. Why doesn't
    > > the memory map update with each change?

    >
    > > BTW thanks for the help,

    >
    > 1. You should munmap the exact memory space (Virtual address and
    > size) that you Mmaped. So I would guess that the illigal instruction
    > happens when you try to munmap it.
    > 2. Note that in your loop, you set the leds to 0x5aff and immidiately
    > set it to 0xa5ff on the next loop cycle. What this would mean is you
    > would not see one of the LED states when the loop is run (too quick
    > for your eye). Put another sleep(1) after "*leds = 0x5aff; /*
    > Alternate leds on from 1 */" line. Note that depending on how the
    > LEDs are wired and how the registers are setup the actual LED state
    > could be ON for a 0 and OFF for a 1.


    Thanks so much! This has been a huge help.

  12. Re: Writing to a device at a known physical address

    On Dec 13, 8:22 pm, Juergen Beisert wrote:
    > Hi Janaka,
    >
    >
    >
    > Janaka wrote:
    > > On Dec 12, 6:51 pm, Juergen Beisert wrote:
    > >> Janaka wrote:
    > >> > //Turn some GPIO Pins on
    > >> > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > >> > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > >> > //Get some values of GPIO lines
    > >> > uiGet = *(volatile unsigned int *)(regmap_addr +
    > >> > GPIO2_DATA_REG_OFFSET);

    >
    > >> As you are talking to hardware, at this point you should consider there
    > >> are architectures in the wild that do some kind of access reordering in
    > >> hardware.
    > >> For example PowerPC: In your example it will do the read access prior the
    > >> (buffered) write access (even if the compiler generates code in the other
    > >> order!). Your program would fail at least on this architecture.

    >
    > >> So: Do not use volatile types in this way. Use the read?()/write?()
    > >> inline functions from the architecture specific part of the linux source
    > >> instead (refer include/asm-/io.h). Its more save, more
    > >> portable and the source is easier to read.

    >
    > >> JB

    >
    > > Thanks Juergen. Anything else that I should lookout for when
    > > accessing mmaped space ? I have come up with one HW design flaw where
    > > some of the registers on the chip are middle-endian while others are
    > > little-endian.
    > > BTW I am using MPC8349 in little-endian mode with PowerPC arch type
    > > (not PPC). And it works as expected so far. Does this re-ordering
    > > happen with optimized compiler options or is this HW architecture
    > > cache lining caveat ?

    >
    > That's the problem. This reordering happens in hardware. So the compiler has
    > *no* effect on it. But I'm not sure if it happens on all PPC cores. Its
    > easy to understand: A read access would stop program execution, while a
    > write access can be done in background later while program execution
    > continues. This increases the execution speed when you are working with
    > regular RAM (with or without cache). But could crash, when there is no RAM
    > and hardware registers instead.
    > As the CPU works with the same mnemonics, it cannot differentiate if it
    > talks to RAM or hardware. Same is done on x86: But there are chipset
    > related register bits to set, that forbits reordering in *some* address
    > areas. Don't know if something like this also exists on PPC/PowerPC.
    >
    > You need the "sync" command between all hardware access commands.
    > The "volatile" keeps command order in assembler in sync with your C code
    > and the "sync" command keeps assembler command order and execution order in
    > sync. Very easy ;-)
    >
    > JB


    Thanks and cheers.

  13. Re: Writing to a device at a known physical address

    On Dec 13, 4:22 am, Juergen Beisert wrote:
    > Hi Janaka,
    >
    >
    >
    > Janaka wrote:
    > > On Dec 12, 6:51 pm, Juergen Beisert wrote:
    > >> Janaka wrote:
    > >> > //Turn some GPIO Pins on
    > >> > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > >> > GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > >> > //Get some values of GPIO lines
    > >> > uiGet = *(volatile unsigned int *)(regmap_addr +
    > >> > GPIO2_DATA_REG_OFFSET);

    >
    > >> As you are talking to hardware, at this point you should consider there
    > >> are architectures in the wild that do some kind of access reordering in
    > >> hardware.
    > >> For example PowerPC: In your example it will do the read access prior the
    > >> (buffered) write access (even if the compiler generates code in the other
    > >> order!). Your program would fail at least on this architecture.

    >
    > >> So: Do not use volatile types in this way. Use the read?()/write?()
    > >> inline functions from the architecture specific part of the linux source
    > >> instead (refer include/asm-/io.h). Its more save, more
    > >> portable and the source is easier to read.

    >
    > >> JB

    >
    > > Thanks Juergen. Anything else that I should lookout for when
    > > accessing mmaped space ? I have come up with one HW design flaw where
    > > some of the registers on the chip are middle-endian while others are
    > > little-endian.
    > > BTW I am using MPC8349 in little-endian mode with PowerPC arch type
    > > (not PPC). And it works as expected so far. Does this re-ordering
    > > happen with optimized compiler options or is this HW architecture
    > > cache lining caveat ?

    >
    > That's the problem. This reordering happens in hardware. So the compiler has
    > *no* effect on it. But I'm not sure if it happens on all PPC cores. Its
    > easy to understand: A read access would stop program execution, while a
    > write access can be done in background later while program execution
    > continues. This increases the execution speed when you are working with
    > regular RAM (with or without cache). But could crash, when there is no RAM
    > and hardware registers instead.
    > As the CPU works with the same mnemonics, it cannot differentiate if it
    > talks to RAM or hardware. Same is done on x86: But there are chipset
    > related register bits to set, that forbits reordering in *some* address
    > areas. Don't know if something like this also exists on PPC/PowerPC.
    >
    > You need the "sync" command between all hardware access commands.
    > The "volatile" keeps command order in assembler in sync with your C code
    > and the "sync" command keeps assembler command order and execution order in
    > sync. Very easy ;-)
    >
    > JB


    This is a follow on question to the above. The program described above
    is a user space program.
    Of course because I'm working directly with hardware this should be
    done as a driver. My question
    is how do I access /dev/mem from user space? Every example driver I've
    seen requires the user
    space program to open the device in order to call the driver functions
    on that device. But a normal
    user cannot open /dev/mem. Do I need a device pointer (sort of like /
    dev/modem and /dev/Stty)
    that has general user access?

    I'm really looking for the best way to approach this. I've never
    written anything but a trivial driver and
    I want this to be as efficient as possible. (Yes, I've got the Rubini
    book on order....).

    Thanks for any input you can give me..

  14. Re: Writing to a device at a known physical address

    James,

    James Kimble wrote:
    > Of course because I'm working directly with hardware this should be
    > done as a driver.


    This is not always true. Hardware abstraction is always a good idea. But if
    you only need to set some bits at startup or when the system is already up
    and running it could make sense to use this userspace way.

    > My question is how do I access /dev/mem from user space?


    ?
    man open mmap close ?

    > Every example driver I've seen requires the user space program to open the
    > device in order to call the driver functions on that device.
    > But a normal user cannot open /dev/mem. Do I need a device pointer (sort
    > of like / dev/modem and /dev/Stty) that has general user access?


    Yes, you need to be root to open /dev/mem. As you have access to almost
    everything in your system this device is restricted to root only. Note: You
    can destroy everything in your system, when you are using /dev/mem in a
    wrong way!

    > I'm really looking for the best way to approach this. I've never
    > written anything but a trivial driver and I want this to be as efficient
    > as possible. (Yes, I've got the Rubini book on order....).


    Take a look into the UIO (=user I/O) framework, coming with the fresh 2.6.23
    kernel. With the help of this framework you can write your own trivial
    (=very small) kernel driver that restrict access to a specific piece of
    hardware (it works like /dev/mem but for the specific piece of hardware
    only).
    The advantage is, you can continue to handle this piece of hardware from
    userland, but any misuse is restricted to this piece of hardware instead of
    the whole system. And with the help of "udev" you can create the
    permissions for this device as you need it in your application.

    Refer Documentation/DocBook/uio-howto.tmpl for the UI framework.

    JB


  15. Re: Writing to a device at a known physical address

    On Dec 15, 2:30*am, James Kimble wrote:
    > On Dec 13, 4:22 am, Juergen Beisert wrote:
    >
    >
    >
    >
    >
    > > Hi Janaka,

    >
    > > Janaka wrote:
    > > > On Dec 12, 6:51 pm, Juergen Beisert wrote:
    > > >> Janaka wrote:
    > > >> > //Turn some GPIO Pins on
    > > >> > *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
    > > >> > * * * * * * *GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
    > > >> > //Get some values of GPIO lines
    > > >> > uiGet = *(volatile unsigned int *)(regmap_addr +
    > > >> > * * * * * * *GPIO2_DATA_REG_OFFSET);

    >
    > > >> As you are talking to hardware, at this point you should consider there
    > > >> are architectures in the wild that do some kind of access reordering in
    > > >> hardware.
    > > >> For example PowerPC: In your example it will do the read access priorthe
    > > >> (buffered) write access (even if the compiler generates code in the other
    > > >> order!). Your program would fail at least on this architecture.

    >
    > > >> So: Do not use volatile types in this way. Use the read?()/write?()
    > > >> inline functions from the architecture specific part of the linux source
    > > >> instead (refer include/asm-/io.h). Its more save, more
    > > >> portable and the source is easier to read.

    >
    > > >> JB

    >
    > > > Thanks Juergen. *Anything else that I should lookout for when
    > > > accessing mmaped space ? *I have come up with one HW design flaw where
    > > > some of the registers on the chip are middle-endian while others are
    > > > little-endian.
    > > > BTW I am using MPC8349 in little-endian mode with PowerPC arch type
    > > > (not PPC). *And it works as expected so far. *Does this re-ordering
    > > > happen with optimized compiler options or is this HW architecture
    > > > cache lining caveat ?

    >
    > > That's the problem. This reordering happens in hardware. So the compilerhas
    > > *no* effect on it. But I'm not sure if it happens on all PPC cores. Its
    > > easy to understand: A read access would stop program execution, while a
    > > write access can be done in background later while program execution
    > > continues. This increases the execution speed when you are working with
    > > regular RAM (with or without cache). But could crash, when there is no RAM
    > > and hardware registers instead.
    > > As the CPU works with the same mnemonics, it cannot differentiate if it
    > > talks to RAM or hardware. Same is done on x86: But there are chipset
    > > related register bits to set, that forbits reordering in *some* address
    > > areas. Don't know if something like this also exists on PPC/PowerPC.

    >
    > > You need the "sync" command between all hardware access commands.
    > > The "volatile" keeps command order in assembler in sync with your C code
    > > and the "sync" command keeps assembler command order and execution orderin
    > > sync. Very easy ;-)

    >
    > > JB

    >
    > This is a follow on question to the above. The program described above
    > is a user space program.
    > Of course because I'm working directly with hardware this should be
    > done as a driver. My question
    > is how do I access /dev/mem from user space? Every example driver I've
    > seen requires the user
    > space program to open the device in order to call the driver functions
    > on that device. But a normal
    > user cannot open /dev/mem. Do I need a device pointer (sort of like /
    > dev/modem and /dev/Stty)
    > that has general user access?
    >
    > I'm really looking for the best way to approach this. I've never
    > written anything but a trivial driver and
    > I want this to be as efficient as possible. (Yes, I've got the Rubini
    > book on order....).
    >
    > Thanks for any input you can give me..- Hide quoted text -
    >
    > - Show quoted text -


    User space program look easier for programming, but do it in a device
    driver seems more reasonable. Even you don't have to use mmap in your
    user space progrem.

    Write a simple device driver to access hardware directly. "ioremap"
    can be used to map physical address to kernel virtual address space,
    then you use readb/w/l and writeb/w/l to read/write such address. In
    user space, you write simple program to cooperate with your device
    driver, ioctl system call is enough for most of scenario.

    Thanks,
    Marco Wang

+ Reply to Thread