Below are the changes to the atmel_serial.c in the linux kernel 3.0.4
to allow reception of data at 6Mb/s rate in AT91SAM9260.
Changes include:
1. Switching of the synchro mode when 460800 speed is selected
2. Use of RX DMA buffer located in internal SRAM for "ttyS3" USART
(the name of the USART is hardcoded in sources!)
Changes in this driver should be supplemented with setting of the
bus matrix to prioritize access of PDC to SRAM.
To achieve that, I have added the following code in board initialization routine:
/* Modify the Bus Matrix settings */
at91_sys_write(AT91_MATRIX_SCFG0, 0x010a0010);
at91_sys_write(AT91_MATRIX_SCFG1, 0x010a0010);
at91_sys_write(AT91_MATRIX_PRAS0, 0x00200300);
at91_sys_write(AT91_MATRIX_PRAS1, 0x00200300);
I hope, that this information will be usefull for someone...
Wojciech Zabołotny <
wz...@ise.pw.edu.pl>
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh12655
# Made on 2011-10-26 17:26 CEST by <wzab@WZLap>.
# Source directory was `/tmp'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 7405 -rw-r--r-- atmel_serial_c_synchro_6mbs.patch
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= atmel_serial_c_synchro_6mbs.patch ==============
if test -n "${keep_file}" && test -f 'atmel_serial_c_synchro_6mbs.patch'
then
${echo} "x - SKIPPING atmel_serial_c_synchro_6mbs.patch (file already exists)"
else
${echo} "x - extracting atmel_serial_c_synchro_6mbs.patch (text)"
sed 's/^X//' << 'SHAR_EOF' > 'atmel_serial_c_synchro_6mbs.patch' &&
*** atmel_serial.c 2011-08-29 22:56:30.000000000 +0200
--- ../a/atmel_serial.c 2011-10-24 20:55:40.000000000 +0200
***************
*** 49,55 ****
X #include <mach/gpio.h>
X #endif
X
! #define PDC_BUFFER_SIZE 512
X /* Revisit: We should calculate this based on the actual port settings */
X #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */
X
--- 49,55 ----
X #include <mach/gpio.h>
X #endif
X
! #define PDC_BUFFER_SIZE 1024
X /* Revisit: We should calculate this based on the actual port settings */
X #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */
X
***************
*** 142,147 ****
--- 142,148 ----
X short use_dma_rx; /* enable PDC receiver */
X short pdc_rx_idx; /* current PDC RX buffer */
X struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */
+ short rx_buf_sram; /* Added by WZab to mark, that this port uses RX buffer in SRAM */
X
X short use_dma_tx; /* enable PDC transmitter */
X struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
***************
*** 789,797 ****
X head = min(head, pdc->dma_size);
X
X if (likely(head != tail)) {
X dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
X pdc->dma_size, DMA_FROM_DEVICE);
!
X /*
X * head will only wrap around when we recycle
X * the DMA buffer, and when that happens, we
--- 790,801 ----
X head = min(head, pdc->dma_size);
X
X if (likely(head != tail)) {
+ if(atmel_port->rx_buf_sram) {
+ //__dma_single_dev_to_cpu(pdc->buf,PDC_BUFFER_SIZE,DMA_FROM_DEVICE);
+ } else {
X dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
X pdc->dma_size, DMA_FROM_DEVICE);
! }
X /*
X * head will only wrap around when we recycle
X * the DMA buffer, and when that happens, we
***************
*** 802,810 ****
X
X tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
X
X dma_sync_single_for_device(port->dev, pdc->dma_addr,
X pdc->dma_size, DMA_FROM_DEVICE);
!
X port->icount.rx += count;
X pdc->ofs = head;
X }
--- 806,817 ----
X
X tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
X
+ if(atmel_port->rx_buf_sram) {
+ //__dma_single_cpu_to_dev(pdc->buf,PDC_BUFFER_SIZE,DMA_FROM_DEVICE);
+ } else {
X dma_sync_single_for_device(port->dev, pdc->dma_addr,
X pdc->dma_size, DMA_FROM_DEVICE);
! }
X port->icount.rx += count;
X pdc->ofs = head;
X }
***************
*** 888,894 ****
X struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
X struct tty_struct *tty = port->state->port.tty;
X int retval;
-
X /*
X * Ensure that no interrupts are enabled otherwise when
X * request_irq() is called we could get stuck trying to
--- 895,900 ----
***************
*** 910,917 ****
X * Initialize DMA (if necessary)
X */
X if (atmel_use_dma_rx(port)) {
X int i;
!
X for (i = 0; i < 2; i++) {
X struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
X
--- 916,926 ----
X * Initialize DMA (if necessary)
X */
X if (atmel_use_dma_rx(port)) {
+ if(strcmp(tty->name,"ttyS3")) {
X int i;
! printk("<1>Initializing: %s - not HS",tty->name);
! atmel_port-> rx_buf_sram = 0;
! //This is not our UART dedicated to high speed transmission
X for (i = 0; i < 2; i++) {
X struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
X
***************
*** 934,940 ****
X pdc->dma_size = PDC_BUFFER_SIZE;
X pdc->ofs = 0;
X }
!
X atmel_port->pdc_rx_idx = 0;
X
X UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
--- 943,981 ----
X pdc->dma_size = PDC_BUFFER_SIZE;
X pdc->ofs = 0;
X }
! } else {
! int i;
! dma_addr_t dma_buf=NULL;
! void * virt_buf=NULL;
! //This is the UART dedicated to
! printk("<1>Initializing: %s - HS",tty->name);
! // Changed for use of DMA in internal SRAM
! atmel_port-> rx_buf_sram = 1;
! if (request_mem_region(AT91SAM9260_SRAM0_BASE, 2*PDC_BUFFER_SIZE, "hsuart")) {
! dma_buf = AT91SAM9260_SRAM0_BASE;
! } else if (request_mem_region(AT91SAM9260_SRAM1_BASE, 2*PDC_BUFFER_SIZE, "hsuart")) {
! dma_buf = AT91SAM9260_SRAM1_BASE;
! } else {
! //We were not able to allocate the DMA buffer in SRAM
! free_irq(port->irq,port);
! return -ENOMEM;
! }
! //Buffer allocated, assign it
! virt_buf = ioremap(dma_buf,2*PDC_BUFFER_SIZE);
! if(!virt_buf) {
! release_mem_region(dma_buf,2*PDC_BUFFER_SIZE);
! free_irq(port->irq,port);
! return -ENOMEM;
! }
! for (i = 0; i < 2; i++) {
! struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
! pdc->dma_addr = dma_buf+i*PDC_BUFFER_SIZE;
! pdc->buf = virt_buf+i*PDC_BUFFER_SIZE;
! pdc->dma_size = PDC_BUFFER_SIZE;
! pdc->ofs = 0;
! }
! printk("<1>USART buffer: DMA_ADDR=%x, virt=%x, high_memory=%x\n",dma_buf,virt_buf,high_memory);
! }
X atmel_port->pdc_rx_idx = 0;
X
X UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
***************
*** 1011,1016 ****
--- 1052,1063 ----
X * Shut-down the DMA.
X */
X if (atmel_use_dma_rx(port)) {
+ //First check if this port uses the SRAM buffer
+ if(atmel_port->rx_buf_sram) {
+ iounmap(atmel_port->pdc_rx[0].buf);
+ release_mem_region(atmel_port->pdc_rx[0].dma_addr,2*PDC_BUFFER_SIZE);
+ atmel_port->rx_buf_sram = 0;
+ } else {
X int i;
X
X for (i = 0; i < 2; i++) {
***************
*** 1022,1027 ****
--- 1069,1075 ----
X DMA_FROM_DEVICE);
X kfree(pdc->buf);
X }
+ }
X }
X if (atmel_use_dma_tx(port)) {
X struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
***************
*** 1113,1128 ****
X /* Get current mode register */
X mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
X | ATMEL_US_NBSTOP | ATMEL_US_PAR
! | ATMEL_US_USMODE);
X
! baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
! quot = uart_get_divisor(port, baud);
X
! if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
X quot /= 8;
X mode |= ATMEL_US_USCLKS_MCK_DIV8;
! }
X
X /* byte size */
X switch (termios->c_cflag & CSIZE) {
X case CS5:
--- 1161,1185 ----
X /* Get current mode register */
X mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
X | ATMEL_US_NBSTOP | ATMEL_US_PAR
! | ATMEL_US_USMODE | ATMEL_US_SYNC);
X
! if (termios->c_ispeed != 460800) {
! printk("<1> USART - ASYNC mode i_speed=%d\n",termios->c_ispeed);
! baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
! quot = uart_get_divisor(port, baud);
X
! if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
X quot /= 8;
X mode |= ATMEL_US_USCLKS_MCK_DIV8;
! }
X
+ } else {
+ printk("<1> USART - SYNC mode i_speed=%d\n",termios->c_ispeed);
+ baud = 6000000;
+ quot = 100; /* This value doesn't matter anyway */
+ mode |= ATMEL_US_USCLKS_SCK | ATMEL_US_SYNC;
+ if(at91_set_A_periph(AT91_PIN_PA30, 1)) printk("<1> Can't set PA30 to SCK2\n");
+ }
X /* byte size */
X switch (termios->c_cflag & CSIZE) {
X case CS5:
SHAR_EOF
(set 20 11 10 26 17 25 22 'atmel_serial_c_synchro_6mbs.patch'
eval "${shar_touch}") && \
chmod 0644 'atmel_serial_c_synchro_6mbs.patch'
if test $? -ne 0
then ${echo} "restore of atmel_serial_c_synchro_6mbs.patch failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'atmel_serial_c_synchro_6mbs.patch': 'MD5 check failed'
) << \SHAR_EOF
f91066dbbb14c1e9ea565f67105829dc atmel_serial_c_synchro_6mbs.patch
SHAR_EOF
else
test `LC_ALL=C wc -c < 'atmel_serial_c_synchro_6mbs.patch'` -ne 7405 && \
${echo} "restoration warning: size of 'atmel_serial_c_synchro_6mbs.patch' is not 7405"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0