diff --git a/Documentation/boards.dox b/Documentation/boards.dox index f0fc2f1..8d4fabb 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -43,6 +43,7 @@ @li @subpage tny-a9263 @li @subpage usb-a9g20-lpw @li @subpage usb-a9263 +@li @subpage virt2real Blackfin type: diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 21f9012..3754646 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -54,6 +54,12 @@ select GPIOLIB select MFD_SYSCON +config ARCH_DAVINCI + bool "TI Davinci" + select CPU_ARM926T + select HAS_DEBUG_LL + select GPIOLIB + config ARCH_EP93XX bool "Cirrus Logic EP93xx" select CPU_ARM920T @@ -188,6 +194,7 @@ source arch/arm/mach-at91/Kconfig source arch/arm/mach-bcm2835/Kconfig source arch/arm/mach-clps711x/Kconfig +source arch/arm/mach-davinci/Kconfig source arch/arm/mach-ep93xx/Kconfig source arch/arm/mach-highbank/Kconfig source arch/arm/mach-imx/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2bbba35..c1bd836 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -54,6 +54,7 @@ machine-$(CONFIG_ARCH_AT91) := at91 machine-$(CONFIG_ARCH_BCM2835) := bcm2835 machine-$(CONFIG_ARCH_CLPS711X) := clps711x +machine-$(CONFIG_ARCH_DAVINCI) := davinci machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_HIGHBANK) := highbank machine-$(CONFIG_ARCH_IMX) := imx diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index ac85093..16742d9 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -99,5 +99,6 @@ obj-$(CONFIG_MACH_USB_A9G20) += usb-a926x/ obj-$(CONFIG_MACH_VERSATILEPB) += versatile/ obj-$(CONFIG_MACH_VEXPRESS) += vexpress/ +obj-$(CONFIG_MACH_VIRT2REAL) += virt2real/ obj-$(CONFIG_MACH_ZEDBOARD) += avnet-zedboard/ obj-$(CONFIG_MACH_VARISCITE_MX6) += variscite-mx6/ diff --git a/arch/arm/boards/virt2real/Makefile b/arch/arm/boards/virt2real/Makefile new file mode 100644 index 0000000..b2f44bb --- /dev/null +++ b/arch/arm/boards/virt2real/Makefile @@ -0,0 +1 @@ +obj-y += lowlevel.o board.o diff --git a/arch/arm/boards/virt2real/board.c b/arch/arm/boards/virt2real/board.c new file mode 100644 index 0000000..b7f7217 --- /dev/null +++ b/arch/arm/boards/virt2real/board.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 Antony Pavlov + * + * This file is part of barebox. + * 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 version 2 + * as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include + +static int hostname_init(void) +{ + barebox_set_hostname("virt2real"); + + return 0; +} +core_initcall(hostname_init); diff --git a/arch/arm/boards/virt2real/lowlevel.c b/arch/arm/boards/virt2real/lowlevel.c new file mode 100644 index 0000000..3c90d78 --- /dev/null +++ b/arch/arm/boards/virt2real/lowlevel.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Antony Pavlov + * + * This file is part of barebox. + * 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 version 2 + * as published by the Free Software Foundation. + * + * 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. + * + */ + +#define __LOWLEVEL_INIT__ + +#include +#include +#include +#include +#include + +#define VIRT2REAL_SRAM_BASE 0x82000000 +#define VIRT2REAL_SRAM_SIZE SZ_16M + +void __naked __bare_init barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + + barebox_arm_entry(VIRT2REAL_SRAM_BASE, VIRT2REAL_SRAM_SIZE, 0); +} diff --git a/arch/arm/boards/virt2real/virt2real.dox b/arch/arm/boards/virt2real/virt2real.dox new file mode 100644 index 0000000..fc38321 --- /dev/null +++ b/arch/arm/boards/virt2real/virt2real.dox @@ -0,0 +1,41 @@ +/** @page virt2real virt2real board + +virt2real is a is a miniature board for creation of WiFi +or internet controllable smart devices. + +The board has +@li TI DaVinchi DM365 running at 300 MHz +@li 128 MiB DDR2 SDRAM; +@li 256 MiB NAND Flash Memory; +@li 2 x UART serial interfaces; +@li 2 x Ethernet interfaces; +@li 1 x USB interface; +@li microSD card slot. + +The board uses U-Boot as bootloader. + +Barebox mini-howto: + +1. Connect to the boards's UART0 (115200 8N1); +Use J2.2 (GND), J2.4 (UART0_TXD), J2.6(UART0_RXD) pins. + +2. Turn board's power on; + +3. Wait 'Hit any key to stop autoboot' prompt and press the space key. + +4. Upload barebox.bin via Ymodem +@verbatim + virt2real ># loady +@endverbatim + +5. Run barebox +@verbatim + virt2real ># go 0x82000000 +@endverbatim + +virt2real links: +@li http://virt2real.com/ +@li http://wiki.virt2real.ru/ +@li https://github.com/virt2real + +*/ diff --git a/arch/arm/configs/virt2real_defconfig b/arch/arm/configs/virt2real_defconfig new file mode 100644 index 0000000..a81d18b --- /dev/null +++ b/arch/arm/configs/virt2real_defconfig @@ -0,0 +1,49 @@ +CONFIG_BUILTIN_DTB=y +CONFIG_BUILTIN_DTB_NAME="virt2real" +CONFIG_ARCH_DAVINCI=y +CONFIG_AEABI=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_TEXT_BASE=0x82300000 +CONFIG_MALLOC_SIZE=0x200000 +CONFIG_MALLOC_TLSF=y +CONFIG_PROMPT="virt2real: " +CONFIG_LONGHELP=y +CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_MENU=y +CONFIG_PASSWORD=y +CONFIG_PARTITION=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_MM=y +# CONFIG_CMD_BOOTM is not set +# CONFIG_CMD_BOOTU is not set +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_LED=y +CONFIG_OFDEVICE=y +CONFIG_OF_BAREBOX_DRIVERS=y +CONFIG_DRIVER_SERIAL_NS16550=y +# CONFIG_SPI is not set +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_GPIO_OF=y +CONFIG_SHA1=y +CONFIG_SHA256=y diff --git a/arch/arm/dts/dm365.dtsi b/arch/arm/dts/dm365.dtsi new file mode 100644 index 0000000..ea69007 --- /dev/null +++ b/arch/arm/dts/dm365.dtsi @@ -0,0 +1,28 @@ +#include "skeleton.dtsi" + +/ { + soc { + compatible = "simple-bus"; + model = "TI TMS320DM365"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x01c00000 0x400000>; + + serial0: serial@1c20000 { + compatible = "ns16550a"; + reg = <0x20000 0x400>; + reg-shift = <2>; + clock-frequency = <24000000>; + status = "disabled"; + }; + + gpio: gpio@1c67000 { + compatible = "ti,dm6441-gpio"; + gpio-controller; + reg = <0x67000 0x800>; + #gpio-cells = <2>; + ti,ngpio = <107>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/dts/virt2real.dts b/arch/arm/dts/virt2real.dts new file mode 100644 index 0000000..09aec1f --- /dev/null +++ b/arch/arm/dts/virt2real.dts @@ -0,0 +1,35 @@ +/dts-v1/; + +#include "dm365.dtsi" + +/ { + model = "virt2real"; + + memory { + reg = <0x82000000 0x01000000>; + }; + + soc { + serial0: serial@1c20000 { + status = "okay"; + }; + + gpio: gpio@1c67000 { + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + + green_led { + label = "green-led"; + gpios = <&gpio 73 0>; + }; + + red_led { + label = "red-led"; + gpios = <&gpio 74 0>; + }; + }; +}; diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 28afaa3..52114d0 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -3,6 +3,13 @@ #include +#include +/* + * Allow for constants defined here to be used from assembly code + * by prepending the UL suffix only with actual C code compilation. + */ +#define UL(x) _AC(x, UL) + static inline void arm_add_mem_device(const char* name, resource_size_t start, resource_size_t size) { diff --git a/arch/arm/mach-arm.dox b/arch/arm/mach-arm.dox index 758df3f..1d2de48 100644 --- a/arch/arm/mach-arm.dox +++ b/arch/arm/mach-arm.dox @@ -54,6 +54,8 @@ @subsection mach_arm_omap_info OMAP CPUs +@li @subpage dev_davinci_arch + @li @subpage dev_omap_arch @subsection mach_arm_s3c24xx_info S3C24XX CPUs diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig new file mode 100644 index 0000000..3165d50 --- /dev/null +++ b/arch/arm/mach-davinci/Kconfig @@ -0,0 +1,16 @@ +if ARCH_DAVINCI + +config ARCH_TEXT_BASE + hex + default 0x82000000 + +choice + prompt "Davinci Board type" + +config MACH_VIRT2REAL + bool "Virt2Real" + select HAVE_DEFAULT_ENVIRONMENT_NEW + +endchoice + +endif diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile new file mode 100644 index 0000000..b96d414 --- /dev/null +++ b/arch/arm/mach-davinci/Makefile @@ -0,0 +1 @@ +obj-y += time.o diff --git a/arch/arm/mach-davinci/include/mach/debug_ll.h b/arch/arm/mach-davinci/include/mach/debug_ll.h new file mode 100644 index 0000000..587f408 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/debug_ll.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Antony Pavlov + * + * This file is part of barebox. + * 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 version 2 + * as published by the Free Software Foundation. + * + * 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. + * + */ + +/** @file + * This File contains declaration for early output support + */ +#ifndef __INCLUDE_ARCH_DEBUG_LL_H__ +#define __INCLUDE_ARCH_DEBUG_LL_H__ + +#include +#include + +#define DEBUG_LL_UART_ADDR DAVINCI_UART0_BASE +#define DEBUG_LL_UART_RSHFT 2 + +#define rbr (0 << DEBUG_LL_UART_RSHFT) +#define lsr (5 << DEBUG_LL_UART_RSHFT) +#define LSR_THRE 0x20 /* Xmit holding register empty */ + +static inline void PUTC_LL(char ch) +{ + while (!(__raw_readb(DEBUG_LL_UART_ADDR + lsr) & LSR_THRE)) + ; + + __raw_writeb(ch, DEBUG_LL_UART_ADDR + rbr); +} + +#endif /* __INCLUDE_ARCH_DEBUG_LL_H__ */ diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h new file mode 100644 index 0000000..ea9f481 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -0,0 +1,29 @@ +/* + * Hardware definitions common to all DaVinci family processors + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +/* + * Before you add anything to this file: + * + * This header is for defines common to ALL DaVinci family chips. + * Anything that is chip specific should go in .h, + * and the chip/board init code should then explicitly include + * .h + */ +/* + * I/O mapping + */ +#define IO_PHYS UL(0x01c00000) + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h new file mode 100644 index 0000000..bc7449f --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -0,0 +1,20 @@ +/* + * DaVinci serial device definitions + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +#include + +#define DAVINCI_UART0_BASE (IO_PHYS + 0x20000) +#define DAVINCI_UART1_BASE (IO_PHYS + 0x20400) +#define DAVINCI_UART2_BASE (IO_PHYS + 0x20800) + +#endif /* __ASM_ARCH_SERIAL_H */ diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h new file mode 100644 index 0000000..34781b6 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/time.h @@ -0,0 +1,20 @@ +/* + * Local header file for DaVinci time code. + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H +#define __ARCH_ARM_MACH_DAVINCI_TIME_H + +#include + +#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) +#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) +#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) + +#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */ diff --git a/arch/arm/mach-davinci/mach-davinci.dox b/arch/arm/mach-davinci/mach-davinci.dox new file mode 100644 index 0000000..789eacc --- /dev/null +++ b/arch/arm/mach-davinci/mach-davinci.dox @@ -0,0 +1,7 @@ +/** @page dev_davinci_arch TI DaVinci in barebox + +@section davinci_boards DaVinci-based boards + +@li @subpage virt2real + +*/ diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c new file mode 100644 index 0000000..60f0d19 --- /dev/null +++ b/arch/arm/mach-davinci/time.c @@ -0,0 +1,209 @@ +/* + * DaVinci timer subsystem + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include + +#include + +/* Timer register offsets */ +#define PID12 0x0 +#define TIM12 0x10 +#define TIM34 0x14 +#define PRD12 0x18 +#define PRD34 0x1c +#define TCR 0x20 +#define TGCR 0x24 +#define WDTCR 0x28 + +/* Timer register bitfields */ +#define TCR_ENAMODE_DISABLE 0x0 +#define TCR_ENAMODE_ONESHOT 0x1 +#define TCR_ENAMODE_PERIODIC 0x2 +#define TCR_ENAMODE_MASK 0x3 + +#define TGCR_TIMMODE_SHIFT 2 +#define TGCR_TIMMODE_64BIT_GP 0x0 +#define TGCR_TIMMODE_32BIT_UNCHAINED 0x1 +#define TGCR_TIMMODE_64BIT_WDOG 0x2 +#define TGCR_TIMMODE_32BIT_CHAINED 0x3 + +#define TGCR_TIM12RS_SHIFT 0 +#define TGCR_TIM34RS_SHIFT 1 +#define TGCR_RESET 0x0 +#define TGCR_UNRESET 0x1 +#define TGCR_RESET_MASK 0x3 + +#define WDTCR_WDEN_SHIFT 14 +#define WDTCR_WDEN_DISABLE 0x0 +#define WDTCR_WDEN_ENABLE 0x1 +#define WDTCR_WDKEY_SHIFT 16 +#define WDTCR_WDKEY_SEQ0 0xa5c6 +#define WDTCR_WDKEY_SEQ1 0xda7e + +#define DAVINCI_TIMER_CLOCK 24000000 + +struct timer_s { + void __iomem *base; + unsigned long tim_off; + unsigned long prd_off; + unsigned long enamode_shift; +}; + +static struct timer_s timers[] = { + { + .base = IOMEM(DAVINCI_TIMER0_BASE), + .enamode_shift = 6, + .tim_off = TIM12, + .prd_off = PRD12, + }, + { + .base = IOMEM(DAVINCI_TIMER0_BASE), + .enamode_shift = 22, + .tim_off = TIM34, + .prd_off = PRD34, + }, + { + .base = IOMEM(DAVINCI_TIMER1_BASE), + .enamode_shift = 6, + .tim_off = TIM12, + .prd_off = PRD12, + }, + { + .base = IOMEM(DAVINCI_TIMER1_BASE), + .enamode_shift = 22, + .tim_off = TIM34, + .prd_off = PRD34, + }, +}; + +static struct timer_s *t = &timers[0]; + +static uint64_t davinci_cs_read(void) +{ + return (uint64_t)__raw_readl(t->base + t->tim_off); +} + +static struct clocksource davinci_cs = { + .read = davinci_cs_read, + .mask = CLOCKSOURCE_MASK(32), +}; + +static int timer32_config(struct timer_s *t) +{ + u32 tcr; + + tcr = __raw_readl(t->base + TCR); + + /* disable timer */ + tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); + __raw_writel(tcr, t->base + TCR); + + /* reset counter to zero, set new period */ + __raw_writel(0, t->base + t->tim_off); + __raw_writel(0xffffffff, t->base + t->prd_off); + + /* Set enable mode for periodic timer */ + tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; + + __raw_writel(tcr, t->base + TCR); + + return 0; +} + +/* Global init of 64-bit timer as a whole */ +static void __init timer_init(void __iomem *base) +{ + u32 tgcr; + + /* Disabled, Internal clock source */ + __raw_writel(0, base + TCR); + + /* reset both timers, no pre-scaler for timer34 */ + tgcr = 0; + __raw_writel(tgcr, base + TGCR); + + /* Set both timers to unchained 32-bit */ + tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT; + __raw_writel(tgcr, base + TGCR); + + /* Unreset timers */ + tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | + (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); + __raw_writel(tgcr, base + TGCR); + + /* Init both counters to zero */ + __raw_writel(0, base + TIM12); + __raw_writel(0, base + TIM34); +} + +static int clocksource_init(void) +{ + clocks_calc_mult_shift(&davinci_cs.mult, &davinci_cs.shift, + DAVINCI_TIMER_CLOCK, NSEC_PER_SEC, 10); + + init_clock(&davinci_cs); + + timer_init(IOMEM(DAVINCI_TIMER0_BASE)); + timer_init(IOMEM(DAVINCI_TIMER1_BASE)); + + timer32_config(t); + + return 0; +} +core_initcall(clocksource_init); + +/* reset board using watchdog timer */ +void __noreturn reset_cpu(ulong addr) +{ + u32 tgcr, wdtcr; + void __iomem *base; + + base = IOMEM(DAVINCI_WDOG_BASE); + + /* disable, internal clock source */ + __raw_writel(0, base + TCR); + + /* reset timer, set mode to 64-bit watchdog, and unreset */ + tgcr = 0; + __raw_writel(tgcr, base + TGCR); + tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT; + tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | + (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); + __raw_writel(tgcr, base + TGCR); + + /* clear counter and period regs */ + __raw_writel(0, base + TIM12); + __raw_writel(0, base + TIM34); + __raw_writel(0, base + PRD12); + __raw_writel(0, base + PRD34); + + /* put watchdog in pre-active state */ + wdtcr = __raw_readl(base + WDTCR); + wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) | + (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); + __raw_writel(wdtcr, base + WDTCR); + + /* put watchdog in active state */ + wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) | + (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); + __raw_writel(wdtcr, base + WDTCR); + + /* write an invalid value to the WDKEY field to trigger + * a watchdog reset */ + wdtcr = 0x00004000; + __raw_writel(wdtcr, base + WDTCR); + + unreachable(); +} +EXPORT_SYMBOL(reset_cpu); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7c42656..7302955 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -20,6 +20,13 @@ help Say yes here to enable the GPIO driver for the CLPS711X CPUs +config GPIO_DAVINCI + bool "TI Davinci/Keystone GPIO support" + default y if ARCH_DAVINCI + depends on ARM && ARCH_DAVINCI + help + Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. + config GPIO_GENERIC_PLATFORM bool "Generic memory-mapped GPIO controller support" select GPIO_GENERIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b7c536d..68a76a3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_GPIO_BCM2835) += gpio-bcm2835.o +obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_IMX) += gpio-imx.o diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c new file mode 100644 index 0000000..7d15b85 --- /dev/null +++ b/drivers/gpio/gpio-davinci.c @@ -0,0 +1,211 @@ +/* + * TI DaVinci GPIO Support + * + * Copyright (c) 2006-2007 David Brownell + * Copyright (c) 2007, MontaVista Software, Inc. + * Copyright (c) 2014 Antony Pavlov + * + * 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. + */ + +#include +#include +#include +#include +#include + +#define readl_relaxed readl +#define writel_relaxed writel + +struct davinci_gpio_regs { + u32 dir; + u32 out_data; + u32 set_data; + u32 clr_data; + u32 in_data; + u32 set_rising; + u32 clr_rising; + u32 set_falling; + u32 clr_falling; + u32 intstat; +}; + +struct davinci_gpio_controller { + struct gpio_chip chip; + /* Serialize access to GPIO registers */ + void __iomem *regs; + void __iomem *set_data; + void __iomem *clr_data; + void __iomem *in_data; +}; + +#define chip2controller(chip) \ + container_of(chip, struct davinci_gpio_controller, chip) + +static struct davinci_gpio_regs __iomem *gpio2regs(void __iomem *gpio_base, + unsigned gpio) +{ + void __iomem *ptr; + + if (gpio < 32 * 1) + ptr = gpio_base + 0x10; + else if (gpio < 32 * 2) + ptr = gpio_base + 0x38; + else if (gpio < 32 * 3) + ptr = gpio_base + 0x60; + else if (gpio < 32 * 4) + ptr = gpio_base + 0x88; + else if (gpio < 32 * 5) + ptr = gpio_base + 0xb0; + else + ptr = NULL; + return ptr; +} + +static int davinci_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + + return ((readl_relaxed(&g->dir)) & (1 << offset)) ? + GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + +static inline int __davinci_direction(struct gpio_chip *chip, + unsigned offset, bool out, int value) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + u32 temp; + u32 mask = 1 << offset; + + temp = readl_relaxed(&g->dir); + if (out) { + temp &= ~mask; + writel_relaxed(mask, value ? &g->set_data : &g->clr_data); + } else { + temp |= mask; + } + writel_relaxed(temp, &g->dir); + + return 0; +} + +static int davinci_direction_in(struct gpio_chip *chip, unsigned offset) +{ + return __davinci_direction(chip, offset, false, 0); +} + +static int +davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) +{ + return __davinci_direction(chip, offset, true, value); +} + +/* + * Read the pin's value (works even if it's set up as output); + * returns zero/nonzero. + * + * Note that changes are synched to the GPIO clock, so reading values back + * right after you've set them may give old values. + */ +static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + + return (1 << offset) & readl_relaxed(&g->in_data); +} + +/* + * Assuming the pin is muxed as a gpio output, set its output value. + */ +static void +davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + + writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data); +} + +static struct gpio_ops davinci_gpio_ops = { + .direction_input = davinci_direction_in, + .direction_output = davinci_direction_out, + .get_direction = davinci_get_direction, + .get = davinci_gpio_get, + .set = davinci_gpio_set, +}; + +static int davinci_gpio_probe(struct device_d *dev) +{ + void __iomem *gpio_base; + int ret; + u32 val; + int i, base; + unsigned ngpio; + struct davinci_gpio_controller *chips; + + ret = of_property_read_u32(dev->device_node, "ti,ngpio", &val); + if (ret) { + dev_err(dev, "could not read 'ti,ngpio' property\n"); + return -EINVAL; + } + + ngpio = val; + + if (WARN_ON(ARCH_NR_GPIOS < ngpio)) + ngpio = ARCH_NR_GPIOS; + + chips = xzalloc((ngpio / 32 + 1) * sizeof(*chips)); + + gpio_base = dev_request_mem_region(dev, 0); + if (!gpio_base) { + dev_err(dev, "could not get memory region\n"); + return -ENODEV; + } + + for (i = 0, base = 0; base < ngpio; i++, base += 32) { + struct davinci_gpio_regs __iomem *regs; + struct gpio_chip *gc; + + gc = &chips[i].chip; + gc->ops = &davinci_gpio_ops; + + gc->dev = dev; + gc->base = base; + gc->ngpio = ngpio - base; + if (gc->ngpio > 32) + gc->ngpio = 32; + + regs = gpio2regs(gpio_base, base); + chips[i].regs = regs; + chips[i].set_data = ®s->set_data; + chips[i].clr_data = ®s->clr_data; + chips[i].in_data = ®s->in_data; + + gpiochip_add(gc); + } + + return 0; +} + +static struct of_device_id davinci_gpio_ids[] = { + { .compatible = "ti,dm6441-gpio", }, + { /* sentinel */ }, +}; + +static struct driver_d davinci_gpio_driver = { + .name = "davinci_gpio", + .probe = davinci_gpio_probe, + .of_compatible = DRV_OF_COMPAT(davinci_gpio_ids), +}; + +static int davinci_gpio_drv_reg(void) +{ + return platform_driver_register(&davinci_gpio_driver); +} +coredevice_initcall(davinci_gpio_drv_reg); diff --git a/include/linux/const.h b/include/linux/const.h new file mode 100644 index 0000000..c872bfd --- /dev/null +++ b/include/linux/const.h @@ -0,0 +1,27 @@ +/* const.h: Macros for dealing with constants. */ + +#ifndef _LINUX_CONST_H +#define _LINUX_CONST_H + +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specifiers unilaterally. We + * use the following macros to deal with this. + * + * Similarly, _AT() will cast an expression with a type in C, but + * leave it unchanged in asm. + */ + +#ifdef __ASSEMBLY__ +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define __AC(X,Y) (X##Y) +#define _AC(X,Y) __AC(X,Y) +#define _AT(T,X) ((T)(X)) +#endif + +#define _BITUL(x) (_AC(1,UL) << (x)) +#define _BITULL(x) (_AC(1,ULL) << (x)) + +#endif /* !(_LINUX_CONST_H) */