This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to program the UART in OMAP4460

I'm running Android 4.0.4 (ICS) on Google/Samsung Galaxy Nexus S phone (rooted). I want to save the state of the software and hardware, disable the MMU, program the UART for serial communication with external Linux PC, re-enable the MMU, and restore the software and hardware context and continue to run Android as usual. I'm stuck at the point where MMU has to be disabled, UART programmed, serial communication initiated. I programmed the MMU to disable it.

 

How do I setup the MMU and UART for non-interrupt-driven serial transmit/receive.

Thanks.

--shahed

/*!************************************************************************

*  \fn void setup_uart(void)

*  \param

*  \brief

**************************************************************************/

void setup_uart(void)

{

uint32_t baud_divisor = 1843200/16/115200;

OMAP_UART_IER = 0x0;

OMAP_UART_LCR = 0xBF;

OMAP_UART_FCR = 0x10;

OMAP_UART_MCR &= 0x7F;

OMAP_UART_LCR = 0x80 | 0x03;

OMAP_UART_RHR = baud_divisor & 0xff;

OMAP_UART_IER = (baud_divisor >> 8) & 0xff;

OMAP_UART_LCR = 0x3;

OMAP_UART_MCR = 0x1 | 0x2;

OMAP_UART_FCR = 0x1 |0x2 | 0x4;

}

 

/*!************************************************************************

*  \fn int omap_serial_putc(char inC )

*  \param inC

*  \brief

**************************************************************************/

int omap_serial_putc(char inC)

{

while ((OMAP_UART_LSR & OMAP_UART_LSR_THRE) == 0) {

/*waiting */

}

OMAP_UART_THR = inC;

return 0;

}

/*!************************************************************************

*  \fn int omap_serial_puts(char *buf, int size)

*  \param buf,size

*  \brief

**************************************************************************/

int omap_serial_puts(char *buf, int size)

{

int idx = 0;

for (idx = 0; idx < size; idx++) {

while ((OMAP_UART_LSR & OMAP_UART_LSR_THRE) == 0) {

/*waiting */

}

OMAP_UART_THR = buf[idx];

}

return 0;

}

/*!************************************************************************

*  \fn int omap_serial_gets( char *buf, int size )

*  \param buf,size

*  \brief

**************************************************************************/

int omap_serial_gets(char *buf, int size)

{

int i = 0;

if (NULL == buf) {

return -1;

}

for (i = 0; i < size; i++) {

while ((OMAP_UART_LSR & OMAP_UART_LSR_DR) == 0) {

/* waiting for port to be ready */

}

buf[i] = OMAP_UART_RHR;

}

return 0;

}

/*!************************************************************************

*  \fn int omap_serial_getc( void )

*  \brief

**************************************************************************/

int omap_serial_getc(void)

{

while ((OMAP_UART_LSR & OMAP_UART_LSR_DR) == 0) {

/* waiting for port to be ready */

}

return (OMAP_UART_RHR);

}

 

  • Hi Shahed,

    I want too to use the serial port of my board with omap4460.

    how can i configure the mux pin of UART1 to acts as UART ?

    Best Regards,

  • Shahed,

    If you have disabled the MMU, you can directly use the physical address of the UART controller. Are you ensuring that your code is getting executed after MMU init?

  • Hi Renjith,

    After disabling the MMU and before accessing the UART registers, I have instrumented the code to explicitly return known values back to the driving application. I do see the correct values being returned from code that is executed after the MMU is disabled. This tells me that my code is being executed correctly after MMU is disabled.

    Yes, I am using physical addresses of UART registers as specified in TI's TRM. But to no avail. As soon as I hit the assembly instruction that reads a UART register, the software hangs. If I comment out that instruction, then the code returns with the instrumented test value.

    The only odd-ball thing that I'm doing is I'm starting with the phone running normally (Android ICS 4.0.4 on Google Samsung Galaxy Nexus S), then I go to my kernel module (via an app module) that disables the caches and the MMU and tries to access the UART and then re-enables the MMU and cahches and returns to Android app module.

    Please suggest / provide simple test code for this scenario. Or, point out any errors in my smplified code provided by me earlier in the thread. BTW, I'm using 48 MHZ clock rate in baud rate divisor calculation. There was an editing error in the example code.

    Thanks.

    --Shahed

  • Shahed,

    Just now I watched a detective movie. I'm getting the feel of a detective:) Let me try to figure out who the culprit is 

    1. What if your MMU is not turned off properly?

    2. Have you invalidated the i-cache before turning off MMU?

    3. Have you flushed/invalidated the d-cache? You should write a loop to wait for the cache to get flushed before disabling it.

    4. As a final step, you can ioremap and create a virtual pointer to your UART base address and try to access that instead of the physical address. That will validate whether MMU is really turned off or not.

  • Hi Renjith,

    Thank you for your suggestions. I'm looking into 1, 2, and 3. I'm pretty sure, I have done these. I'll check the code in detail. In the mean time, regarding #4, can you please tell me more about it: how do I exactly ioremap and create the virtual pointer? I did try to access the registers directly by using their logical address in addition to physical address. But that did not work. I would like to try your suggestion#4. Please tell me a bit more about it.

    Thanks for your help.

    --Shahed

  • Hi Shahed,

    Ioremap will a VA for a PA and a size. VA = ioremap(PA, size);

    http://www.makelinux.net/ldd3/chp-9-sect-4

  • Hi Renjith,

    ioremap is defined in <asm/io.h> header file. I searched several io.h files on my machine that has Android development software from AOSP. The target phone is Google/Samsung Galaxy Nexus -- uses OMAP4460 SOC. I tried io.h appropriate for this target processor. I get errors during linking: undefined reference to ioremap.

    I checked the io.h files appropriate to arm arch (/root/kernel/omap/arch/include/asm/io.h and arch/arm/mach-omap2/asm/io.h) available in my machine.

    Are there other header and implementation files to be used for ioremap() and read/write8/16/32() functions/macros?

    Thank you for your help.

    --Shahed

  • Shahed,

    grep for ioremap in arch/arm/mach-omap2. You'll be able to see a sample implementation

  • Hi Renjith, I have looked at the io.h in arch/arm/mach-omap2. All I see there is omap_sram_init(). I have also looked at other "io.h" files. The closest to my target is omap/arch/arm/include/asm/io.h. However, it does not have ioremap but has an extern to __arm_ioremap() and takes 3 arguments:unsigned long, size_t, and unsigned int. I cant seem to find an io.h with ioremap definition for my target. Thanks. --Shahed

  • Shahed,

    Don't worry about the header file part. Can you grep in the whole arch/arm directory? There will be lot of references to ioremap. Just try it out once, without any hesitation.

  • The ioremap definition is available at arch/arm/include/asm/io.h

    So, you can get your purpose done by including 

    #include <linux/io.h>

    which internally should invoke the asm/io.h file.

    and the ioremap function is a macro which is defined by "__arm_ioremap()".

    -Umakanta

  • Hi Umakanta, Renjith, Gina,

    I tried to include the files suggested by you. The file compiles but does not link. I get "undefined reference to ioremap".

    Is there any reference to code that shows how to write to and read from the micro-USB port on Google Samsung Galaxy Nexus S running Android ICS 4.0.4?

    Thanks. --Shahed

  • Shahed,

    Which is your kernel version?

  • The Kernel used by Android ICS version 4.04.

    Thanks.

     

  • I  don't track Android versions. Let me know your kernel version which is printed during boot.

  • Shahed,

    You've to do just #include <linux/io.h> .

    This will in turn call asm/io.h and where ioremap macro is defined.

  • I am trying to read UART register after the entire phone software is booted in and running.

    The mmu, caches, interrupts, other hardware has been initialized and running.

    1. Now at this point I would like to read UART regiter. I am unable to do this.

    2. Later I would like to disable mmu, caches, interrupts, etc., and read and write UART register. I am unable to this.

    Please let me know about this problem.

    Thanks for your help

    --Shahed

  • Hi,

    May be the undefined reference error for ioremap(), removed by doing a clean build of your kernel with #include <linux/io.h>.

    Also, before doing the ioremap to access the UART registers, do a request_mem_region().

    This checks whether some other peripheral has accessed this memory region or not.

    If you get success, then you can do ioremap for the memory region of UART registers.

    -Umakanta Patro