Skip to contentSkip to conversation

External serial 8250/16550

DISCUSSION Paulo Fragoso 3 participants 8 messages Apr 24, 2011 – May 24, 2011

lore
Share & tools
lore
#0 lore raw

Hi,

I was called for help to add a external serial using a board based on at91sam9g45, was useded chip TL16c2550 conected on EBI1_D[0-7] for data and EBI_A[0-2] for address register.

There are two UART in this chip which will be select by EBI1_NCS1 and PC13/NCS2

I'm trying to register this uart in this way:

static struct plat_serial8250_port tms_serial_data[] = {
	PORT(0x70000000, AT91_PIN_PC0),
	PORT(0x80000000, AT91_PIN_PC1),
	{ },
};

static struct platform_device tms_serial_device = {

         .name                   = "serial8250",
         .id                     = -1,
         .dev                    =
                 {
                         .platform_data  = &tms_serial_data,
                 },
};

static void tms_add_device_serial(void)

{
         at91_sys_write(AT91_SMC_CSR(1),
                                   AT91_SMC_ACSS_STD
                                 | AT91_SMC_DBW_8
                                 | AT91_SMC_BAT
                                 | AT91_SMC_WSEN
                                 | AT91_SMC_NWS_(32)     /* wait states */
                                 | AT91_SMC_RWSETUP_(6)  /* setup time */
                                 | AT91_SMC_RWHOLD_(4)   /* hold time */

         );
         at91_sys_write(AT91_SMC_CSR(2),
                                   AT91_SMC_ACSS_STD
                                 | AT91_SMC_DBW_8
                                 | AT91_SMC_BAT
                                 | AT91_SMC_WSEN
                                 | AT91_SMC_NWS_(32)     /* wait states */
                                 | AT91_SMC_RWSETUP_(6)  /* setup time */
                                 | AT91_SMC_RWHOLD_(4)   /* hold time */
         );

         platform_device_register(&tms_serial_device);
}

//#endif

static void __init ek_map_io(void)

{
	/* Initialize processor: 12.000 MHz crystal */
	at91sam9g45_initialize(12000000);

	/* DGBU on ttyS0. (Rx & Tx only) */
	at91_register_uart(0, 0, 0);

	/* USART0 on ttyS2. (Rx, Tx, RTS, CTS) - Used by smartcard */
	at91_register_uart(AT91SAM9G45_ID_US0, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);

	/* USART1 on ttyS1. (Rx, Tx, RTS, CTS) */
	at91_register_uart(AT91SAM9G45_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);

	/* set serial console to ttyS0 (ie, DBGU) */
	at91_set_serial_console(0);

	/* antes: at91_init_serial(&tms_uart_config); */
         /* how to map IO */
}

static void __init ek_board_init(void)

{
	/* Serial */
	at91_add_device_serial();
...
	/* External Serial */
	tms_add_device_serial();
}

But doesn't work, how to map correctly external serial port?

Is there any sample code for external uart using linux-2.6.36 and arm AT91SAM9?

Thanks.
Paulo.

#1 lore raw

hi Paulo,

Quoted 5 lines

I was called for help to add a external serial using a board based on at91sam9g45,

? ? ? ?at91_sys_write(AT91_SMC_CSR(1),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?AT91_SMC_ACSS_STD

Quoted 8 lines
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_DBW_8
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_BAT
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_WSEN
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_NWS_(32) ? ? /* wait states */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_RWSETUP_(6) ?/* setup time */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| AT91_SMC_RWHOLD_(4) ? /* hold time */

? ? ? ?);

Those AT91_SMC registers and bits only exist on the AT91RM9200, whereas you're using a SAM9-based processor.

You should be configuring the memory controller by:
#include <mach/at91sam9_smc.h>
#include "sam9_smc.h"

and declaring a "struct sam9_smc_config" with all the setting & timings, and then calling:
sam9_smc_configure(CHIP_SELECT_NUMBER, &your_smc_config_struct);

Quoted 1 line

But doesn't work, how to map correctly external serial port?

If you specify UPF_IOREMAP in the "struct plat_serial8250_port" flags, the serial-driver will automatically map the IO region for you.

Quoted 2 lines

Is there any sample code for external uart using linux-2.6.36 and arm AT91SAM9?

Not for a SAM9-based board. But for an AT91RM9200 example, look at board-tms.c in the AT91 patches on http://maxim.org.za/at91_26.html . SAM9 should be the same, except for the SMC memory-controller configuration (as described above).

Regards,
Andrew Victor

#2 lore raw

Em 26/04/2011 13:39, Andrew Victor escreveu:

Quoted 9 lines

Those AT91_SMC registers and bits only exist on the AT91RM9200, whereas you're using a SAM9-based processor.

You should be configuring the memory controller by:

   #include<mach/at91sam9_smc.h>
   #include "sam9_smc.h"

and declaring a "struct sam9_smc_config" with all the setting&

