From 7a669866eea8b66b87b22015b793b5ea4ff950c1 Mon Sep 17 00:00:00 2001 From: Claas Ziemke Date: Wed, 22 Aug 2012 14:39:02 +0200 Subject: Added BeagleBoard BSP Coding done in course of GSoC2012. Commit edited to be brought up-to-date with mainline by Ben Gras . --- c/src/lib/libbsp/arm/beagle/misc/boot.c | 62 ++++ c/src/lib/libbsp/arm/beagle/misc/i2c.c | 450 +++++++++++++++++++++++ c/src/lib/libbsp/arm/beagle/misc/restart.c | 32 ++ c/src/lib/libbsp/arm/beagle/misc/system-clocks.c | 140 +++++++ c/src/lib/libbsp/arm/beagle/misc/timer.c | 46 +++ 5 files changed, 730 insertions(+) create mode 100644 c/src/lib/libbsp/arm/beagle/misc/boot.c create mode 100644 c/src/lib/libbsp/arm/beagle/misc/i2c.c create mode 100644 c/src/lib/libbsp/arm/beagle/misc/restart.c create mode 100644 c/src/lib/libbsp/arm/beagle/misc/system-clocks.c create mode 100644 c/src/lib/libbsp/arm/beagle/misc/timer.c (limited to 'c/src/lib/libbsp/arm/beagle/misc') diff --git a/c/src/lib/libbsp/arm/beagle/misc/boot.c b/c/src/lib/libbsp/arm/beagle/misc/boot.c new file mode 100644 index 0000000000..771df7007d --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/misc/boot.c @@ -0,0 +1,62 @@ +/** + * @file + * + * @ingroup beagle_boot + * + * @brief Boot support implementation. + */ + +/* + * Copyright (c) 2012 Claas Ziemke. All rights reserved. + * + * Claas Ziemke + * Kernerstrasse 11 + * 70182 Stuttgart + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include + +#include + +void beagle_setup_boot_block( + beagle_boot_block *boot_block, + uint8_t icr, + uint8_t page_count +) +{ + memset(boot_block, 0, sizeof(*boot_block)); + + ++page_count; + + boot_block->field.d0 = icr; + boot_block->field.d2 = icr; + boot_block->field.d4 = page_count; + boot_block->field.d6 = page_count; + boot_block->field.d8 = page_count; + boot_block->field.d10 = page_count; + + icr = (uint8_t) ~((unsigned) icr); + page_count = (uint8_t) ~((unsigned) page_count); + + boot_block->field.d1 = icr; + boot_block->field.d3 = icr; + boot_block->field.d5 = page_count; + boot_block->field.d7 = page_count; + boot_block->field.d9 = page_count; + boot_block->field.d11 = page_count; + + boot_block->field.d12 = 0xaa; +} + +void beagle_set_boot_block_bad( + beagle_boot_block *boot_block +) +{ + boot_block->field.d12 = 0; +} diff --git a/c/src/lib/libbsp/arm/beagle/misc/i2c.c b/c/src/lib/libbsp/arm/beagle/misc/i2c.c new file mode 100644 index 0000000000..322c501d3c --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/misc/i2c.c @@ -0,0 +1,450 @@ +/** + * @file + * + * @ingroup beagle_i2c + * + * @brief I2C support implementation. + */ + +/* + * Copyright (c) 2012 Claas Ziemke. All rights reserved. + * + * Claas Ziemke + * Kernerstrasse 11 + * 70182 Stuttgart + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include + +#include +#include + +static struct i2c *i2c_base = (struct i2c *)I2C_DEFAULT_BASE; + +static unsigned short wait_for_pin( void ) { + + unsigned short status; + int timeout = I2C_TIMEOUT; + + do { + udelay( 1000 ); + status = readw( &i2c_base->stat ); + } while( !( status & + ( I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | + I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | + I2C_STAT_AL ) ) && timeout-- ); + + if( timeout <= 0 ) { + printk( "timed out in wait_for_pin: I2C_STAT = %x\n", + readw( &i2c_base->stat ) ); + writew( 0xFFFF, &i2c_base->stat ); /* clear current interrupts...*/ + status = 0; + } + + return status; +} + +static void wait_for_bb( void ) { + + int timeout = I2C_TIMEOUT; + unsigned short status; + + writew( 0xFFFF, &i2c_base->stat ); /* clear current interrupts...*/ + while( ( status = readw( &i2c_base->stat ) & I2C_STAT_BB ) && timeout-- ) { + writew( status, &i2c_base->stat ); + udelay( 1000 ); + } + + if( timeout <= 0 ) { + printk( "timed out in wait_for_bb: I2C_STAT = %x\n", + readw( &i2c_base->stat ) ); + } + writew( 0xFFFF, &i2c_base->stat ); /* clear delayed stuff*/ +} + +static void flush_fifo( void ) { + + unsigned short status; + + /* note: if you try and read data when its not there or ready + * you get a bus error + */ + while( 1 ) { + status = readw( &i2c_base->stat ); + if( status == I2C_STAT_RRDY ) { + readw( &i2c_base->data ); + writew( I2C_STAT_RRDY, &i2c_base->stat ); + udelay( 1000 ); + } else { + break; + } + } +} + +void i2c_init( int speed, int slaveadd ) { + + int psc, fsscll, fssclh; + int hsscll = 0, hssclh = 0; + unsigned int scll, sclh; + int timeout = I2C_TIMEOUT; + + // Only handle standard, fast and high speeds + if( ( speed != OMAP_I2C_STANDARD ) && + ( speed != OMAP_I2C_FAST_MODE ) && + ( speed != OMAP_I2C_HIGH_SPEED ) ) { + printk( "Error : I2C unsupported speed %d\n", speed ); + return; + } + + psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK; + psc -= 1; + if( psc < I2C_PSC_MIN ) { + printk( "Error : I2C unsupported prescalar %d\n", psc ); + return; + } + + if( speed == OMAP_I2C_HIGH_SPEED ) { + // High speed + + // For first phase of HS mode + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * OMAP_I2C_FAST_MODE ); + + fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM; + fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM; + if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) || + ( fssclh > 255 ) ) ) { + printk( "Error : I2C initializing first phase clock\n" ); + return; + } + + // For second phase of HS mode + hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * speed ); + + hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM; + hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM; + if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) || + ( fssclh > 255 ) ) ) { + printk( "Error : I2C initializing second phase clock\n" ); + return; + } + + scll = ( unsigned int ) hsscll << 8 | ( unsigned int ) fsscll; + sclh = ( unsigned int ) hssclh << 8 | ( unsigned int ) fssclh; + + } else { + // Standard and fast speed + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * speed ); + + fsscll -= I2C_FASTSPEED_SCLL_TRIM; + fssclh -= I2C_FASTSPEED_SCLH_TRIM; + if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) || + ( fssclh > 255 ) ) ) { + printk( "Error : I2C initializing clock\n" ); + return; + } + + scll = ( unsigned int ) fsscll; + sclh = ( unsigned int ) fssclh; + } + + if( readw( &i2c_base->con ) & I2C_CON_EN ) { + writew( 0, &i2c_base->con ); + udelay( 50000 ); + } + + writew( 0x2, &i2c_base->sysc ); /* for ES2 after soft reset */ + udelay( 1000 ); + + writew( I2C_CON_EN, &i2c_base->con ); + while( !( readw( &i2c_base->syss ) & I2C_SYSS_RDONE ) && timeout-- ) { + if (timeout <= 0) { + printk( "ERROR: Timeout in soft-reset\n" ); + return; + } + udelay( 1000 ); + } + + writew( 0, &i2c_base->con ); + writew( psc, &i2c_base->psc ); + writew( scll, &i2c_base->scll ); + writew( sclh, &i2c_base->sclh ); + + /* own address */ + writew( slaveadd, &i2c_base->oa ); + writew( I2C_CON_EN, &i2c_base->con ); + + /* have to enable intrrupts or OMAP i2c module doesn't work */ + writew( I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE | + I2C_IE_AL_IE, &i2c_base->ie ); + udelay( 1000 ); + flush_fifo(); + writew( 0xFFFF, &i2c_base->stat ); + writew( 0, &i2c_base->cnt ); + + //if( gd->flags & GD_FLG_RELOC ) bus_initialized[ current_bus ] = 1; +} + +static int i2c_read_byte( + unsigned char devaddr, + unsigned char regoffset, + unsigned char *value +) +{ + int i2c_error = 0; + unsigned short status; + + /* wait until bus not busy */ + wait_for_bb(); + + /* one byte only */ + writew(1, &i2c_base->cnt); + /* set slave address */ + writew(devaddr, &i2c_base->sa); + /* no stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | + I2C_CON_TRX, &i2c_base->con); + + /* send register offset */ + while (1) { + status = wait_for_pin(); + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + goto read_exit; + } + if (status & I2C_STAT_XRDY) { + /* Important: have to use byte access */ + writeb(regoffset, &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &i2c_base->stat); + break; + } + } + + /* set slave address */ + writew(devaddr, &i2c_base->sa); + /* read one byte from slave */ + writew(1, &i2c_base->cnt); + /* need stop bit here */ + writew(I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_STP, + &i2c_base->con); + + /* receive data */ + while (1) { + status = wait_for_pin(); + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + goto read_exit; + } + if (status & I2C_STAT_RRDY) { + *value = readw(&i2c_base->data); + writew(I2C_STAT_RRDY, &i2c_base->stat); + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &i2c_base->stat); + break; + } + } + +read_exit: + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + writew(0, &i2c_base->cnt); + return i2c_error; +} + +int i2c_write( + unsigned char chip, + unsigned int addr, + int alen, + unsigned char *buffer, + int len +) +{ + int i; + unsigned short status; + int i2c_error = 0; + + if (alen > 1) { + printk("I2C write: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + printk("I2C write: address 0x%x + 0x%x out of range\n", + addr, len); + return 1; + } + + /* wait until bus not busy */ + wait_for_bb(); + + /* start address phase - will write regoffset + len bytes data */ + writew(alen + len, &i2c_base->cnt); + /* set slave address */ + writew(chip, &i2c_base->sa); + /* stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_STP, &i2c_base->con); + + /* Send address byte */ + status = wait_for_pin(); + + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + printk("error waiting for i2c address ACK (status=0x%x)\n", + status); + goto write_exit; + } + + if (status & I2C_STAT_XRDY) { + writeb(addr & 0xFF, &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } else { + i2c_error = 1; + printk("i2c bus not ready for transmit (status=0x%x)\n", + status); + goto write_exit; + } + + /* address phase is over, now write data */ + for (i = 0; i < len; i++) { + status = wait_for_pin(); + + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + printk("i2c error waiting for data ACK (status=0x%x)\n", + status); + goto write_exit; + } + + if (status & I2C_STAT_XRDY) { + writeb(buffer[i], &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } else { + i2c_error = 1; + printk("i2c bus not ready for Tx (i=%d)\n", i); + goto write_exit; + } + } + +write_exit: + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + return i2c_error; +} + +int i2c_read( + unsigned char chip, + uint addr, + int alen, + unsigned char *buffer, + int len +) +{ + int i; + + if (alen > 1) { + printk("I2C read: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + printk("I2C read: address out of range\n"); + return 1; + } + + for (i = 0; i < len; i++) { + if (i2c_read_byte(chip, addr + i, &buffer[i])) { + printk("I2C read: I/O error\n"); + i2c_init( CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE ); + return 1; + } + } + + return 0; +} + +/* Write (fill) memory + * + * Syntax: + * i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] + */ +static int imw ( unsigned char chip, unsigned long addr, unsigned char byte ) +{ + + unsigned int alen; + int count; + + alen = 1; + count = 1; + + while (count-- > 0) { + if (i2c_write(chip, addr++, alen, &byte, 1) != 0) + printk("Error writing the chip.\n"); + /* + * Wait for the write to complete. The write can take + * up to 10mSec (we allow a little more time). + */ + } + + return (0); +} + +/* + * Syntax: + * i2c md {i2c_chip} {addr}{.0, .1, .2} {len} + */ +static int imd( unsigned char chip, unsigned int addr, unsigned int length ) +{ + int j, nbytes, linebytes; + + unsigned int alen = 0; + if (alen > 3) return 0; + + /* + * Print the lines. + * + * We buffer all read data, so we can make sure data is read only + * once. + */ + nbytes = length; + do { + unsigned char linebuf[DISP_LINE_LEN]; + unsigned char *cp; + + linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; + + if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0) + printk ("Error reading the chip.\n"); + else { + printk("%04x:", addr); + cp = linebuf; + for (j=0; j 0x7e)) + printk ("."); + else + printk("%c", *cp); + cp++; + } + printk ("\n"); + } + nbytes -= linebytes; + } while (nbytes > 0); + + return 0; +} diff --git a/c/src/lib/libbsp/arm/beagle/misc/restart.c b/c/src/lib/libbsp/arm/beagle/misc/restart.c new file mode 100644 index 0000000000..fe7775ae06 --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/misc/restart.c @@ -0,0 +1,32 @@ +/** + * @file + * + * @ingroup beagle + * + * @brief Restart implementation. + */ + +/* + * Copyright (c) 2012 Claas Ziemke. All rights reserved. + * + * Claas Ziemke + * Kernerstrasse 11 + * 70182 Stuttgart + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include + +#include + +#include + +void bsp_restart(void *addr) +{ + BEAGLE_DO_RESTART(addr); +} diff --git a/c/src/lib/libbsp/arm/beagle/misc/system-clocks.c b/c/src/lib/libbsp/arm/beagle/misc/system-clocks.c new file mode 100644 index 0000000000..56b5d9aadb --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/misc/system-clocks.c @@ -0,0 +1,140 @@ +/** + * @file + * + * @ingroup beagle + * + * @brief System clocks. + */ + +/* + * Copyright (c) 2012 Claas Ziemke. All rights reserved. + * + * Claas Ziemke + * Kernerstrasse 11 + * 70182 Stuttgart + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include +#include + +uint32_t beagle_sysclk(void) +{ + uint32_t sysclk_ctrl = BEAGLE_SYSCLK_CTRL; + + return (sysclk_ctrl & 0x1) == 0 ? + BEAGLE_OSCILLATOR_MAIN + : (397 * BEAGLE_OSCILLATOR_RTC); +} + +uint32_t beagle_hclkpll_clk(void) +{ + uint32_t sysclk = beagle_sysclk(); + uint32_t hclkpll_ctrl = BEAGLE_HCLKPLL_CTRL; + uint32_t m = HCLK_PLL_M_GET(hclkpll_ctrl) + 1; + uint32_t n = HCLK_PLL_N_GET(hclkpll_ctrl) + 1; + uint32_t p = 1U << HCLK_PLL_P_GET(hclkpll_ctrl); + uint32_t hclkpll_clk = 0; + + if ((hclkpll_ctrl & HCLK_PLL_BYPASS) != 0) { + if ((hclkpll_ctrl & HCLK_PLL_DIRECT) != 0) { + hclkpll_clk = sysclk; + } else { + hclkpll_clk = sysclk / (2 * p); + } + } else { + if ((hclkpll_ctrl & HCLK_PLL_DIRECT) != 0) { + hclkpll_clk = (m * sysclk) / n; + } else { + if ((hclkpll_ctrl & HCLK_PLL_FBD_FCLKOUT) != 0) { + hclkpll_clk = m * (sysclk / n); + } else { + hclkpll_clk = (m / (2 * p)) * (sysclk / n); + } + } + } + + return hclkpll_clk; +} + +uint32_t beagle_periph_clk(void) +{ + uint32_t pwr_ctrl = BEAGLE_PWR_CTRL; + uint32_t periph_clk = 0; + + if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) { + uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL; + uint32_t div = HCLK_DIV_PERIPH_CLK_GET(hclkdiv_ctrl) + 1; + + periph_clk = beagle_hclkpll_clk() / div; + } else { + periph_clk = beagle_sysclk(); + } + + return periph_clk; +} + +uint32_t beagle_hclk(void) +{ + uint32_t pwr_ctrl = BEAGLE_PWR_CTRL; + uint32_t hclk = 0; + + if ((pwr_ctrl & PWR_HCLK_USES_PERIPH_CLK) != 0) { + hclk = beagle_periph_clk(); + } else { + if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) { + uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL; + uint32_t div = 1U << HCLK_DIV_HCLK_GET(hclkdiv_ctrl); + + hclk = beagle_hclkpll_clk() / div; + } else { + hclk = beagle_sysclk(); + } + } + + return hclk; +} + +uint32_t beagle_arm_clk(void) +{ + uint32_t pwr_ctrl = BEAGLE_PWR_CTRL; + uint32_t arm_clk = 0; + + if ((pwr_ctrl & PWR_HCLK_USES_PERIPH_CLK) != 0) { + arm_clk = beagle_periph_clk(); + } else { + if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) { + arm_clk = beagle_hclkpll_clk(); + } else { + arm_clk = beagle_sysclk(); + } + } + + return arm_clk; +} + +uint32_t beagle_dram_clk(void) +{ + uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL; + uint32_t div = HCLK_DIV_DDRAM_CLK_GET(hclkdiv_ctrl); + uint32_t dram_clk = 0; + + if (div != 0) { + uint32_t pwr_ctrl = BEAGLE_PWR_CTRL; + + if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) { + dram_clk = beagle_hclkpll_clk(); + } else { + dram_clk = beagle_sysclk(); + } + + dram_clk /= div; + } + + return dram_clk; +} diff --git a/c/src/lib/libbsp/arm/beagle/misc/timer.c b/c/src/lib/libbsp/arm/beagle/misc/timer.c new file mode 100644 index 0000000000..50570e0b00 --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/misc/timer.c @@ -0,0 +1,46 @@ +/** + * @file + * + * @ingroup beagle + * + * @brief Benchmark timer support. + */ + +/* + * Copyright (c) 2012 Claas Ziemke. All rights reserved. + * + * Claas Ziemke + * Kernerstrasse 11 + * 70182 Stuttgart + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include +#include +#include + +#include + +static uint32_t benchmark_timer_base; + +void benchmark_timer_initialize(void) +{ + benchmark_timer_base = beagleboard_timer(); +} + +uint32_t benchmark_timer_read(void) +{ + return beagleboard_timer() - benchmark_timer_base; +} + +void benchmark_timer_disable_subtracting_average_overhead( + bool find_average_overhead +) +{ + /* VOID */ +} -- cgit v1.2.3