diff --git a/.gitignore b/.gitignore index 135fdeb..c2e6e9a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ barebox.map barebox.kwb barebox.kwbuart +barebox.canon-a1100.bin barebox-flash-image System.map Module.symvers diff --git a/Documentation/boards/digic.rst b/Documentation/boards/digic.rst new file mode 100644 index 0000000..e2c49b6 --- /dev/null +++ b/Documentation/boards/digic.rst @@ -0,0 +1,16 @@ +Canon DIGIC +=========== + +Canon PowerShot A1100 IS +------------------------ + +Running barebox on QEMU +^^^^^^^^^^^^^^^^^^^^^^^ + +QEMU supports Canon A1100 camera emulation since version 2.0. + +Usage:: + + $ qemu-system-arm -M canon-a1100 \ + -nographic -monitor null -serial stdio \ + -bios barebox.canon-a1100.bin diff --git a/Makefile b/Makefile index 0791c38..b75e46b 100644 --- a/Makefile +++ b/Makefile @@ -997,7 +997,8 @@ .tmp_kallsyms* common/barebox_default_env* barebox.ldr \ scripts/bareboxenv-target barebox-flash-image \ Doxyfile.version barebox.srec barebox.s5p barebox.ubl \ - barebox.uimage barebox.spi barebox.kwb barebox.kwbuart + barebox.uimage barebox.spi barebox.kwb barebox.kwbuart \ + barebox.canon-a1100.bin # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 usr/include diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8465d4a..2d024dc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -60,6 +60,15 @@ select HAS_DEBUG_LL select GPIOLIB +config ARCH_DIGIC + bool "Canon DIGIC-based cameras" + select CPU_ARM946E + select HAS_DEBUG_LL + select CLOCKSOURCE_DIGIC + select GPIOLIB + help + Support for Canon's digital cameras that use the DIGIC4 chip. + config ARCH_EP93XX bool "Cirrus Logic EP93xx" select CPU_ARM920T @@ -218,6 +227,7 @@ source arch/arm/mach-bcm2835/Kconfig source arch/arm/mach-clps711x/Kconfig source arch/arm/mach-davinci/Kconfig +source arch/arm/mach-digic/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 983f7f5..337aef1 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -55,6 +55,7 @@ machine-$(CONFIG_ARCH_BCM2835) := bcm2835 machine-$(CONFIG_ARCH_CLPS711X) := clps711x machine-$(CONFIG_ARCH_DAVINCI) := davinci +machine-$(CONFIG_ARCH_DIGIC) := digic machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_HIGHBANK) := highbank machine-$(CONFIG_ARCH_IMX) := imx @@ -184,6 +185,16 @@ KBUILD_IMAGE := barebox.zynq endif +quiet_cmd_canon_a1100_image = DD $@ + cmd_canon_a1100_image = scripts/canon-a1100-image $< $@ || \ + echo "WARNING: Couldn't create Canon A1100 image due to previous errors." +barebox.canon-a1100.bin: $(KBUILD_BINARY) FORCE + $(call if_changed,canon_a1100_image) + +ifeq ($(CONFIG_MACH_CANON_A1100),y) +KBUILD_IMAGE := barebox.canon-a1100.bin +endif + KWBIMAGE_OPTS = \ -c -i $(srctree)/$(BOARD)/kwbimage.cfg -d $(TEXT_BASE) -e $(TEXT_BASE) diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index d200512..e195870 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_MACH_AT91SAM9X5EK) += at91sam9x5ek/ obj-$(CONFIG_MACH_BEAGLE) += beagle/ obj-$(CONFIG_MACH_BEAGLEBONE) += beaglebone/ +obj-$(CONFIG_MACH_CANON_A1100) += canon-a1100/ obj-$(CONFIG_MACH_NITROGEN6X) += boundarydevices-nitrogen6x/ obj-$(CONFIG_MACH_CCMX51) += ccxmx51/ obj-$(CONFIG_MACH_CFA10036) += crystalfontz-cfa10036/ diff --git a/arch/arm/boards/canon-a1100/Makefile b/arch/arm/boards/canon-a1100/Makefile new file mode 100644 index 0000000..b08c4a9 --- /dev/null +++ b/arch/arm/boards/canon-a1100/Makefile @@ -0,0 +1 @@ +lwl-y += lowlevel.o diff --git a/arch/arm/boards/canon-a1100/lowlevel.c b/arch/arm/boards/canon-a1100/lowlevel.c new file mode 100644 index 0000000..bbae825 --- /dev/null +++ b/arch/arm/boards/canon-a1100/lowlevel.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + + /* FIXME: can we determine RAM size using CP15 register? + * + * see http://chdk.setepontos.com/index.php?topic=5980.90 + * + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/Bgbcdeca.html + * 4.2.19. c6, MPU memory region programming registers + * + * But the 'cpuinfo' command says that the Protection + * unit is disabled. + * The Control Register value (mrc p15, 0, %0, c0, c1, 4) + * is 0x00051078. + */ + barebox_arm_entry(0x0, SZ_64M, 0); +} diff --git a/arch/arm/configs/canon-a1100_defconfig b/arch/arm/configs/canon-a1100_defconfig new file mode 100644 index 0000000..5c1e195 --- /dev/null +++ b/arch/arm/configs/canon-a1100_defconfig @@ -0,0 +1,56 @@ +CONFIG_BUILTIN_DTB=y +CONFIG_BUILTIN_DTB_NAME="canon-a1100" +CONFIG_ARCH_DIGIC=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_PBL_IMAGE=y +CONFIG_IMAGE_COMPRESSION_LZ4=y +CONFIG_TEXT_BASE=0x00300000 +CONFIG_MALLOC_SIZE=0x200000 +CONFIG_PROMPT="canon-a1100 > " +CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +# CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_DEBUG_LL=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_BOOTM is not set +# CONFIG_CMD_BOOTU is not set +CONFIG_CMD_GO=y +CONFIG_CMD_LOADY=y +# CONFIG_CMD_MOUNT is not set +# CONFIG_CMD_UMOUNT is not set +CONFIG_CMD_EXPORT=y +CONFIG_CMD_GLOBAL=y +CONFIG_CMD_MD5SUM=y +# CONFIG_CMD_PWD is not set +CONFIG_CMD_SHA1SUM=y +CONFIG_CMD_LET=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_SLEEP=y +# CONFIG_CMD_CLEAR is not set +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_MM=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OFTREE=y +CONFIG_OFDEVICE=y +CONFIG_DRIVER_SERIAL_DIGIC=y +# CONFIG_SPI is not set +CONFIG_MTD=y +# CONFIG_MTD_WRITE is not set +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set +CONFIG_CLOCKSOURCE_DUMMY=y +CONFIG_CLOCKSOURCE_DUMMY_RATE=2000 +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_GPIO_OF=y +CONFIG_GPIO_DIGIC=y +CONFIG_ZLIB=y diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig index aed4cb7..fb1a999 100644 --- a/arch/arm/cpu/Kconfig +++ b/arch/arm/cpu/Kconfig @@ -39,6 +39,19 @@ Say Y if you want support for the ARM926T processor. Otherwise, say N. +# ARM946E-S +config CPU_ARM946E + bool + depends on !MMU + select CPU_32v4T + help + ARM946E-S is a member of the ARM9E-S family of high- + performance, 32-bit system-on-chip processor solutions. + The TCM and ARMv5TE 32-bit instruction set is supported. + + Say Y if you want support for the ARM946E-S processor. + Otherwise, say N. + # Feroceon config CPU_FEROCEON bool diff --git a/arch/arm/dts/canon-a1100.dts b/arch/arm/dts/canon-a1100.dts new file mode 100644 index 0000000..a88eacf --- /dev/null +++ b/arch/arm/dts/canon-a1100.dts @@ -0,0 +1,35 @@ +/dts-v1/; + +/include/ "digic4.dtsi" + +/ { + model = "Canon PowerShot A1100 IS"; + compatible = "canon,a1100"; + + memory { + reg = <0x00000000 0x04000000>; + }; + + flash@f8000000 { + compatible = "cfi-flash"; + reg = <0xf8000000 0x08000000>; + }; + + leds { + compatible = "gpio-leds"; + + direct_print { + label = "direct-print (blue)"; + gpios = <&gpio 51 0>; + }; + + auto_focus { + label = "auto-focus (red)"; + gpios = <&gpio 55 0>; + }; + }; +}; + +&timer2 { + status = "okay"; +}; diff --git a/arch/arm/dts/digic4.dtsi b/arch/arm/dts/digic4.dtsi new file mode 100644 index 0000000..21b004d --- /dev/null +++ b/arch/arm/dts/digic4.dtsi @@ -0,0 +1,42 @@ +/include/ "skeleton.dtsi" + +/ { + compatible = "canon,digic4"; + + timer0: timer@c0210000 { + compatible = "canon,digic-timer"; + reg = <0xc0210000 0x1c>; + status = "disabled"; + }; + + timer1: timer@c0210100 { + compatible = "canon,digic-timer"; + reg = <0xc0210100 0x1c>; + status = "disabled"; + }; + + timer2: timer@c0210200 { + compatible = "canon,digic-timer"; + reg = <0xc0210200 0x1c>; + status = "disabled"; + }; + + /* + * I don't know real max GPIO number but this page + * http://magiclantern.wikia.com/wiki/Register_Map#GPIO_Ports + * says about 93 pins on 5DMkIII. + * Assume that DIGIC4 has at least 96 pins. + * So resource size is 96 * 4 = 0x180. + */ + gpio: gpio { + compatible = "canon,digic-gpio"; + reg = <0xc0220000 0x180>; + #gpio-cells = <2>; + gpio-controller; + }; + + uart: uart { + compatible = "canon,digic-uart"; + reg = <0xc0800000 0x1c>; + }; +}; diff --git a/arch/arm/mach-digic/Kconfig b/arch/arm/mach-digic/Kconfig new file mode 100644 index 0000000..d25c3b3 --- /dev/null +++ b/arch/arm/mach-digic/Kconfig @@ -0,0 +1,15 @@ +if ARCH_DIGIC + +choice + prompt "camera type" + +config MACH_CANON_A1100 + bool "Canon PowerShot A1100 IS" + +endchoice + +config ARCH_TEXT_BASE + hex + default 0x00001900 if MACH_CANON_A1100 + +endif diff --git a/arch/arm/mach-digic/Makefile b/arch/arm/mach-digic/Makefile new file mode 100644 index 0000000..820eb10 --- /dev/null +++ b/arch/arm/mach-digic/Makefile @@ -0,0 +1 @@ +obj-y += core.o diff --git a/arch/arm/mach-digic/core.c b/arch/arm/mach-digic/core.c new file mode 100644 index 0000000..b1caec0 --- /dev/null +++ b/arch/arm/mach-digic/core.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 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 + +void __noreturn reset_cpu(unsigned long ignored) +{ + pr_err("%s: unimplemented\n", __func__); + hang(); +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-digic/include/mach/debug_ll.h b/arch/arm/mach-digic/include/mach/debug_ll.h new file mode 100644 index 0000000..721fd44 --- /dev/null +++ b/arch/arm/mach-digic/include/mach/debug_ll.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013, 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. + * + */ + +#ifndef __MACH_DEBUG_LL_H__ +#define __MACH_DEBUG_LL_H__ + +#include +#include +#include + +#define DEBUG_LL_UART DIGIC4_UART + +/* Serial interface registers */ +#define DEBUG_LL_UART_TX (DEBUG_LL_UART + DIGIC_UART_TX) +#define DEBUG_LL_UART_ST (DEBUG_LL_UART + DIGIC_UART_ST) + +static inline void PUTC_LL(char ch) +{ + while (!(readl(DEBUG_LL_UART_ST) & DIGIC_UART_ST_TX_RDY)) + ; /* noop */ + + writel(0x06, DEBUG_LL_UART_ST); + writel(ch, DEBUG_LL_UART_TX); +} + +#endif /* __MACH_DEBUG_LL_H__ */ diff --git a/arch/arm/mach-digic/include/mach/digic4.h b/arch/arm/mach-digic/include/mach/digic4.h new file mode 100644 index 0000000..ffc7979 --- /dev/null +++ b/arch/arm/mach-digic/include/mach/digic4.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2013 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. + * + */ + +#ifndef __DIGIC4_H__ +#define __DIGIC4_H__ + +#define DIGIC4_UART 0xc0800000 + +#endif /* __DIGIC4_H__ */ diff --git a/arch/arm/mach-digic/include/mach/uart.h b/arch/arm/mach-digic/include/mach/uart.h new file mode 100644 index 0000000..043f7cd --- /dev/null +++ b/arch/arm/mach-digic/include/mach/uart.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 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. + * + */ + +#ifndef __DIGIC_UART_H__ +#define __DIGIC_UART_H__ + +/* Serial interface registers offsets */ +#define DIGIC_UART_TX 0x0 +#define DIGIC_UART_RX 0x4 +#define DIGIC_UART_ST 0x14 +# define DIGIC_UART_ST_RX_RDY 1 +# define DIGIC_UART_ST_TX_RDY 2 + +#endif /* __DIGIC_UART_H__ */ diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c1480ce..fc5a389 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -14,6 +14,10 @@ bool depends on ARCH_CLPS711X +config CLOCKSOURCE_DIGIC + bool + depends on ARCH_DIGIC + config CLOCKSOURCE_DUMMY bool "Enable dummy software-only clocksource" help diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 97c0288..b80df6b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o obj-$(CONFIG_CLOCKSOURCE_CLPS711X) += clps711x.o +obj-$(CONFIG_CLOCKSOURCE_DIGIC) += digic.o obj-$(CONFIG_CLOCKSOURCE_DUMMY) += dummy.o obj-$(CONFIG_CLOCKSOURCE_MVEBU) += mvebu.o obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o diff --git a/drivers/clocksource/digic.c b/drivers/clocksource/digic.c new file mode 100644 index 0000000..b80ef6f --- /dev/null +++ b/drivers/clocksource/digic.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013, 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 +#include +#include + +#define DIGIC_TIMER_CLOCK 1000000 + +#define DIGIC_TIMER_CONTROL 0x00 +#define DIGIC_TIMER_VALUE 0x0c + +static void __iomem *timer_base; + +static uint64_t digic_cs_read(void) +{ + return (uint64_t)(0xffff - readl(timer_base + DIGIC_TIMER_VALUE)); +} + +static struct clocksource digic_cs = { + .read = digic_cs_read, + .mask = CLOCKSOURCE_MASK(16), +}; + +static int digic_timer_probe(struct device_d *dev) +{ + /* use only one timer */ + if (timer_base) + return -EBUSY; + + timer_base = dev_request_mem_region(dev, 0); + if (!timer_base) { + dev_err(dev, "could not get memory region\n"); + return -ENODEV; + } + + clocks_calc_mult_shift(&digic_cs.mult, &digic_cs.shift, + DIGIC_TIMER_CLOCK, NSEC_PER_SEC, 1); + + /* disable timer */ + writel(0x80000000, timer_base + DIGIC_TIMER_CONTROL); + + /* magic values... divider? */ + writel(0x00000002, timer_base + 0x04); + writel(0x00000003, timer_base + 0x14); + + /* max counter value */ + writel(0x0000ffff, timer_base + 0x08); + + init_clock(&digic_cs); + + /* enable timer */ + writel(0x00000001, timer_base + DIGIC_TIMER_CONTROL); + /* start timer */ + writel(0x00000001, timer_base + 0x10); + + return 0; +} + +static __maybe_unused struct of_device_id digic_timer_dt_ids[] = { + { + .compatible = "canon,digic-timer", + }, { + /* sentinel */ + } +}; + +static struct driver_d digic_timer_driver = { + .probe = digic_timer_probe, + .name = "digic-timer", + .of_compatible = DRV_OF_COMPAT(digic_timer_dt_ids), +}; + +static int digic_timer_init(void) +{ + return platform_driver_register(&digic_timer_driver); +} +coredevice_initcall(digic_timer_init); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f98a9c0..545c132 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -9,6 +9,10 @@ config GPIO_GENERIC bool +config GPIO_DIGIC + bool "GPIO support for Canon DIGIC" + depends on ARCH_DIGIC + config GPIO_BCM2835 bool "GPIO support for BCM2835" depends on ARCH_BCM2835 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 22d2ac0..045a18c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_GPIO_BCM2835) += gpio-bcm2835.o obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o +obj-$(CONFIG_GPIO_DIGIC) += gpio-digic.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_IMX) += gpio-imx.o obj-$(CONFIG_GPIO_JZ4740) += gpio-jz4740.o diff --git a/drivers/gpio/gpio-digic.c b/drivers/gpio/gpio-digic.c new file mode 100644 index 0000000..468aaa7 --- /dev/null +++ b/drivers/gpio/gpio-digic.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2013 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 +#include +#include +#include +#include + +/* + * See http://magiclantern.wikia.com/wiki/Register_Map#GPIO_Ports + */ + +#define DIGIC_GPIO_IN_LVL 1 +#define DIGIC_GPIO_OUT_LVL 2 +#define DIGIC_GPIO_DIR 4 +#define DIGIC_GPIO_TRISTATE 8 + +struct digic_gpio_chip { + void __iomem *base; + struct gpio_chip gc; +}; + +#define to_digic_gpio_chip(c) container_of(c, struct digic_gpio_chip, gc) + +static inline uint32_t digic_gpio_readl(struct digic_gpio_chip *chip, + uint32_t offset) +{ + return readl(chip->base + 4 * offset); +} + +static inline void digic_gpio_writel(struct digic_gpio_chip *chip, + uint32_t value, uint32_t offset) +{ + writel(value, chip->base + 4 * offset); +} + +static int digic_gpio_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct digic_gpio_chip *chip = to_digic_gpio_chip(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + + return digic_gpio_readl(chip, offset) & DIGIC_GPIO_IN_LVL; +} + +static void digic_gpio_set_value(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct digic_gpio_chip *chip = to_digic_gpio_chip(gc); + uint32_t t; + + if (offset >= gc->ngpio) + return; + + t = digic_gpio_readl(chip, offset); + /* Port direction (1 = OUT, 0 = IN) */ + if (value) + t |= DIGIC_GPIO_OUT_LVL; + else + t &= ~(DIGIC_GPIO_OUT_LVL); + digic_gpio_writel(chip, t, offset); +} + +static int digic_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct digic_gpio_chip *chip = to_digic_gpio_chip(gc); + uint32_t t; + + if (offset >= gc->ngpio) + return -EINVAL; + + t = digic_gpio_readl(chip, offset); + /* Port direction (1 = OUT, 0 = IN) */ + t &= ~(DIGIC_GPIO_DIR); + digic_gpio_writel(chip, t, offset); + + return 0; +} + +static int digic_gpio_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct digic_gpio_chip *chip = to_digic_gpio_chip(gc); + uint32_t t; + + if (offset >= gc->ngpio) + return -EINVAL; + + t = digic_gpio_readl(chip, offset); + /* Port direction (1 = OUT, 0 = IN) */ + t |= DIGIC_GPIO_DIR; + digic_gpio_writel(chip, t, offset); + + digic_gpio_set_value(gc, offset, value); + + return 0; +} + +static struct gpio_ops digic_gpio_ops = { + .direction_input = digic_gpio_direction_input, + .direction_output = digic_gpio_direction_output, + .get = digic_gpio_get_value, + .set = digic_gpio_set_value, +}; + +static int digic_gpio_probe(struct device_d *dev) +{ + struct digic_gpio_chip *chip; + struct resource *res; + resource_size_t rsize; + int ret = -EINVAL; + + chip = xzalloc(sizeof(*chip)); + + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + goto err; + + rsize = resource_size(res); + chip->gc.ngpio = rsize / sizeof(int32_t); + + chip->base = dev_request_mem_region(dev, 0); + chip->gc.ops = &digic_gpio_ops; + chip->gc.base = 0; + + chip->gc.dev = dev; + + ret = gpiochip_add(&chip->gc); + if (ret) { + dev_err(dev, "couldn't add gpiochip, ret = %d\n", ret); + goto err; + } + + dev_info(dev, "probed gpiochip%d with base %d\n", + dev->id, chip->gc.base); + + return 0; + +err: + kfree(chip); + + return ret; +} + +static __maybe_unused struct of_device_id digic_gpio_dt_ids[] = { + { + .compatible = "canon,digic-gpio", + }, { + /* sentinel */ + } +}; + +static struct driver_d digic_gpio_driver = { + .name = "digic-gpio", + .probe = digic_gpio_probe, + .of_compatible = DRV_OF_COMPAT(digic_gpio_dt_ids), +}; + +static int digic_gpio_init(void) +{ + return platform_driver_register(&digic_gpio_driver); +} +coredevice_initcall(digic_gpio_init); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index f51c6e6..aa88331 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -129,4 +129,8 @@ help Say Y here if you have a Cadence serial IP core. +config DRIVER_SERIAL_DIGIC + bool "Canon DIGIC serial driver" + depends on ARCH_DIGIC + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index e1865f7..2d0e98e 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_DRIVER_SERIAL_OMAP4_USBBOOT) += serial_omap4_usbboot.o obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o obj-$(CONFIG_DRIVER_SERIAL_CADENCE) += serial_cadence.o +obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o diff --git a/drivers/serial/serial_digic.c b/drivers/serial/serial_digic.c new file mode 100644 index 0000000..235ea0f --- /dev/null +++ b/drivers/serial/serial_digic.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2013, 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 +#include +#include + +#include + +/* + * This driver is based on the "Serial terminal" docs here: + * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers + * + * See also disassembler output for Canon A1100IS firmware + * (version a1100_100c): + * * a outc-like function can be found at address 0xffff18f0; + * * a getc-like function can be found at address 0xffff192c. + */ + +static inline uint32_t digic_serial_readl(struct console_device *cdev, + uint32_t offset) +{ + void __iomem *base = cdev->dev->priv; + + return readl(base + offset); +} + +static inline void digic_serial_writel(struct console_device *cdev, + uint32_t value, uint32_t offset) +{ + void __iomem *base = cdev->dev->priv; + + writel(value, base + offset); +} + +static int digic_serial_setbaudrate(struct console_device *cdev, int baudrate) +{ + /* I don't know how to setup baudrate :( */ + + return 0; +} + +static void digic_serial_putc(struct console_device *cdev, char c) +{ + uint32_t status; + + do { + status = digic_serial_readl(cdev, DIGIC_UART_ST); + } while (!(status & DIGIC_UART_ST_TX_RDY)); + + digic_serial_writel(cdev, 0x06, DIGIC_UART_ST); + digic_serial_writel(cdev, c, DIGIC_UART_TX); +} + +static int digic_serial_getc(struct console_device *cdev) +{ + uint32_t status; + + do { + status = digic_serial_readl(cdev, DIGIC_UART_ST); + } while (!(status & DIGIC_UART_ST_RX_RDY)); + + digic_serial_writel(cdev, 0x01, DIGIC_UART_ST); + + return digic_serial_readl(cdev, DIGIC_UART_RX); +} + +static int digic_serial_tstc(struct console_device *cdev) +{ + uint32_t status = digic_serial_readl(cdev, DIGIC_UART_ST); + + return ((status & DIGIC_UART_ST_RX_RDY) != 0); + + /* + * Canon folks use additional check, something like this: + * + * if (digic_serial_readl(cdev, DIGIC_UART_ST) & 0x38) { + * digic_serial_writel(cdev, 0x38, DIGIC_UART_ST); + * return 0; + * } + * + * But I know nothing about these magic bits in the status register... + * + */ +} + +static int digic_serial_probe(struct device_d *dev) +{ + struct console_device *cdev; + + cdev = xzalloc(sizeof(struct console_device)); + dev->priv = dev_request_mem_region(dev, 0); + cdev->dev = dev; + cdev->tstc = &digic_serial_tstc; + cdev->putc = &digic_serial_putc; + cdev->getc = &digic_serial_getc; + cdev->setbrg = &digic_serial_setbaudrate; + + console_register(cdev); + + return 0; +} + +static __maybe_unused struct of_device_id digic_serial_dt_ids[] = { + { + .compatible = "canon,digic-uart", + }, { + /* sentinel */ + } +}; + +static struct driver_d digic_serial_driver = { + .name = "digic-uart", + .probe = digic_serial_probe, + .of_compatible = DRV_OF_COMPAT(digic_serial_dt_ids), +}; +console_platform_driver(digic_serial_driver); diff --git a/scripts/canon-a1100-image b/scripts/canon-a1100-image new file mode 100755 index 0000000..6c08d74 --- /dev/null +++ b/scripts/canon-a1100-image @@ -0,0 +1,10 @@ +#!/bin/bash -e + +IFILE=$1 +OFILE=$2 + +dd if=/dev/zero bs=4M count=1 of=$OFILE 2>/dev/null +dd if=$IFILE of=$OFILE conv=notrunc 2>/dev/null + +# 0xffff0000: fe 3f f0 ea b 0xffc00000 +echo -n -e "\xfe\x3f\xf0\xea" | dd of=$OFILE bs=64K seek=63 conv=notrunc 2>/dev/null