I changed the code following TL16C2550 datasheet and now I am using correct registers for AT91sam:

static struct sam9_smc_config tms_uart_smc_config = {
	.ncs_read_setup		= 0,
	.nrd_setup		= 2,
	.ncs_write_setup	= 0,
	.nwe_setup		= 2,

	.ncs_read_pulse		= 5,
	.nrd_pulse		= 4,
	.ncs_write_pulse	= 4,
	.nwe_pulse		= 3,

	.read_cycle		= 10,
	.write_cycle		= 9,

	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | 
AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8 | AT91_SMC_BAT_WRITE,
	.tdf_cycles		= 3,
};
Quoted 2 lines

timings, and then calling:

    sam9_smc_configure(CHIP_SELECT_NUMBER,&your_smc_config_struct);

#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP| UPF_SHARE_IRQ)
#define SERIAL_CLK (1843200)

#define PORT(_base, _irq)				\
	{						\
		.mapbase	= _base,		\
		.irq		= _irq,			\
		.uartclk	= SERIAL_CLK,		\
		.iotype		= UPIO_MEM,		\
		.regshift	= 0,			\
		.flags		= SERIAL_FLAGS,		\
	}
static struct plat_serial8250_port tms_uart_data[] = {
	PORT(AT91_CHIPSELECT_1, AT91_PIN_PC0),
	PORT(AT91_CHIPSELECT_2, AT91_PIN_PC1),
	{ },
};
static struct platform_device tms_uart_device = {
	.name			= "serial8250",
	.id			= PLAT8250_DEV_PLATFORM,
	.dev			=
		{
			.platform_data	= &tms_uart_data,
		},
};
Quoted 3 lines

If you specify UPF_IOREMAP in the "struct plat_serial8250_port" flags, the serial-driver will automatically map the IO region for you.

and I am trying init in this way:

static void __init ek_board_init(void)

{
	/* Serial */
	at91_add_device_serial();
	/* USB HS Host */
	at91_add_device_usbh_ohci(&ek_usbh_hs_data);
	at91_add_device_usbh_ehci(&ek_usbh_hs_data);
	/* USB HS Device */
	at91_add_device_usba(&ek_usba_udc_data);

...

	/* External serial */
	tms_add_device_uart();
}
Quoted 5 lines

Not for a SAM9-based board. But for an AT91RM9200 example, look at board-tms.c in the AT91 patches on http://maxim.org.za/at91_26.html . SAM9 should be the same, except for the SMC memory-controller configuration (as described above).

I'm getting kernel opps yet! What is wrong in my code?

Entire code is here:
http://users.nlink.com.br/~paulo/TMS/20110504/board-sweda_tms2.c

Thanks,
Paulo.

Quoted 4 lines

Regards,
Andrew Victor

#3 lore raw
Quoted 26 lines · Paulo Fragoso

Em 26/04/2011 13:39, Andrew Victor escreveu:

Quoted 9 lines

Those AT91_SMC registers and bits only exist on the AT91RM9200, whereas you're using a SAM9-based processor.

You should be configuring the memory controller by:
#include<mach/at91sam9_smc.h>
#include "sam9_smc.h"

and declaring a "struct sam9_smc_config" with all the setting&

I changed the code following TL16C2550 datasheet and now I am using correct registers for AT91sam:

static struct sam9_smc_config tms_uart_smc_config = { .ncs_read_setup = 0,
.nrd_setup = 2,
.ncs_write_setup = 0,
.nwe_setup = 2,

.ncs_read_pulse = 5,
.nrd_pulse = 4,
.ncs_write_pulse = 4,
.nwe_pulse = 3,

Quoted 8 lines

.read_cycle = 10,
.write_cycle = 9,

.mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8 | AT91_SMC_BAT_WRITE, .tdf_cycles = 3,
};

I found an error on sam9_smc_configure call, now first (or second) serial was detected:

Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled serial8250.0: ttyS0 at MMIO 0x30000000 (irq = 97) is a 16550A

Whole code is on:

http://users.nlink.com.br/~paulo/TMS/20110509/board-sweda_tms2.c

Many Thanks,
Paulo.

#4 lore raw
Quoted 29 lines · Paulo Fragoso
Quoted 26 lines · Paulo Fragoso

Em 26/04/2011 13:39, Andrew Victor escreveu:

Quoted 9 lines

Those AT91_SMC registers and bits only exist on the AT91RM9200, whereas you're using a SAM9-based processor.

You should be configuring the memory controller by:
#include<mach/at91sam9_smc.h>
#include "sam9_smc.h"

and declaring a "struct sam9_smc_config" with all the setting&

I changed the code following TL16C2550 datasheet and now I am using correct registers for AT91sam:

