From c98b47ad24b2d91f41c09a3d62d7f70ad84f4b7d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 30 Mar 2008 11:30:43 +0100 Subject: core support for Freescale mx31 This patch adds the core support for Freescale mx31 Signed-off-by: Sascha Hauer Signed-off-by: Guennadi Liakhovetski --- cpu/arm1136/mx31/Makefile | 44 ++++++++ cpu/arm1136/mx31/generic.c | 99 ++++++++++++++++++ cpu/arm1136/mx31/interrupts.c | 113 +++++++++++++++++++++ cpu/arm1136/mx31/serial.c | 230 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 486 insertions(+) create mode 100644 cpu/arm1136/mx31/Makefile create mode 100644 cpu/arm1136/mx31/generic.c create mode 100644 cpu/arm1136/mx31/interrupts.c create mode 100644 cpu/arm1136/mx31/serial.c (limited to 'cpu') diff --git a/cpu/arm1136/mx31/Makefile b/cpu/arm1136/mx31/Makefile new file mode 100644 index 0000000..1fc8eea --- /dev/null +++ b/cpu/arm1136/mx31/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundatio; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS = interrupts.o serial.o generic.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +####################################################################### +## + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend diff --git a/cpu/arm1136/mx31/generic.c b/cpu/arm1136/mx31/generic.c new file mode 100644 index 0000000..297d616 --- /dev/null +++ b/cpu/arm1136/mx31/generic.c @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2007 + * Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +static u32 mx31_decode_pll(u32 reg, u32 infreq) +{ + u32 mfi = (reg >> 10) & 0xf; + u32 mfn = reg & 0x3f; + u32 mfd = (reg >> 16) & 0x3f; + u32 pd = (reg >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + mfd += 1; + pd += 1; + + return ((2 * (infreq >> 10) * (mfi * mfd + mfn)) / + (mfd * pd)) << 10; +} + +u32 mx31_get_mpl_dpdgck_clk(void) +{ + u32 infreq; + + if ((__REG(CCM_CCMR) & CCMR_PRCS_MASK) == CCMR_FPM) + infreq = CONFIG_MX31_CLK32 * 1024; + else + infreq = CONFIG_MX31_HCLK_FREQ; + + return mx31_decode_pll(__REG(CCM_MPCTL), infreq); } + +u32 mx31_get_mcu_main_clk(void) +{ + /* For now we assume mpl_dpdgck_clk == mcu_main_clk + * which should be correct for most boards + */ + return mx31_get_mpl_dpdgck_clk(); +} + +u32 mx31_get_ipg_clk(void) +{ + u32 freq = mx31_get_mcu_main_clk(); + u32 pdr0 = __REG(CCM_PDR0); + + freq /= ((pdr0 >> 3) & 0x7) + 1; + freq /= ((pdr0 >> 6) & 0x3) + 1; + + return freq; +} + +void mx31_dump_clocks(void) +{ + u32 cpufreq = mx31_get_mcu_main_clk(); + printf("mx31 cpu clock: %dMHz\n", cpufreq / 1000000); + printf("ipg clock : %dHz\n", mx31_get_ipg_clk()); +} + +void mx31_gpio_mux(unsigned long mode) +{ + unsigned long reg, shift, tmp; + + reg = IOMUXC_BASE + (mode & 0xfc); + shift = (~mode & 0x3) * 8; + + tmp = __REG(reg); + tmp &= ~(0xff << shift); + tmp |= ((mode >> 8) & 0xff) << shift; + __REG(reg) = tmp; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + printf("CPU: Freescale i.MX31 at %d MHz\n", + mx31_get_mcu_main_clk() / 1000000); + return 0; +} +#endif diff --git a/cpu/arm1136/mx31/interrupts.c b/cpu/arm1136/mx31/interrupts.c new file mode 100644 index 0000000..189f601 --- /dev/null +++ b/cpu/arm1136/mx31/interrupts.c @@ -0,0 +1,113 @@ +/* + * (C) Copyright 2007 + * Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#define TIMER_BASE 0x53f90000 /* General purpose timer 1 */ + +/* General purpose timers registers */ +#define GPTCR __REG(TIMER_BASE) /* Control register */ +#define GPTPR __REG(TIMER_BASE + 0x4) /* Prescaler register */ +#define GPTSR __REG(TIMER_BASE + 0x8) /* Status register */ +#define GPTCNT __REG(TIMER_BASE + 0x24) /* Counter register */ + +/* General purpose timers bitfields */ +#define GPTCR_SWR (1<<15) /* Software reset */ +#define GPTCR_FRR (1<<9) /* Freerun / restart */ +#define GPTCR_CLKSOURCE_32 (4<<6) /* Clock source */ +#define GPTCR_TEN (1) /* Timer enable */ + +/* + * nothing really to do with interrupts, just starts up a counter. + */ +int interrupt_init(void) +{ + int i; + + /* setup GP Timer 1 */ + GPTCR = GPTCR_SWR; + for (i = 0; i < 100; i++) GPTCR = 0; /* We have no udelay by now */ + GPTPR = 0; /* 32Khz */ + /* Freerun Mode, PERCLK1 input */ + GPTCR |= GPTCR_CLKSOURCE_32 | GPTCR_TEN; + + return 0; +} + +void reset_timer_masked(void) +{ + GPTCR = 0; + /* Freerun Mode, PERCLK1 input*/ + GPTCR = GPTCR_CLKSOURCE_32 | GPTCR_TEN; +} + +ulong get_timer_masked(void) +{ + ulong val = GPTCNT; + return val; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void set_timer(ulong t) +{ +} + +/* delay x useconds AND perserve advance timstamp value */ +void udelay(unsigned long usec) +{ + ulong tmo, tmp; + + if (usec >= 1000) { + /* "big" number, spread normalization to seconds */ + /* start to normalize for usec to ticks per sec */ + tmo = usec / 1000; + /* find number of "ticks" to wait to achieve target */ + tmo *= CFG_HZ; + tmo /= 1000; /* finish normalize. */ + } else { + /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CFG_HZ; + tmo /= (1000*1000); + } + + tmp = get_timer(0); /* get current timestamp */ + if ((tmo + tmp + 1) < tmp) + /* setting this forward will roll time stamp */ + /* reset "advancing" timestamp to 0, set lastinc value */ + reset_timer_masked(); + else + /* else, set advancing stamp wake up time */ + tmo += tmp; + while (get_timer_masked() < tmo)/* loop till event */ + /*NOP*/; +} + +void reset_cpu(ulong addr) +{ + __REG16(WDOG_BASE) = 4; +} diff --git a/cpu/arm1136/mx31/serial.c b/cpu/arm1136/mx31/serial.c new file mode 100644 index 0000000..f7e1b3b --- /dev/null +++ b/cpu/arm1136/mx31/serial.c @@ -0,0 +1,230 @@ +/* + * (c) 2007 Sascha Hauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#if defined CONFIG_MX31_UART + +#include + +#define __REG(x) (*((volatile u32 *)(x))) + +#ifdef CFG_MX31_UART1 +#define UART_PHYS 0x43f90000 +#elif defined(CFG_MX31_UART2) +#define UART_PHYS 0x43f94000 +#elif defined(CFG_MX31_UART3) +#define UART_PHYS 0x5000c000 +#elif defined(CFG_MX31_UART4) +#define UART_PHYS 0x43fb0000 +#elif defined(CFG_MX31_UART5) +#define UART_PHYS 0x43fb4000 +#else +#error "define CFG_MX31_UARTx to use the mx31 UART driver" +#endif + +/* Register definitions */ +#define URXD 0x0 /* Receiver Register */ +#define UTXD 0x40 /* Transmitter Register */ +#define UCR1 0x80 /* Control Register 1 */ +#define UCR2 0x84 /* Control Register 2 */ +#define UCR3 0x88 /* Control Register 3 */ +#define UCR4 0x8c /* Control Register 4 */ +#define UFCR 0x90 /* FIFO Control Register */ +#define USR1 0x94 /* Status Register 1 */ +#define USR2 0x98 /* Status Register 2 */ +#define UESC 0x9c /* Escape Character Register */ +#define UTIM 0xa0 /* Escape Timer Register */ +#define UBIR 0xa4 /* BRM Incremental Register */ +#define UBMR 0xa8 /* BRM Modulator Register */ +#define UBRC 0xac /* Baud Rate Count Register */ +#define UTS 0xb4 /* UART Test Register (mx31) */ + +/* UART Control Register Bit Fields.*/ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */ +#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ + +DECLARE_GLOBAL_DATA_PTR; + +void serial_setbrg(void) +{ + u32 clk = mx31_get_ipg_clk(); + + if (!gd->baudrate) + gd->baudrate = CONFIG_BAUDRATE; + + __REG(UART_PHYS + UFCR) = 4 << 7; /* divide input clock by 2 */ + __REG(UART_PHYS + UBIR) = 0xf; + __REG(UART_PHYS + UBMR) = clk / (2 * gd->baudrate); + +} + +int serial_getc(void) +{ + while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY); + return __REG(UART_PHYS + URXD); +} + +void serial_putc(const char c) +{ + __REG(UART_PHYS + UTXD) = c; + + /* wait for transmitter to be ready */ + while (!(__REG(UART_PHYS + UTS) & UTS_TXEMPTY)); + + /* If \n, also do \r */ + if (c == '\n') + serial_putc('\r'); +} + +/* + * Test whether a character is in the RX buffer */ +int serial_tstc(void) +{ + /* If receive fifo is empty, return false */ + if (__REG(UART_PHYS + UTS) & UTS_RXEMPTY) + return 0; + return 1; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init(void) +{ + __REG(UART_PHYS + UCR1) = 0x0; + __REG(UART_PHYS + UCR2) = 0x0; + + while (!(__REG(UART_PHYS + UCR2) & UCR2_SRST)); + + __REG(UART_PHYS + UCR3) = 0x0704; + __REG(UART_PHYS + UCR4) = 0x8000; + __REG(UART_PHYS + UESC) = 0x002b; + __REG(UART_PHYS + UTIM) = 0x0; + + __REG(UART_PHYS + UTS) = 0x0; + + serial_setbrg(); + + __REG(UART_PHYS + UCR2) = UCR2_WS | UCR2_IRTS | UCR2_RXEN | \ + UCR2_TXEN | UCR2_SRST; + + __REG(UART_PHYS + UCR1) = UCR1_UARTEN; + + return 0; +} + + +#endif /* CONFIG_MX31 */ -- cgit v1.1