| /* |
| * arch/arm/mach-at91/include/mach/uncompress.h |
| * |
| * Copyright (C) 2003 SAN People |
| * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> |
| * |
| * 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 |
| */ |
| |
| #ifndef __ASM_ARCH_UNCOMPRESS_H |
| #define __ASM_ARCH_UNCOMPRESS_H |
| |
| #include <linux/io.h> |
| #include <linux/atmel_serial.h> |
| #include <mach/hardware.h> |
| |
| #include <mach/at91_dbgu.h> |
| #include <mach/cpu.h> |
| |
| void __iomem *at91_uart; |
| |
| static const u32 uarts_rm9200[] = { |
| AT91_BASE_DBGU0, |
| AT91RM9200_BASE_US0, |
| AT91RM9200_BASE_US1, |
| AT91RM9200_BASE_US2, |
| AT91RM9200_BASE_US3, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9260[] = { |
| AT91_BASE_DBGU0, |
| AT91SAM9260_BASE_US0, |
| AT91SAM9260_BASE_US1, |
| AT91SAM9260_BASE_US2, |
| AT91SAM9260_BASE_US3, |
| AT91SAM9260_BASE_US4, |
| AT91SAM9260_BASE_US5, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9261[] = { |
| AT91_BASE_DBGU0, |
| AT91SAM9261_BASE_US0, |
| AT91SAM9261_BASE_US1, |
| AT91SAM9261_BASE_US2, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9263[] = { |
| AT91_BASE_DBGU1, |
| AT91SAM9263_BASE_US0, |
| AT91SAM9263_BASE_US1, |
| AT91SAM9263_BASE_US2, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9g45[] = { |
| AT91_BASE_DBGU1, |
| AT91SAM9G45_BASE_US0, |
| AT91SAM9G45_BASE_US1, |
| AT91SAM9G45_BASE_US2, |
| AT91SAM9G45_BASE_US3, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9rl[] = { |
| AT91_BASE_DBGU0, |
| AT91SAM9RL_BASE_US0, |
| AT91SAM9RL_BASE_US1, |
| AT91SAM9RL_BASE_US2, |
| AT91SAM9RL_BASE_US3, |
| 0, |
| }; |
| |
| static const u32 uarts_sam9x5[] = { |
| AT91_BASE_DBGU0, |
| AT91SAM9X5_BASE_USART0, |
| AT91SAM9X5_BASE_USART1, |
| AT91SAM9X5_BASE_USART2, |
| 0, |
| }; |
| |
| static const u32 uarts_sama5d3[] = { |
| AT91_BASE_DBGU1, |
| SAMA5D3_BASE_USART0, |
| SAMA5D3_BASE_USART1, |
| SAMA5D3_BASE_USART2, |
| SAMA5D3_BASE_USART3, |
| 0, |
| }; |
| |
| static const u32 uarts_sama5d4[] = { |
| AT91_BASE_DBGU2, |
| SAMA5D4_BASE_USART3, |
| 0, |
| }; |
| |
| static inline const u32* decomp_soc_detect(void __iomem *dbgu_base) |
| { |
| u32 cidr, socid; |
| |
| cidr = __raw_readl(dbgu_base + AT91_DBGU_CIDR); |
| socid = cidr & ~AT91_CIDR_VERSION; |
| |
| switch (socid) { |
| case ARCH_ID_AT91RM9200: |
| return uarts_rm9200; |
| |
| case ARCH_ID_AT91SAM9G20: |
| case ARCH_ID_AT91SAM9260: |
| return uarts_sam9260; |
| |
| case ARCH_ID_AT91SAM9261: |
| return uarts_sam9261; |
| |
| case ARCH_ID_AT91SAM9263: |
| return uarts_sam9263; |
| |
| case ARCH_ID_AT91SAM9G45: |
| return uarts_sam9g45; |
| |
| case ARCH_ID_AT91SAM9RL64: |
| return uarts_sam9rl; |
| |
| case ARCH_ID_AT91SAM9N12: |
| case ARCH_ID_AT91SAM9X5: |
| return uarts_sam9x5; |
| |
| case ARCH_ID_SAMA5: |
| cidr = __raw_readl(dbgu_base + AT91_DBGU_EXID); |
| if (cidr & ARCH_EXID_SAMA5D3) |
| return uarts_sama5d3; |
| else if (cidr & ARCH_EXID_SAMA5D4) |
| return uarts_sama5d4; |
| |
| break; |
| } |
| |
| /* at91sam9g10 */ |
| if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) { |
| return uarts_sam9261; |
| } |
| /* at91sam9xe */ |
| else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) { |
| return uarts_sam9260; |
| } |
| |
| return NULL; |
| } |
| |
| static inline void arch_decomp_setup(void) |
| { |
| int i = 0; |
| const u32* usarts; |
| |
| usarts = decomp_soc_detect((void __iomem *)AT91_BASE_DBGU0); |
| if (!usarts) |
| usarts = decomp_soc_detect((void __iomem *)AT91_BASE_DBGU1); |
| if (!usarts) |
| usarts = decomp_soc_detect((void __iomem *)AT91_BASE_DBGU2); |
| if (!usarts) { |
| at91_uart = NULL; |
| return; |
| } |
| |
| do { |
| /* physical address */ |
| at91_uart = (void __iomem *)usarts[i]; |
| |
| if (__raw_readl(at91_uart + ATMEL_US_BRGR)) |
| return; |
| i++; |
| } while (usarts[i]); |
| |
| at91_uart = NULL; |
| } |
| |
| /* |
| * The following code assumes the serial port has already been |
| * initialized by the bootloader. If you didn't setup a port in |
| * your bootloader then nothing will appear (which might be desired). |
| * |
| * This does not append a newline |
| */ |
| static void putc(int c) |
| { |
| if (!at91_uart) |
| return; |
| |
| while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY)) |
| barrier(); |
| __raw_writel(c, at91_uart + ATMEL_US_THR); |
| } |
| |
| static inline void flush(void) |
| { |
| if (!at91_uart) |
| return; |
| |
| /* wait for transmission to complete */ |
| while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) |
| barrier(); |
| } |
| |
| #endif |