static struct sam9_smc_config tms_uart_smc_config = { .ncs_read_setup = 0,
.nrd_setup = 2,
.ncs_write_setup = 0,
.nwe_setup = 2,

.ncs_read_pulse = 5,
.nrd_pulse = 4,
.ncs_write_pulse = 4,
.nwe_pulse = 3,

Quoted 8 lines
Quoted 8 lines

.read_cycle = 10,
.write_cycle = 9,

.mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8 | AT91_SMC_BAT_WRITE, .tdf_cycles = 3,
};

I have one doubt about new-style UART initialization, how can I initialize a board using AT91sam9 with two internal USART and two external 8250 UART at same time?

For example:

	/* DGBU on ttyS0. (Rx & Tx only) */
	at91_register_uart(0, 0, 0);

	/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
	at91_register_uart(AT91SAM9G45_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);

	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
	at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);

If I wish to put two more 8250 external serial in sequence (ttyS3 and ttyS4) which ID will be used at at91_register_uart function?

Looking at91_register_uart function all structs pdev are defined internaly, how I will define serila8250 platform_device and pass at at91_register_uart function?

Paulo.

#5 lore raw

Em 11/05/2011 23:23, Paulo Fragoso escreveu:

Quoted 16 lines · Paulo Fragoso

I have one doubt about new-style UART initialization, how can I initialize a board using AT91sam9 with two internal USART and two external 8250 UART at same time?

For example:

/* DGBU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);

/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ at91_register_uart(AT91SAM9G45_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);

/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);

Quoted 6 lines

If I wish to put two more 8250 external serial in sequence (ttyS3 and ttyS4) which ID will be used at at91_register_uart function?

Looking at91_register_uart function all structs pdev are defined internaly, how I will define serila8250 platform_device and pass at at91_register_uart function?

I discovered NCS1 is always on level 0 (selected) and NCS2 is always on level 1, those lines never change its state after boot, and they were configured correctly:

     sam9_smc_configure(1, &tms_uart_smc_config);
     sam9_smc_configure(2, &tms_uart_smc_config);

Entire file is here:
http://users.nlink.com.br/~paulo/TMS/20110519/board-sweda_tms2.c

This explain constant output on COMA from TL16C2550 and COMB is detected at boot time but doesn't work.

I will research what can be happening but what can be wrong with NCS1 and NCS2?

Thanks,
Paulo.

#6 lore raw
Quoted 6 lines · Paulo Fragoso

This explain constant output on COMA from TL16C2550 and COMB is detected at boot time but doesn't work.

I will research what can be happening but what can be wrong with NCS1 and NCS2?

All is working at boot time and NCS1 was correctly programed in bootstrap.

But no data out at serial line I'm testing enabling getty in inittab.

NCS1, NCS2, IOW and IOR are working how expected by the SMC config:

static struct sam9_smc_config tms_uart_smc_config = {

     .ncs_read_setup   = 0,
     .nrd_setup        = 2,
     .ncs_write_setup  = 0,
     .nwe_setup        = 2,
     .ncs_read_pulse   = 5,
     .nrd_pulse        = 4,
     .ncs_write_pulse  = 4,
     .nwe_pulse        = 3,

.read_cycle = 10,
.write_cycle = 9,

.mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8 | AT91_SMC_BAT_WRITE,
.tdf_cycles = 3,
};

Why isn't there any data on TX for COMA or COMB?

Paulo.

#7 lore raw
Quoted 28 lines · Paulo Fragoso
Quoted 6 lines · Paulo Fragoso

This explain constant output on COMA from TL16C2550 and COMB is detected at boot time but doesn't work.

I will research what can be happening but what can be wrong with NCS1 and NCS2?

All is working at boot time and NCS1 was correctly programed in bootstrap.

But no data out at serial line I'm testing enabling getty in inittab.

NCS1, NCS2, IOW and IOR are working how expected by the SMC config:

static struct sam9_smc_config tms_uart_smc_config = { .ncs_read_setup = 0,
.nrd_setup = 2,
.ncs_write_setup = 0,
.nwe_setup = 2,

.ncs_read_pulse = 5,
.nrd_pulse = 4,
.ncs_write_pulse = 4,
.nwe_pulse = 3,

.read_cycle = 10,
.write_cycle = 9,

Quoted 6 lines

.mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8 | AT91_SMC_BAT_WRITE, .tdf_cycles = 3,
};

Why isn't there any data on TX for COMA or COMB?

Hi Paulo,

I will have soon to do the same job on a SAM9G20 (but with a Quad UART). Did you try to access the registers of the UART? (You can do that from userspace:
ftp://ftp.embeddedarm.com/ts-arm-sbc/ts-7260-linux/sources/peekpoke.tar.gz). I think The UART has a scratch register, you could test if you can write and read back the data. Do you have any error messages in your logs? Have you try to use the stty program on your serial port, eg: stty -F /dev/ttySXYZ raw -clocal.
Perhaps your problem is on the transceiver side, have you try to tie Tx and Rx together and then read write date to the serial port from your embedded system?

Chris

Quoted 8 lines

Paulo.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel