diff options
252 files changed, 13346 insertions, 1125 deletions
diff --git a/Documentation/boards.dox b/Documentation/boards.dox index 6bcc14f68c..8d4fabbdd3 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -43,6 +43,7 @@ ARM type: @li @subpage tny-a9263 @li @subpage usb-a9g20-lpw @li @subpage usb-a9263 +@li @subpage virt2real Blackfin type: @@ -58,7 +59,8 @@ MIPS type: @li @subpage dlink_dir_320 @li @subpage loongson_ls1b @li @subpage qemu_malta -@li @subpage rzx50 +@li @subpage ritmix-rzx50 +@li @subpage tplink-mr3020 */ @@ -1,5 +1,5 @@ VERSION = 2014 -PATCHLEVEL = 03 +PATCHLEVEL = 04 SUBLEVEL = 0 EXTRAVERSION = NAME = None diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 21f90121cd..3754646235 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -54,6 +54,12 @@ config ARCH_CLPS711X 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/cpu/Kconfig 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 2bbba35a67..c1bd836d9f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -54,6 +54,7 @@ AFLAGS += -include asm/unified.h -msoft-float $(AFLAGS_THUMB2) 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 0d8c9cf4cf..16742d9138 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -99,4 +99,6 @@ obj-$(CONFIG_MACH_USB_A9263) += usb-a926x/ 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/chumby_falconwing/falconwing.c b/arch/arm/boards/chumby_falconwing/falconwing.c index 2ae902fb60..24dc6e3216 100644 --- a/arch/arm/boards/chumby_falconwing/falconwing.c +++ b/arch/arm/boards/chumby_falconwing/falconwing.c @@ -75,7 +75,6 @@ static struct fb_videomode falconwing_vmode = { .lower_margin = 8, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }; #define MAX_FB_SIZE SZ_1M diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c index 3c87311600..912e13c32c 100644 --- a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c +++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c @@ -76,7 +76,6 @@ static struct fb_videomode imxfb_mode = { .vsync_len = 3, .sync = 0, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }; static void eukrea_cpuimx35_enable_display(int enable) diff --git a/arch/arm/boards/freescale-mx21-ads/imx21ads.c b/arch/arm/boards/freescale-mx21-ads/imx21ads.c index 1bbd8cbf2a..bd7e46e161 100644 --- a/arch/arm/boards/freescale-mx21-ads/imx21ads.c +++ b/arch/arm/boards/freescale-mx21-ads/imx21ads.c @@ -62,7 +62,6 @@ static struct imx_fb_videomode imx_fb_modedata = { .vsync_len = 1, .sync = 0, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, .pcr = 0xfb108bc7, .bpp = 16, diff --git a/arch/arm/boards/freescale-mx28-evk/mx28-evk.c b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c index 3bbdb1d5c9..dce6d31030 100644 --- a/arch/arm/boards/freescale-mx28-evk/mx28-evk.c +++ b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c @@ -201,7 +201,6 @@ static struct fb_videomode mx28_evk_vmodes[] = { .lower_margin = 10, .sync = FB_SYNC_DE_HIGH_ACT | FB_SYNC_CLK_INVERT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, } }; diff --git a/arch/arm/boards/freescale-mx35-3ds/3stack.c b/arch/arm/boards/freescale-mx35-3ds/3stack.c index 2be1554b68..8f821adb73 100644 --- a/arch/arm/boards/freescale-mx35-3ds/3stack.c +++ b/arch/arm/boards/freescale-mx35-3ds/3stack.c @@ -95,7 +95,6 @@ static struct fb_videomode CTP_CLAA070LC0ACW = { .vsync_len = 1, /* note: DE only display */ .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }; static struct imx_ipu_fb_platform_data ipu_fb_data = { diff --git a/arch/arm/boards/freescale-mx53-qsb/board.c b/arch/arm/boards/freescale-mx53-qsb/board.c index 74826e4a5e..38d1ee6f7c 100644 --- a/arch/arm/boards/freescale-mx53-qsb/board.c +++ b/arch/arm/boards/freescale-mx53-qsb/board.c @@ -99,6 +99,7 @@ static int loco_late_init(void) rev = readl(MX53_IIM_BASE_ADDR + 0x878); set_board_rev(rev); printf("MCIMX53-START-R board 1.0 rev %c\n", (rev == 1) ? 'A' : 'B' ); + barebox_set_hostname("loco-r"); armlinux_set_revision(loco_system_rev); /* Set VDDGP to 1.25V for 1GHz on SW1 */ mc13xxx_reg_read(mc34708, MC13892_REG_SW_0, &val); @@ -146,8 +147,8 @@ static int loco_late_init(void) } else { /* so we have a DA9053 based board */ printf("MCIMX53-START board 1.0\n"); + barebox_set_hostname("loco"); armlinux_set_revision(loco_system_rev); - return 0; } /* USB PWR enable */ diff --git a/arch/arm/boards/freescale-mx53-qsb/env/config-board b/arch/arm/boards/freescale-mx53-qsb/env/config-board index a6cf69ddbc..e8e8378f53 100644 --- a/arch/arm/boards/freescale-mx53-qsb/env/config-board +++ b/arch/arm/boards/freescale-mx53-qsb/env/config-board @@ -3,5 +3,4 @@ # board defaults, do not change in running system. Change /env/config # instead -global.hostname=loco global.linux.bootargs.base="console=ttymxc0,115200" diff --git a/arch/arm/boards/freescale-mx6-sabrelite/board.c b/arch/arm/boards/freescale-mx6-sabrelite/board.c index 85c61510fa..f42489f765 100644 --- a/arch/arm/boards/freescale-mx6-sabrelite/board.c +++ b/arch/arm/boards/freescale-mx6-sabrelite/board.c @@ -78,8 +78,48 @@ static int ksz9021rn_phy_fixup(struct phy_device *dev) return 0; } +static struct gpio fec_gpios[] = { + { + .gpio = 87, + .flags = GPIOF_OUT_INIT_LOW, + .label = "phy-rst", + }, { + .gpio = 190, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-addr2", + }, { + .gpio = 23, + .flags = GPIOF_OUT_INIT_LOW, + .label = "phy-led-mode", + }, { + /* MODE strap-in pins: advertise all capabilities */ + .gpio = 185, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-adv1", + }, { + .gpio = 187, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-adv1", + }, { + .gpio = 188, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-adv1", + }, { + .gpio = 189, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-adv1", + }, { + /* Enable 125 MHz clock output */ + .gpio = 184, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "phy-125MHz", + }, +}; + static int sabrelite_ksz9021rn_setup(void) { + int ret; + if (!of_machine_is_compatible("fsl,imx6q-sabrelite") && !of_machine_is_compatible("fsl,imx6dl-sabrelite")) return 0; @@ -87,24 +127,16 @@ static int sabrelite_ksz9021rn_setup(void) mxc_iomux_v3_setup_multiple_pads(sabrelite_enet_gpio_pads, ARRAY_SIZE(sabrelite_enet_gpio_pads)); - gpio_direction_output(87, 0); /* GPIO 3-23 */ - - gpio_direction_output(190, 1); /* GPIO 6-30: PHYAD2 */ - - /* LED-Mode: Tri-Color Dual LED Mode */ - gpio_direction_output(23 , 0); /* GPIO 1-23 */ - - /* MODE strap-in pins: advertise all capabilities */ - gpio_direction_output(185, 1); /* GPIO 6-25 */ - gpio_direction_output(187, 1); /* GPIO 6-27 */ - gpio_direction_output(188, 1); /* GPIO 6-28*/ - gpio_direction_output(189, 1); /* GPIO 6-29 */ - - /* Enable 125 MHz clock output */ - gpio_direction_output(184, 1); /* GPIO 6-24 */ + ret = gpio_request_array(fec_gpios, ARRAY_SIZE(fec_gpios)); + if (ret) { + pr_err("Failed to request fec gpios: %s\n", strerror(-ret)); + return ret; + } mdelay(10); - gpio_set_value(87, 1); + + /* FEC driver picks up the reset gpio later and releases the phy reset */ + gpio_free_array(fec_gpios, ARRAY_SIZE(fec_gpios)); return 0; } diff --git a/arch/arm/boards/friendlyarm-mini2440/mini2440.c b/arch/arm/boards/friendlyarm-mini2440/mini2440.c index 2c2426016d..86e22ad131 100644 --- a/arch/arm/boards/friendlyarm-mini2440/mini2440.c +++ b/arch/arm/boards/friendlyarm-mini2440/mini2440.c @@ -85,7 +85,6 @@ static struct fb_videomode s3c24x0_fb_modes[] = { .pixclock = 115913, .sync = FB_SYNC_USE_PWREN, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, #endif #ifdef CONFIG_MINI2440_VIDEO_A70 diff --git a/arch/arm/boards/guf-cupid/board.c b/arch/arm/boards/guf-cupid/board.c index e171331a44..127edaa170 100644 --- a/arch/arm/boards/guf-cupid/board.c +++ b/arch/arm/boards/guf-cupid/board.c @@ -68,7 +68,6 @@ static struct fb_videomode guf_cupid_fb_mode = { .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_CLK_INVERT | FB_SYNC_OE_ACT_HIGH, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }; #define GPIO_LCD_ENABLE (2 * 32 + 24) diff --git a/arch/arm/boards/karo-tx28/tx28-stk5.c b/arch/arm/boards/karo-tx28/tx28-stk5.c index 57cb0c3907..2aaceb442e 100644 --- a/arch/arm/boards/karo-tx28/tx28-stk5.c +++ b/arch/arm/boards/karo-tx28/tx28-stk5.c @@ -72,7 +72,6 @@ static struct fb_videomode tx28evk_vmodes[] = { .lower_margin = 10, .sync = FB_SYNC_DE_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, { /* * Emerging ETV570 640 x 480 display (directly connected) @@ -93,7 +92,6 @@ static struct fb_videomode tx28evk_vmodes[] = { .lower_margin = 10, .sync = FB_SYNC_DE_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, /* * This display is connected: * display side -> CPU side @@ -127,7 +125,6 @@ static struct fb_videomode tx28evk_vmodes[] = { .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_DE_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, { /* * Modeline "1024x768" x 60.0 @@ -149,7 +146,6 @@ static struct fb_videomode tx28evk_vmodes[] = { .lower_margin = 3, .sync = FB_SYNC_DE_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, { /* * Modeline "1280x1024" x 60.0 @@ -172,7 +168,6 @@ static struct fb_videomode tx28evk_vmodes[] = { .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_DE_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, }; diff --git a/arch/arm/boards/phytec-phycore-imx35/pcm043.c b/arch/arm/boards/phytec-phycore-imx35/pcm043.c index 46821a784a..c1928cc8ff 100644 --- a/arch/arm/boards/phytec-phycore-imx35/pcm043.c +++ b/arch/arm/boards/phytec-phycore-imx35/pcm043.c @@ -73,7 +73,6 @@ static struct fb_videomode pcm043_fb_mode[] = { .vsync_len = 1, .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, }, { /* 240x320 @ 60 Hz */ .name = "Sharp-LQ035Q7", @@ -90,7 +89,6 @@ static struct fb_videomode pcm043_fb_mode[] = { .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | \ FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, } }; diff --git a/arch/arm/boards/phytec-phyflex-imx6/Makefile b/arch/arm/boards/phytec-phyflex-imx6/Makefile index 93e73081c2..01c7a259e9 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/Makefile +++ b/arch/arm/boards/phytec-phyflex-imx6/Makefile @@ -1,5 +1,2 @@ obj-y += board.o -obj-y += flash-header-phytec-pfla02-1gib.dcd.o flash-header-phytec-pfla02-2gib.dcd.o -extra-y += flash-header-phytec-pfla02-1gib.dcd.S flash-header-phytec-pfla02-2gib.dcd.S -extra-y += flash-header-phytec-pfla02-1gib.dcd flash-header-phytec-pfla02-2gib.dcd lwl-y += lowlevel.o diff --git a/arch/arm/boards/phytec-phyflex-imx6/board.c b/arch/arm/boards/phytec-phyflex-imx6/board.c index e9bd1680fd..c11f4c46ba 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/board.c +++ b/arch/arm/boards/phytec-phyflex-imx6/board.c @@ -21,6 +21,10 @@ #include <gpio.h> #include <init.h> #include <of.h> +#include <mach/bbu.h> +#include <fec.h> + +#include <linux/micrel_phy.h> #include <mach/imx6.h> @@ -36,12 +40,33 @@ static int eth_phy_reset(void) return 0; } +static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val) +{ + phy_write(dev, 0x0d, device); + phy_write(dev, 0x0e, reg); + phy_write(dev, 0x0d, (1 << 14) | device); + phy_write(dev, 0x0e, val); +} + +static int ksz9031rn_phy_fixup(struct phy_device *dev) +{ + mmd_write_reg(dev, 2, 8, 0x039F); + + return 0; +} + static int phytec_pfla02_init(void) { - if (!of_machine_is_compatible("phytec,imx6q-pfla02")) + if (!of_machine_is_compatible("phytec,imx6q-pfla02") && + !of_machine_is_compatible("phytec,imx6dl-pfla02") && + !of_machine_is_compatible("phytec,imx6s-pfla02")) return 0; eth_phy_reset(); + phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK, + ksz9031rn_phy_fixup); + + imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT); return 0; } @@ -49,7 +74,7 @@ device_initcall(phytec_pfla02_init); static int phytec_pfla02_core_init(void) { - if (!of_machine_is_compatible("phytec,imx6q-pfla02")) + if (!of_machine_is_compatible("phytec,imx6x-pbab01")) return 0; imx6_init_lowlevel(); diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-1gib.imxcfg b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-1gib.imxcfg index 524ebca580..d73207c364 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-1gib.imxcfg +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-1gib.imxcfg @@ -1,5 +1,5 @@ -#define SETUP_1GIB_2GIB \ +#define SETUP_1GIB_2GIB_4GIB \ wm 32 0x021b0040 0x00000017; \ wm 32 0x021b0000 0xc21a0000 diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-2gib.imxcfg b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-2gib.imxcfg index bf6e0ab26b..2291b71e8c 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-2gib.imxcfg +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-2gib.imxcfg @@ -1,5 +1,5 @@ -#define SETUP_1GIB_2GIB \ +#define SETUP_1GIB_2GIB_4GIB \ wm 32 0x021b0040 0x00000027; \ wm 32 0x021b0000 0xC31A0000 diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-4gib.imxcfg b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-4gib.imxcfg new file mode 100644 index 0000000000..c6dc775d8f --- /dev/null +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02-4gib.imxcfg @@ -0,0 +1,6 @@ + +#define SETUP_1GIB_2GIB_4GIB \ + wm 32 0x021b0040 0x00000047; \ + wm 32 0x021b0000 0xC41A0000 + +#include "flash-header-phytec-pfla02.h" diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02.h b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02.h index b90f7cb3cf..138ae36ee3 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02.h +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02.h @@ -60,7 +60,7 @@ wm 32 0x021b0030 0x005b0e21 wm 32 0x021b0008 0x09444040 wm 32 0x021b0004 0x00025576 -SETUP_1GIB_2GIB +SETUP_1GIB_2GIB_4GIB wm 32 0x021b001c 0x04088032 wm 32 0x021b001c 0x0408803a diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg new file mode 100644 index 0000000000..e5a729223f --- /dev/null +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg @@ -0,0 +1,6 @@ + +#define SETUP_S_DL_512MB_1GB \ + wm 32 0x021b0040 0x00000017; \ + wm 32 0x021b0000 0xc21a0000 + +#include "flash-header-phytec-pfla02dl.h" diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl.h b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl.h new file mode 100644 index 0000000000..0f83bc9964 --- /dev/null +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02dl.h @@ -0,0 +1,95 @@ +soc imx6 +loadaddr 0x20000000 +dcdofs 0x400 + +wm 32 0x020e04bc 0x00000030 +wm 32 0x020e04c0 0x00000030 +wm 32 0x020e04c4 0x00000030 +wm 32 0x020e04c8 0x00000030 +wm 32 0x020e04cc 0x00000030 +wm 32 0x020e04d0 0x00000030 +wm 32 0x020e04d4 0x00000030 +wm 32 0x020e04d8 0x00000030 +wm 32 0x020e0470 0x00020030 +wm 32 0x020e0474 0x00020030 +wm 32 0x020e0478 0x00020030 +wm 32 0x020e047c 0x00020030 +wm 32 0x020e0480 0x00020030 +wm 32 0x020e0484 0x00020030 +wm 32 0x020e0488 0x00020030 +wm 32 0x020e048c 0x00020030 +wm 32 0x020e0464 0x00020030 +wm 32 0x020e0490 0x00020030 +wm 32 0x020e04ac 0x00020030 +wm 32 0x020e04b0 0x00020030 +wm 32 0x020e0494 0x00020030 +wm 32 0x020e04a4 0x00003000 +wm 32 0x020e04a8 0x00003000 +wm 32 0x020e04a0 0x00000000 +wm 32 0x020e04b4 0x00003030 +wm 32 0x020e04b8 0x00003030 +wm 32 0x020e0764 0x00000030 +wm 32 0x020e0770 0x00000030 +wm 32 0x020e0778 0x00000030 +wm 32 0x020e077c 0x00000030 +wm 32 0x020e0780 0x00000030 +wm 32 0x020e0784 0x00000030 +wm 32 0x020e078c 0x00000030 +wm 32 0x020e0748 0x00000030 +wm 32 0x020e074c 0x00000030 +wm 32 0x020e0750 0x00020000 +wm 32 0x020e0754 0x00000000 +wm 32 0x020e0760 0x00020000 +wm 32 0x020e076c 0x00000030 +wm 32 0x020e0774 0x000c0000 +wm 32 0x021b081c 0x33333333 +wm 32 0x021b0820 0x33333333 +wm 32 0x021b0824 0x33333333 +wm 32 0x021b0828 0x33333333 +wm 32 0x021b481c 0x33333333 +wm 32 0x021b4820 0x33333333 +wm 32 0x021b4824 0x33333333 +wm 32 0x021b4828 0x33333333 +wm 32 0x021b0018 0x00081740 +wm 32 0x021b001c 0x00008000 +wm 32 0x021b000c 0x555a7975 +wm 32 0x021b0010 0xff538e64 +wm 32 0x021b0014 0x01ff00db +wm 32 0x021b002c 0x000026d2 +wm 32 0x021b0030 0x005b0e21 +wm 32 0x021b0008 0x09444040 +wm 32 0x021b0004 0x00025576 + +SETUP_S_DL_512MB_1GB + +wm 32 0x021b001c 0x04088032 +wm 32 0x021b001c 0x0408803a +wm 32 0x021b001c 0x00008033 +wm 32 0x021b001c 0x0000803b +wm 32 0x021b001c 0x00428031 +wm 32 0x021b001c 0x00428039 +wm 32 0x021b001c 0x09408030 +wm 32 0x021b001c 0x09408038 +wm 32 0x021b001c 0x04008040 +wm 32 0x021b001c 0x04008048 +wm 32 0x021b0800 0xa1380003 +wm 32 0x021b4800 0xa1380003 +wm 32 0x021b0020 0x00005800 +wm 32 0x021b0818 0x00011117 +wm 32 0x021b4818 0x00011117 +wm 32 0x021b083c 0x422D0230 +wm 32 0x021b0840 0x022F022E +wm 32 0x021b483c 0x4237023D +wm 32 0x021b4840 0x02340224 +wm 32 0x021b0848 0x38333135 +wm 32 0x021b4848 0x36353338 +wm 32 0x021b0850 0x2E2E332C +wm 32 0x021b4850 0x3727382F +wm 32 0x021b080c 0x000C000D +wm 32 0x021b0810 0x0018001A +wm 32 0x021b480c 0x00270023 +wm 32 0x021b4810 0x002F002D +wm 32 0x021b08b8 0x00000800 +wm 32 0x021b48b8 0x00000800 +wm 32 0x021b001c 0x00000000 +wm 32 0x021b0404 0x00011006 diff --git a/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02s-512mb.imxcfg b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02s-512mb.imxcfg new file mode 100644 index 0000000000..3116e3613d --- /dev/null +++ b/arch/arm/boards/phytec-phyflex-imx6/flash-header-phytec-pfla02s-512mb.imxcfg @@ -0,0 +1,6 @@ + +#define SETUP_S_DL_512MB_1GB \ + wm 32 0x021b0040 0x00000017; \ + wm 32 0x021b0000 0x83190000 + +#include "flash-header-phytec-pfla02dl.h" diff --git a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c index 6422bc4dcb..fb7b186d21 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c +++ b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c @@ -54,6 +54,8 @@ static inline void setup_uart(void) } extern char __dtb_imx6q_phytec_pbab01_start[]; +extern char __dtb_imx6dl_phytec_pbab01_start[]; +extern char __dtb_imx6s_phytec_pbab01_start[]; ENTRY_FUNCTION(start_phytec_pbab01_1gib, r0, r1, r2) { @@ -86,3 +88,48 @@ ENTRY_FUNCTION(start_phytec_pbab01_2gib, r0, r1, r2) barebox_arm_entry(0x10000000, SZ_2G, fdt); } + +ENTRY_FUNCTION(start_phytec_pbab01_4gib, r0, r1, r2) +{ + uint32_t fdt; + + __barebox_arm_head(); + + arm_cpu_lowlevel_init(); + + arm_setup_stack(0x00920000 - 8); + + fdt = (uint32_t)__dtb_imx6q_phytec_pbab01_start - get_runtime_offset(); + + barebox_arm_entry(0x10000000, 0xEFFFFFF8, fdt); +} + +ENTRY_FUNCTION(start_phytec_pbab01dl_1gib, r0, r1, r2) +{ + uint32_t fdt; + + __barebox_arm_head(); + + arm_cpu_lowlevel_init(); + + arm_setup_stack(0x00920000 - 8); + + fdt = (uint32_t)__dtb_imx6dl_phytec_pbab01_start - get_runtime_offset(); + + barebox_arm_entry(0x10000000, SZ_1G, fdt); +} + +ENTRY_FUNCTION(start_phytec_pbab01s_512mb, r0, r1, r2) +{ + uint32_t fdt; + + __barebox_arm_head(); + + arm_cpu_lowlevel_init(); + + arm_setup_stack(0x00920000 - 8); + + fdt = (uint32_t)__dtb_imx6s_phytec_pbab01_start - get_runtime_offset(); + + barebox_arm_entry(0x10000000, SZ_512M, fdt); +} diff --git a/arch/arm/boards/variscite-mx6/Makefile b/arch/arm/boards/variscite-mx6/Makefile new file mode 100644 index 0000000000..35b114b8dd --- /dev/null +++ b/arch/arm/boards/variscite-mx6/Makefile @@ -0,0 +1,3 @@ +obj-y += board.o flash-header-variscite.dcd.o +extra-y += flash-header-variscite.dcd.S flash-header-variscite.dcd +lwl-y += lowlevel.o diff --git a/arch/arm/boards/variscite-mx6/board.c b/arch/arm/boards/variscite-mx6/board.c new file mode 100644 index 0000000000..592b1116e7 --- /dev/null +++ b/arch/arm/boards/variscite-mx6/board.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Michael Burkey + * Based on code (C) Sascha Hauer, Pengutronix + * Based on code (C) Variscite, Ltd. + * + * 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. + * + */ + +#define pr_fmt(fmt) "var-som-mx6: " fmt + +#include <common.h> +#include <gpio.h> +#include <init.h> +#include <of.h> +#include <debug_ll.h> + +#include <environment.h> +#include <asm/armlinux.h> +#include <generated/mach-types.h> +#include <partition.h> +#include <asm/io.h> +#include <asm/mmu.h> +#include <mach/generic.h> +#include <sizes.h> +#include <mach/imx6.h> +#include <mach/devices-imx6.h> +#include <mach/iomux-mx6.h> +#include <spi/spi.h> +#include <mach/spi.h> +#include <i2c/i2c.h> + +#define ETH_PHY_RST IMX_GPIO_NR(1, 25) + +static int setup_pmic_voltages(void) +{ + unsigned char value, rev_id = 0 ; + struct i2c_adapter *adapter = NULL; + struct i2c_client client; + int addr = -1, ret, bus = 0; + + /* I2C2 bus (2-1 = 1 in barebox numbering) */ + bus = 1; + + /* PFUZE100 device address is 0x08 */ + addr = 0x08; + + adapter = i2c_get_adapter(bus); + if (!adapter) { + pr_err("i2c bus %d not found\n", bus); + return -ENODEV; + } + + client.adapter = adapter; + client.addr = addr; + + /* Attempt to locate the PFUZE100 chip. */ + if (i2c_read_reg(&client, 0x00, &value, 1) != 1) { + pr_err("Read device ID error!\n"); + return -1; + } + if (i2c_read_reg(&client, 0x03, &rev_id, 1) != 1) { + pr_err("Read Rev ID error!\n"); + return -1; + } + + pr_info("Found PFUZE100! deviceid=%x,revid=%x\n", value, rev_id); + + /* Set Gigabit Ethernet voltage (SOM v1.1/1.0)*/ + value = 0x60; + ret = i2c_write_reg(&client, 0x4a, &value, 1); + + /* set VGEN3 to 2.5V */ + value = 0x77; + if (i2c_write_reg(&client, 0x6e, &value, 1) != 1) { + pr_err("Set VGEN3 error!\n"); + return -EIO; + } + + return 0; +} + +static int eth_phy_reset(void) +{ + gpio_request(ETH_PHY_RST, "phy reset"); + gpio_direction_output(ETH_PHY_RST, 0); + mdelay(1); + gpio_set_value(ETH_PHY_RST, 1); + + return 0; +} + +static int variscite_custom_init(void) +{ + if (!of_machine_is_compatible("variscite,imx6q-custom")) + return 0; + + barebox_set_hostname("var-som-mx6"); + + setup_pmic_voltages(); + + eth_phy_reset(); + + armlinux_set_architecture(MACH_TYPE_VAR_SOM_MX6); + + pr_debug("Completing custom_init()\n"); + + return 0; +} +device_initcall(variscite_custom_init); + +static int variscite_custom_core_init(void) +{ + if (!of_machine_is_compatible("variscite,imx6q-custom")) + return 0; + + imx6_init_lowlevel(); + + pr_debug("Completing custom_core_init()\n"); + + return 0; +} +postcore_initcall(variscite_custom_core_init); diff --git a/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg b/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg new file mode 100644 index 0000000000..ed2105792e --- /dev/null +++ b/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg @@ -0,0 +1,86 @@ +loadaddr 0x10000000 +soc imx6 +dcdofs 0x400 +wm 32 0x020e0798 0x000C0000 +wm 32 0x020e0758 0x00000000 +wm 32 0x020e0588 0x00000030 +wm 32 0x020e0594 0x00000030 +wm 32 0x020e056c 0x00000030 +wm 32 0x020e0578 0x00000030 +wm 32 0x020e074c 0x00000030 +wm 32 0x020e057c 0x00000030 +wm 32 0x020e058c 0x00000000 +wm 32 0x020e059c 0x00000030 +wm 32 0x020e05a0 0x00000030 +wm 32 0x020e078c 0x00000030 +wm 32 0x020e0750 0x00020000 +wm 32 0x020e05a8 0x00000030 +wm 32 0x020e05b0 0x00000030 +wm 32 0x020e0524 0x00000030 +wm 32 0x020e051c 0x00000030 +wm 32 0x020e0518 0x00000030 +wm 32 0x020e050c 0x00000030 +wm 32 0x020e05b8 0x00000030 +wm 32 0x020e05c0 0x00000030 +wm 32 0x020e0774 0x00020000 +wm 32 0x020e0784 0x00000030 +wm 32 0x020e0788 0x00000030 +wm 32 0x020e0794 0x00000030 +wm 32 0x020e079c 0x00000030 +wm 32 0x020e07a0 0x00000030 +wm 32 0x020e07a4 0x00000030 +wm 32 0x020e07a8 0x00000030 +wm 32 0x020e0748 0x00000030 +wm 32 0x020e05ac 0x00000030 +wm 32 0x020e05b4 0x00000030 +wm 32 0x020e0528 0x00000030 +wm 32 0x020e0520 0x00000030 +wm 32 0x020e0514 0x00000030 +wm 32 0x020e0510 0x00000030 +wm 32 0x020e05bc 0x00000030 +wm 32 0x020e05c4 0x00000030 +wm 32 0x021b0800 0xA1390003 +wm 32 0x021b080c 0x001F001F +wm 32 0x021b0810 0x001F001F +wm 32 0x021b480c 0x001F001F +wm 32 0x021b4810 0x001F001F +wm 32 0x021b083c 0x4333033F +wm 32 0x021b0840 0x032C031D +wm 32 0x021b483c 0x43200332 +wm 32 0x021b4840 0x031A026A +wm 32 0x021b0848 0x4D464746 +wm 32 0x021b4848 0x47453F4D +wm 32 0x021b0850 0x3E434440 +wm 32 0x021b4850 0x47384839 +wm 32 0x021b081c 0x33333333 +wm 32 0x021b0820 0x33333333 +wm 32 0x021b0824 0x33333333 +wm 32 0x021b0828 0x33333333 +wm 32 0x021b481c 0x33333333 +wm 32 0x021b4820 0x33333333 +wm 32 0x021b4824 0x33333333 +wm 32 0x021b4828 0x33333333 +wm 32 0x021b08b8 0x00000800 +wm 32 0x021b48b8 0x00000800 +wm 32 0x021b0004 0x00020036 +wm 32 0x021b0008 0x09444040 +wm 32 0x021b000c 0x555A7975 +wm 32 0x021b0010 0xFF538F64 +wm 32 0x021b0014 0x01FF00DB +wm 32 0x021b0018 0x00001740 +wm 32 0x021b001c 0x00008000 +wm 32 0x021b002c 0x000026D2 +wm 32 0x021b0030 0x005A1023 +wm 32 0x021b0040 0x00000027 +wm 32 0x021b0000 0x831A0000 +wm 32 0x021b001c 0x04088032 +wm 32 0x021b001c 0x00008033 +wm 32 0x021b001c 0x00048031 +wm 32 0x021b001c 0x09408030 +wm 32 0x021b001c 0x04008040 +wm 32 0x021b0020 0x00005800 +wm 32 0x021b0818 0x00011117 +wm 32 0x021b4818 0x00011117 +wm 32 0x021b0004 0x00025576 +wm 32 0x021b0404 0x00011006 +wm 32 0x021b001c 0x00000000 diff --git a/arch/arm/boards/variscite-mx6/lowlevel.c b/arch/arm/boards/variscite-mx6/lowlevel.c new file mode 100644 index 0000000000..e93e87484c --- /dev/null +++ b/arch/arm/boards/variscite-mx6/lowlevel.c @@ -0,0 +1,74 @@ +/* + * + * Copyright (C) 2013 Michael Burkey + * Based on code by Sascha Hauer <s.hauer@pengutronix.de> + * + * 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. + * + */ +#include <debug_ll.h> +#include <common.h> +#include <sizes.h> +#include <io.h> +#include <asm/barebox-arm-head.h> +#include <asm/barebox-arm.h> +#include <asm/sections.h> +#include <asm/cache.h> +#include <asm/mmu.h> +#include <mach/imx6-mmdc.h> +#include <mach/imx6.h> + +static inline void setup_uart(void) +{ + void __iomem *ccmbase = (void *)MX6_CCM_BASE_ADDR; + void __iomem *uartbase = (void *)MX6_UART1_BASE_ADDR; + void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; + + writel(0x03, iomuxbase + 0x0280); + writel(0x03, iomuxbase + 0x0284); + + writel(0xffffffff, ccmbase + 0x68); + writel(0xffffffff, ccmbase + 0x6c); + writel(0xffffffff, ccmbase + 0x70); + writel(0xffffffff, ccmbase + 0x74); + writel(0xffffffff, ccmbase + 0x78); + writel(0xffffffff, ccmbase + 0x7c); + writel(0xffffffff, ccmbase + 0x80); + + writel(0x00000000, uartbase + 0x80); + writel(0x00004027, uartbase + 0x84); + writel(0x00000704, uartbase + 0x88); + writel(0x00000a81, uartbase + 0x90); + writel(0x0000002b, uartbase + 0x9c); + writel(0x00013880, uartbase + 0xb0); + writel(0x0000047f, uartbase + 0xa4); + writel(0x0000c34f, uartbase + 0xa8); + writel(0x00000001, uartbase + 0x80); + + putc_ll('>'); +} +extern char __dtb_imx6q_var_custom_start[]; + +ENTRY_FUNCTION(start_variscite_custom, r0, r1, r2) +{ + uint32_t fdt; + + arm_cpu_lowlevel_init(); + + arm_setup_stack(0x00920000 - 8); + + if (IS_ENABLED(CONFIG_DEBUG_LL)) + setup_uart(); + + fdt = (uint32_t)__dtb_imx6q_var_custom_start - get_runtime_offset(); + + barebox_arm_entry(0x10000000, SZ_1G, fdt); +} diff --git a/arch/arm/boards/virt2real/Makefile b/arch/arm/boards/virt2real/Makefile new file mode 100644 index 0000000000..b2f44bba1b --- /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 0000000000..b7f72171bb --- /dev/null +++ b/arch/arm/boards/virt2real/board.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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 <common.h> +#include <init.h> + +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 0000000000..3c90d78678 --- /dev/null +++ b/arch/arm/boards/virt2real/lowlevel.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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 <common.h> +#include <asm/barebox-arm.h> +#include <asm/barebox-arm-head.h> +#include <init.h> +#include <sizes.h> + +#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 0000000000..fc383216ec --- /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/freescale-mx53-qsb_defconfig b/arch/arm/configs/freescale-mx53-qsb_defconfig index afe8b72c0d..8365234ea1 100644 --- a/arch/arm/configs/freescale-mx53-qsb_defconfig +++ b/arch/arm/configs/freescale-mx53-qsb_defconfig @@ -16,6 +16,7 @@ CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +CONFIG_BLSPEC=y CONFIG_CONSOLE_ACTIVATE_NONE=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx53-qsb/env/" @@ -25,31 +26,44 @@ CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y CONFIG_CMD_MSLEEP=y CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_LET=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_PASSWD=y +CONFIG_PASSWD_MODE_STAR=y CONFIG_CMD_TIME=y CONFIG_CMD_LN=y CONFIG_CMD_TFTP=y CONFIG_CMD_FILETYPE=y CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y CONFIG_CMD_MEMINFO=y CONFIG_CMD_IOMEM=y +CONFIG_CMD_MM=y CONFIG_CMD_CRC=y CONFIG_CMD_CRC_CMP=y CONFIG_CMD_MD5SUM=y +CONFIG_CMD_SHA1SUM=y +CONFIG_CMD_SHA256SUM=y +CONFIG_CMD_SHA224SUM=y CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_BOOTM_VERBOSE=y CONFIG_CMD_BOOTM_INITRD=y CONFIG_CMD_BOOTM_OFTREE=y CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_BOOTM_AIMAGE=y CONFIG_CMD_UIMAGE=y -# CONFIG_CMD_BOOTU is not set +CONFIG_CMD_BOOTZ=y CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_OFTREE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_MEMTEST=y CONFIG_CMD_BAREBOX_UPDATE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y @@ -64,23 +78,36 @@ CONFIG_CMD_DETECT=y CONFIG_CMD_WD=y CONFIG_NET=y CONFIG_NET_DHCP=y +CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_NETCONSOLE=y +CONFIG_NET_RESOLV=y CONFIG_OFDEVICE=y CONFIG_SMSC_PHY=y CONFIG_DRIVER_NET_FEC_IMX=y +CONFIG_NET_USB=y +CONFIG_NET_USB_ASIX=y +CONFIG_NET_USB_SMSC95XX=y # CONFIG_SPI is not set CONFIG_I2C=y CONFIG_I2C_IMX=y -CONFIG_DISK_ATA=y +CONFIG_DISK_AHCI=y +CONFIG_DISK_AHCI_IMX=y CONFIG_USB=y +CONFIG_USB_IMX_CHIPIDEA=y CONFIG_USB_EHCI=y +CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y CONFIG_MCI=y CONFIG_MCI_IMX_ESDHC=y CONFIG_MFD_MC13XXX=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_GPIO_OF=y +CONFIG_LED_TRIGGERS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_IMX=y +CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y CONFIG_FS_FAT=y diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index e821061cf3..f29c968da6 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -12,9 +12,11 @@ CONFIG_MACH_REALQ7=y CONFIG_MACH_GK802=y CONFIG_MACH_TQMA6X=y CONFIG_MACH_SABRELITE=y +CONFIG_MACH_SABRESD=y CONFIG_MACH_NITROGEN6X=y CONFIG_MACH_SOLIDRUN_HUMMINGBOARD=y CONFIG_MACH_UDOO=y +CONFIG_MACH_VARISCITE_MX6=y CONFIG_IMX_IIM=y CONFIG_IMX_IIM_FUSE_BLOW=y CONFIG_IMX_OCOTP=y @@ -41,9 +43,11 @@ CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y CONFIG_CMD_MSLEEP=y CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_READF=y CONFIG_CMD_LET=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y @@ -72,6 +76,7 @@ CONFIG_CMD_OFTREE=y CONFIG_CMD_OF_PROPERTY=y CONFIG_CMD_OF_NODE=y CONFIG_CMD_MEMTEST=y +CONFIG_CMD_SPLASH=y CONFIG_CMD_BAREBOX_UPDATE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y @@ -94,8 +99,8 @@ CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y CONFIG_OFDEVICE=y CONFIG_OF_BAREBOX_DRIVERS=y -CONFIG_AT803X_PHY=y CONFIG_DRIVER_NET_FEC_IMX=y +CONFIG_AT803X_PHY=y CONFIG_NET_USB=y CONFIG_NET_USB_ASIX=y CONFIG_NET_USB_SMSC95XX=y @@ -107,6 +112,13 @@ CONFIG_MTD_RAW_DEVICE=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y +CONFIG_NAND=y +CONFIG_NAND_ALLOW_ERASE_BAD=y +CONFIG_NAND_IMX=y +CONFIG_NAND_IMX_BBM=y +CONFIG_NAND_MXS=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_FASTMAP=y CONFIG_DISK_AHCI=y CONFIG_DISK_AHCI_IMX=y CONFIG_DISK_INTF_PLATFORM_IDE=y @@ -118,6 +130,12 @@ CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DFU=y +CONFIG_VIDEO=y +CONFIG_DRIVER_VIDEO_IMX_IPUV3=y +CONFIG_DRIVER_VIDEO_IMX_IPUV3_LVDS=y +CONFIG_DRIVER_VIDEO_IMX_IPUV3_HDMI=y +CONFIG_DRIVER_VIDEO_SIMPLEFB=y +CONFIG_DRIVER_VIDEO_EDID=y CONFIG_MCI=y CONFIG_MCI_MMC_BOOT_PARTITIONS=y CONFIG_MCI_IMX_ESDHC=y @@ -133,6 +151,9 @@ CONFIG_EEPROM_AT24=y CONFIG_KEYBOARD_GPIO=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_IMX=y +CONFIG_PWM=y +CONFIG_PWM_IMX=y +CONFIG_MXS_APBH_DMA=y CONFIG_GPIO_STMPE=y CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y @@ -140,4 +161,5 @@ CONFIG_FS_NFS=y CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_FS_FAT_LFN=y -CONFIG_LZO_DECOMPRESS=y +CONFIG_FS_UBIFS=y +CONFIG_FS_UBIFS_COMPRESSION_LZO=y diff --git a/arch/arm/configs/panda_defconfig b/arch/arm/configs/panda_defconfig index 7be86ac85f..c42140a447 100644 --- a/arch/arm/configs/panda_defconfig +++ b/arch/arm/configs/panda_defconfig @@ -1,5 +1,5 @@ CONFIG_ARCH_OMAP=y -CONFIG_ARCH_OMAP4=y +CONFIG_MACH_PANDA=y CONFIG_THUMB2_BAREBOX=y CONFIG_CMD_ARM_MMUINFO=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y @@ -29,9 +29,7 @@ CONFIG_CMD_READLINE=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y CONFIG_CMD_TIME=y -CONFIG_CMD_DIRNAME=y CONFIG_CMD_LN=y -CONFIG_CMD_READLINK=y CONFIG_CMD_TFTP=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y diff --git a/arch/arm/configs/panda_xload_defconfig b/arch/arm/configs/panda_xload_defconfig index 5cedcffdcc..29a2afda8d 100644 --- a/arch/arm/configs/panda_xload_defconfig +++ b/arch/arm/configs/panda_xload_defconfig @@ -1,7 +1,7 @@ CONFIG_ARCH_OMAP=y -CONFIG_ARCH_OMAP4=y # CONFIG_OMAP_GPMC is not set CONFIG_OMAP_BUILD_IFT=y +CONFIG_MACH_PANDA=y CONFIG_THUMB2_BAREBOX=y # CONFIG_CMD_ARM_CPUINFO is not set CONFIG_MMU=y diff --git a/arch/arm/configs/phytec-phycore-imx35_defconfig b/arch/arm/configs/phytec-phycore-imx35_defconfig index 59c1b82135..6674015a6d 100644 --- a/arch/arm/configs/phytec-phycore-imx35_defconfig +++ b/arch/arm/configs/phytec-phycore-imx35_defconfig @@ -1,8 +1,6 @@ CONFIG_ARCH_IMX=y CONFIG_CACHE_L2X0=y -CONFIG_ARCH_IMX_EXTERNAL_BOOT=y CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND=y -CONFIG_ARCH_IMX35=y CONFIG_MACH_PCM043=y CONFIG_IMX_IIM=y CONFIG_IMX_IIM_FUSE_BLOW=y @@ -20,7 +18,6 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y CONFIG_PARTITION=y -CONFIG_PARTITION_DISK=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/phytec-phycore-imx35/env" CONFIG_RESET_SOURCE=y @@ -28,16 +25,16 @@ CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y CONFIG_CMD_MSLEEP=y CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_READF=y CONFIG_CMD_LET=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y CONFIG_CMD_TIME=y -CONFIG_CMD_DIRNAME=y CONFIG_CMD_LN=y -CONFIG_CMD_READLINK=y CONFIG_CMD_TFTP=y CONFIG_CMD_FILETYPE=y CONFIG_CMD_ECHO_E=y @@ -57,9 +54,9 @@ CONFIG_CMD_UIMAGE=y CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_OFTREE=y -CONFIG_CMD_OFTREE_PROBE=y CONFIG_CMD_OF_PROPERTY=y CONFIG_CMD_OF_NODE=y +CONFIG_CMD_BAREBOX_UPDATE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_MAGICVAR=y @@ -68,6 +65,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_CMD_MIITOOL=y CONFIG_CMD_CLK=y +CONFIG_CMD_DETECT=y CONFIG_CMD_WD=y CONFIG_NET=y CONFIG_NET_DHCP=y @@ -76,12 +74,11 @@ CONFIG_NET_PING=y CONFIG_NET_NETCONSOLE=y CONFIG_DRIVER_NET_FEC_IMX=y # CONFIG_SPI is not set +CONFIG_MTD=y CONFIG_DRIVER_CFI=y CONFIG_CFI_BUFFER_WRITE=y -CONFIG_MTD=y CONFIG_NAND=y CONFIG_NAND_IMX=y -CONFIG_UBI=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_IMX=y CONFIG_FS_TFTP=y diff --git a/arch/arm/configs/virt2real_defconfig b/arch/arm/configs/virt2real_defconfig new file mode 100644 index 0000000000..a81d18b25b --- /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/Makefile b/arch/arm/dts/Makefile index 6bac3b908f..b45c174582 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -3,8 +3,7 @@ dtb-$(CONFIG_ARCH_AM33XX) += \ am335x-boneblack.dtb \ am335x-phytec-phycore.dtb dtb-$(CONFIG_ARCH_IMX25) += imx25-karo-tx25.dtb -dtb-$(CONFIG_ARCH_IMX27) += imx27-phytec-phycard-s-rdk.dtb \ - imx27-phytec-phycard-s-som.dtb +dtb-$(CONFIG_ARCH_IMX27) += imx27-phytec-phycard-s-rdk-bb.dtb dtb-$(CONFIG_ARCH_IMX51) += imx51-babbage.dtb \ imx51-genesi-efika-sb.dtb dtb-$(CONFIG_ARCH_IMX53) += imx53-mba53.dtb \ @@ -20,12 +19,15 @@ dtb-$(CONFIG_ARCH_IMX6) += imx6q-gk802.dtb \ imx6q-sabresd.dtb \ imx6dl-mba6x.dtb \ imx6q-mba6x.dtb \ + imx6dl-phytec-pbab01.dtb \ imx6q-phytec-pbab01.dtb \ + imx6s-phytec-pbab01.dtb \ imx6dl-hummingboard.dtb \ imx6q-guf-santaro.dtb \ imx6q-nitrogen6x.dtb \ imx6dl-nitrogen6x.dtb \ - imx6q-udoo.dtb + imx6q-udoo.dtb \ + imx6q-var-custom.dtb dtb-$(CONFIG_ARCH_MVEBU) += dove-cubox-bb.dtb dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5_sockit.dtb \ socfpga_cyclone5_socrates.dtb @@ -43,7 +45,7 @@ pbl-$(CONFIG_MACH_FREESCALE_MX53_LOCO) += imx53-qsb.dtb.o imx53-qsrb.dtb.o pbl-$(CONFIG_MACH_FREESCALE_MX53_VMX53) += imx53-voipac-bsb.dtb.o pbl-$(CONFIG_MACH_DFI_FS700_M60) += imx6q-dfi-fs700-m60-6q.dtb.o imx6dl-dfi-fs700-m60-6s.dtb.o pbl-$(CONFIG_MACH_PCM051) += am335x-phytec-phycore.dtb.o -pbl-$(CONFIG_MACH_PHYTEC_PFLA02) += imx6q-phytec-pbab01.dtb.o +pbl-$(CONFIG_MACH_PHYTEC_PFLA02) += imx6s-phytec-pbab01.dtb.o imx6dl-phytec-pbab01.dtb.o imx6q-phytec-pbab01.dtb.o pbl-$(CONFIG_MACH_REALQ7) += imx6q-dmo-edmqmx6.dtb.o pbl-$(CONFIG_MACH_SOLIDRUN_CUBOX) += dove-cubox-bb.dtb.o pbl-$(CONFIG_MACH_GK802) += imx6q-gk802.dtb.o @@ -60,6 +62,7 @@ pbl-$(CONFIG_MACH_SABRESD) += imx6q-sabresd.dtb.o pbl-$(CONFIG_MACH_GUF_SANTARO) += imx6q-guf-santaro.dtb.o pbl-$(CONFIG_MACH_NITROGEN6X) += imx6q-nitrogen6x.dtb.o imx6dl-nitrogen6x.dtb.o pbl-$(CONFIG_MACH_UDOO) += imx6q-udoo.dtb.o +pbl-$(CONFIG_MACH_VARISCITE_MX6) += imx6q-var-custom.dtb.o .SECONDARY: $(obj)/$(BUILTIN_DTB).dtb.S .SECONDARY: $(patsubst %,$(obj)/%.S,$(dtb-y)) diff --git a/arch/arm/dts/dm365.dtsi b/arch/arm/dts/dm365.dtsi new file mode 100644 index 0000000000..ea69007fa8 --- /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/imx27-phytec-phycard-s-rdk-bb.dts b/arch/arm/dts/imx27-phytec-phycard-s-rdk-bb.dts new file mode 100644 index 0000000000..cecfc5a827 --- /dev/null +++ b/arch/arm/dts/imx27-phytec-phycard-s-rdk-bb.dts @@ -0,0 +1,38 @@ +/* + * Barebox specific DT overlay for Phytec PCA100 RDK + */ + +#include "imx27-phytec-phycard-s-rdk.dts" + +/ { + chosen { + linux,stdout-path = &uart1; + + environment@0 { + compatible = "barebox,environment"; + device-path = &nfc, "partname:environment"; + }; + }; +}; + +&nfc { + partition@0 { + label = "boot"; + reg = <0x0 0x80000>; + }; + + partition@1 { + label = "environment"; + reg = <0x80000 0x80000>; + }; + + partition@2 { + label = "kernel"; + reg = <0x100000 0x400000>; + }; + + partition@3 { + label = "root"; + reg = <0x500000 0x7b00000>; + }; +}; diff --git a/arch/arm/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/dts/imx27-phytec-phycard-s-rdk.dts index fb2b874805..3c3964a996 100644 --- a/arch/arm/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/dts/imx27-phytec-phycard-s-rdk.dts @@ -9,7 +9,7 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include "imx27-phytec-phycard-s-som.dts" +#include "imx27-phytec-phycard-s-som.dtsi" / { model = "Phytec pca100 rapid development kit"; @@ -76,35 +76,54 @@ &iomuxc { imx27-phycard-s-rdk { pinctrl_i2c1: i2c1grp { - fsl,pins = <MX27_I2C2_PINGRP1>; + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; }; pinctrl_owire1: owire1grp { - fsl,pins = <MX27_OWIRE1_PINGRP1>; + fsl,pins = < + MX27_PAD_RTCK__OWIRE 0x0 + >; }; pinctrl_sdhc2: sdhc2grp { - fsl,pins = <MX27_SDHC2_PINGRP1>; + fsl,pins = < + MX27_PAD_SD2_CLK__SD2_CLK 0x0 + MX27_PAD_SD2_CMD__SD2_CMD 0x0 + MX27_PAD_SD2_D0__SD2_D0 0x0 + MX27_PAD_SD2_D1__SD2_D1 0x0 + MX27_PAD_SD2_D2__SD2_D2 0x0 + MX27_PAD_SD2_D3__SD2_D3 0x0 + MX27_PAD_SSI3_RXDAT__GPIO3_29 0x0 /* CD */ + >; }; pinctrl_uart1: uart1grp { fsl,pins = < - MX27_UART1_PINGRP1 - MX27_UART1_RTSCTS_PINGRP1 + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + MX27_PAD_UART1_CTS__UART1_CTS 0x0 + MX27_PAD_UART1_RTS__UART1_RTS 0x0 >; }; pinctrl_uart2: uart2grp { fsl,pins = < - MX27_UART2_PINGRP1 - MX27_UART2_RTSCTS_PINGRP1 + MX27_PAD_UART2_TXD__UART2_TXD 0x0 + MX27_PAD_UART2_RXD__UART2_RXD 0x0 + MX27_PAD_UART2_CTS__UART2_CTS 0x0 + MX27_PAD_UART2_RTS__UART2_RTS 0x0 >; }; pinctrl_uart3: uart3grp { fsl,pins = < - MX27_UART3_PINGRP1 - MX27_UART3_RTSCTS_PINGRP1 + MX27_PAD_UART3_TXD__UART3_TXD 0x0 + MX27_PAD_UART3_RXD__UART3_RXD 0x0 + MX27_PAD_UART3_CTS__UART3_CTS 0x0 + MX27_PAD_UART3_RTS__UART3_RTS 0x0 >; }; }; diff --git a/arch/arm/dts/imx27-phytec-phycard-s-som.dts b/arch/arm/dts/imx27-phytec-phycard-s-som.dtsi index a48d4e178d..1b62480796 100644 --- a/arch/arm/dts/imx27-phytec-phycard-s-som.dts +++ b/arch/arm/dts/imx27-phytec-phycard-s-som.dtsi @@ -17,15 +17,6 @@ model = "Phytec pca100"; compatible = "phytec,imx27-pca100", "fsl,imx27"; - chosen { - linux,stdout-path = &uart1; - - environment@0 { - compatible = "barebox,environment"; - device-path = &nfc, "partname:environment"; - }; - }; - memory { reg = <0xa0000000 0x08000000>; /* 128MB */ }; @@ -38,22 +29,6 @@ status = "okay"; }; -&iomuxc { - imx27-phycard-s-som { - pinctrl_fec1: fec1grp { - fsl,pins = <MX27_FEC1_PINGRP1>; - }; - - pinctrl_i2c2: i2c2grp { - fsl,pins = <MX27_I2C2_PINGRP1>; - }; - - pinctrl_nfc: nfcgrp { - fsl,pins = <MX27_NFC_PINGRP1>; - }; - }; -}; - &fec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; @@ -72,6 +47,52 @@ }; }; +&iomuxc { + imx27-phycard-s-som { + pinctrl_fec1: fec1grp { + fsl,pins = < + MX27_PAD_SD3_CMD__FEC_TXD0 0x0 + MX27_PAD_SD3_CLK__FEC_TXD1 0x0 + MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 + MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 + MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 + MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 + MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 + MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 + MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 + MX27_PAD_ATA_DATA7__FEC_MDC 0x0 + MX27_PAD_ATA_DATA8__FEC_CRS 0x0 + MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 + MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 + MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 + MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 + MX27_PAD_ATA_DATA13__FEC_COL 0x0 + MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 + MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; + }; + + pinctrl_nfc: nfcgrp { + fsl,pins = < + MX27_PAD_NFRB__NFRB 0x0 + MX27_PAD_NFCLE__NFCLE 0x0 + MX27_PAD_NFWP_B__NFWP_B 0x0 + MX27_PAD_NFCE_B__NFCE_B 0x0 + MX27_PAD_NFALE__NFALE 0x0 + MX27_PAD_NFRE_B__NFRE_B 0x0 + MX27_PAD_NFWE_B__NFWE_B 0x0 + >; + }; + }; +}; + &nfc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nfc>; @@ -79,24 +100,4 @@ nand-ecc-mode = "hw"; nand-on-flash-bbt; status = "okay"; - - partition@0 { - label = "boot"; - reg = <0x0 0x80000>; - }; - - partition@1 { - label = "environment"; - reg = <0x80000 0x80000>; - }; - - partition@2 { - label = "kernel"; - reg = <0x100000 0x400000>; - }; - - partition@3 { - label = "root"; - reg = <0x500000 0x7b00000>; - }; }; diff --git a/arch/arm/dts/imx27-pingrp.h b/arch/arm/dts/imx27-pingrp.h deleted file mode 100644 index 57ca02f89d..0000000000 --- a/arch/arm/dts/imx27-pingrp.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2013 Markus Pargmann <mpa@pengutronix.de>, Pengutronix - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ -#ifndef __DTS_IMX27_PINGRP_H -#define __DTS_IMX27_PINGRP_H - -#include "imx27-pinfunc.h" - -#define MX27_CSPI1_PINGRP1 \ - MX27_PAD_CSPI1_MISO__CSPI1_MISO 0x0 \ - MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x0 \ - MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x0 - -#define MX27_CSPI2_PINGRP1 \ - MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x0 \ - MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x0 \ - MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x0 - -#define MX27_CSPI3_PINGRP1 \ - MX27_PAD_SD1_CLK__CSPI3_SCLK 0x0 \ - MX27_PAD_SD1_D0__CSPI3_MISO 0x0 \ - MX27_PAD_SD1_CMD__CSPI3_MOSI 0x0 - -#define MX27_FB_PINGRP1 \ - MX27_PAD_CLS__CLS 0x0 \ - MX27_PAD_CONTRAST__CONTRAST 0x0 \ - MX27_PAD_LD0__LD0 0x0 \ - MX27_PAD_LD1__LD1 0x0 \ - MX27_PAD_LD2__LD2 0x0 \ - MX27_PAD_LD3__LD3 0x0 \ - MX27_PAD_LD4__LD4 0x0 \ - MX27_PAD_LD5__LD5 0x0 \ - MX27_PAD_LD6__LD6 0x0 \ - MX27_PAD_LD7__LD7 0x0 \ - MX27_PAD_LD8__LD8 0x0 \ - MX27_PAD_LD9__LD9 0x0 \ - MX27_PAD_LD10__LD10 0x0 \ - MX27_PAD_LD11__LD11 0x0 \ - MX27_PAD_LD12__LD12 0x0 \ - MX27_PAD_LD13__LD13 0x0 \ - MX27_PAD_LD14__LD14 0x0 \ - MX27_PAD_LD15__LD15 0x0 \ - MX27_PAD_LD16__LD16 0x0 \ - MX27_PAD_LD17__LD17 0x0 \ - MX27_PAD_LSCLK__LSCLK 0x0 \ - MX27_PAD_OE_ACD__OE_ACD 0x0 \ - MX27_PAD_PS__PS 0x0 \ - MX27_PAD_REV__REV 0x0 \ - MX27_PAD_SPL_SPR__SPL_SPR 0x0 \ - MX27_PAD_HSYNC__HSYNC 0x0 \ - MX27_PAD_VSYNC__VSYNC 0x0 - -#define MX27_FEC1_PINGRP1 \ - MX27_PAD_SD3_CMD__FEC_TXD0 0x0 \ - MX27_PAD_SD3_CLK__FEC_TXD1 0x0 \ - MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 \ - MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 \ - MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 \ - MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 \ - MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 \ - MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 \ - MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 \ - MX27_PAD_ATA_DATA7__FEC_MDC 0x0 \ - MX27_PAD_ATA_DATA8__FEC_CRS 0x0 \ - MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 \ - MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 \ - MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 \ - MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 \ - MX27_PAD_ATA_DATA13__FEC_COL 0x0 \ - MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 \ - MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 - -#define MX27_I2C1_PINGRP1 \ - MX27_PAD_I2C_DATA__I2C_DATA 0x0 \ - MX27_PAD_I2C_CLK__I2C_CLK 0x0 - -#define MX27_I2C2_PINGRP1 \ - MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 \ - MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 - -#define MX27_NFC_PINGRP1 \ - MX27_PAD_NFRB__NFRB 0x0 \ - MX27_PAD_NFCLE__NFCLE 0x0 \ - MX27_PAD_NFWP_B__NFWP_B 0x0 \ - MX27_PAD_NFCE_B__NFCE_B 0x0 \ - MX27_PAD_NFALE__NFALE 0x0 \ - MX27_PAD_NFRE_B__NFRE_B 0x0 \ - MX27_PAD_NFWE_B__NFWE_B 0x0 - -#define MX27_OWIRE1_PINGRP1 \ - MX27_PAD_RTCK__OWIRE 0x0 - -#define MX27_PWM_PINGRP1 \ - MX27_PAD_PWMO__PWMO 0x0 - -#define MX27_SDHC1_PINGRP1 \ - MX27_PAD_SD1_CLK__SD1_CLK 0x0 \ - MX27_PAD_SD1_CMD__SD1_CMD 0x0 \ - MX27_PAD_SD1_D0__SD1_D0 0x0 \ - MX27_PAD_SD1_D1__SD1_D1 0x0 \ - MX27_PAD_SD1_D2__SD1_D2 0x0 \ - MX27_PAD_SD1_D3__SD1_D3 0x0 - -#define MX27_SDHC2_PINGRP1 \ - MX27_PAD_SD2_CLK__SD2_CLK 0x0 \ - MX27_PAD_SD2_CMD__SD2_CMD 0x0 \ - MX27_PAD_SD2_D0__SD2_D0 0x0 \ - MX27_PAD_SD2_D1__SD2_D1 0x0 \ - MX27_PAD_SD2_D2__SD2_D2 0x0 \ - MX27_PAD_SD2_D3__SD2_D3 0x0 - -#define MX27_SDHC3_PINGRP1 \ - MX27_PAD_SD3_CLK__SD3_CLK 0x0 \ - MX27_PAD_SD3_CMD__SD3_CMD 0x0 \ - MX27_PAD_SD3_D0__SD3_D0 0x0 \ - MX27_PAD_SD3_D1__SD3_D1 0x0 \ - MX27_PAD_SD3_D2__SD3_D2 0x0 \ - MX27_PAD_SD3_D3__SD3_D3 0x0 - -#define MX27_UART1_PINGRP1 \ - MX27_PAD_UART1_TXD__UART1_TXD 0x0 \ - MX27_PAD_UART1_RXD__UART1_RXD 0x0 - -#define MX27_UART1_RTSCTS_PINGRP1 \ - MX27_PAD_UART1_CTS__UART1_CTS 0x0 \ - MX27_PAD_UART1_RTS__UART1_RTS 0x0 - -#define MX27_UART2_PINGRP1 \ - MX27_PAD_UART2_TXD__UART2_TXD 0x0 \ - MX27_PAD_UART2_RXD__UART2_RXD 0x0 - -#define MX27_UART2_RTSCTS_PINGRP1 \ - MX27_PAD_UART2_CTS__UART2_CTS 0x0 \ - MX27_PAD_UART2_RTS__UART2_RTS 0x0 - -#define MX27_UART3_PINGRP1 \ - MX27_PAD_UART3_TXD__UART3_TXD 0x0 \ - MX27_PAD_UART3_RXD__UART3_RXD 0x0 - -#define MX27_UART3_RTSCTS_PINGRP1 \ - MX27_PAD_UART3_CTS__UART3_CTS 0x0 \ - MX27_PAD_UART3_RTS__UART3_RTS 0x0 - -#endif /* __DTS_IMX27_PINGRP_H */ diff --git a/arch/arm/dts/imx27.dtsi b/arch/arm/dts/imx27.dtsi index 7e98966b18..83a8247325 100644 --- a/arch/arm/dts/imx27.dtsi +++ b/arch/arm/dts/imx27.dtsi @@ -10,12 +10,13 @@ */ #include "skeleton.dtsi" -#include "imx27-pingrp.h" +#include "imx27-pinfunc.h" #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/gpio/gpio.h> / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -70,6 +71,26 @@ }; }; + usbphy { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usbphy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + clocks = <&clks 75>; + clock-names = "main_clk"; + }; + + usbphy2: usbphy@2 { + compatible = "usb-nop-xceiv"; + reg = <2>; + clocks = <&clks 75>; + clock-names = "main_clk"; + }; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -439,6 +460,42 @@ iram = <&iram>; }; + usbotg: usb@10024000 { + compatible = "fsl,imx27-usb"; + reg = <0x10024000 0x200>; + interrupts = <56>; + clocks = <&clks 15>; + fsl,usbmisc = <&usbmisc 0>; + fsl,usbphy = <&usbphy0>; + status = "disabled"; + }; + + usbh1: usb@10024200 { + compatible = "fsl,imx27-usb"; + reg = <0x10024200 0x200>; + interrupts = <54>; + clocks = <&clks 15>; + fsl,usbmisc = <&usbmisc 1>; + status = "disabled"; + }; + + usbh2: usb@10024400 { + compatible = "fsl,imx27-usb"; + reg = <0x10024400 0x200>; + interrupts = <55>; + clocks = <&clks 15>; + fsl,usbmisc = <&usbmisc 2>; + fsl,usbphy = <&usbphy2>; + status = "disabled"; + }; + + usbmisc: usbmisc@10024600 { + #index-cells = <1>; + compatible = "fsl,imx27-usbmisc"; + reg = <0x10024600 0x200>; + clocks = <&clks 62>; + }; + sahara2: sahara@10025000 { compatible = "fsl,imx27-sahara"; reg = <0x10025000 0x1000>; diff --git a/arch/arm/dts/imx53-qsb-common.dtsi b/arch/arm/dts/imx53-qsb-common.dtsi index 571da92ad3..9aa0f083ff 100644 --- a/arch/arm/dts/imx53-qsb-common.dtsi +++ b/arch/arm/dts/imx53-qsb-common.dtsi @@ -230,3 +230,7 @@ &sata { status = "okay"; }; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/dts/imx53.dtsi b/arch/arm/dts/imx53.dtsi index 91659b8ca1..d6cdcafe76 100644 --- a/arch/arm/dts/imx53.dtsi +++ b/arch/arm/dts/imx53.dtsi @@ -79,15 +79,15 @@ compatible = "fsl,imx53-ahci"; reg = <0x10000000 0x1000>; interrupts = <28>; - clocks = <&clks 173>, <&clks 5>, <&clks 188>; - clock-names = "sata", "ahb", "per"; + clocks = <&clks 173>, <&clks 188>, <&clks 5>; + clock-names = "sata_gate", "sata_ref", "ahb"; status = "disabled"; }; ipu: ipu@18000000 { #crtc-cells = <1>; compatible = "fsl,imx53-ipu"; - reg = <0x18000000 0x080000000>; + reg = <0x18000000 0x08000000>; interrupts = <11 10>; clocks = <&clks 59>, <&clks 110>, <&clks 61>; clock-names = "bus", "di0", "di1"; diff --git a/arch/arm/dts/imx6dl-phytec-pbab01.dts b/arch/arm/dts/imx6dl-phytec-pbab01.dts new file mode 100644 index 0000000000..0e90c47768 --- /dev/null +++ b/arch/arm/dts/imx6dl-phytec-pbab01.dts @@ -0,0 +1,29 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; + +#include "imx6dl-phytec-pfla02.dtsi" +#include "imx6qdl-phytec-pbab01.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 Duallite Carrier-Board"; + compatible = "phytec,imx6x-pbab01", "phytec,imx6dl-pfla02", "fsl,imx6dl"; + + chosen { + linux,stdout-path = &uart4; + + environment@0 { + compatible = "barebox,environment"; + device-path = &flash, "partname:barebox-environment"; + }; + }; +}; diff --git a/arch/arm/dts/imx6dl-phytec-pfla02.dtsi b/arch/arm/dts/imx6dl-phytec-pfla02.dtsi new file mode 100644 index 0000000000..fa3a49aa3c --- /dev/null +++ b/arch/arm/dts/imx6dl-phytec-pfla02.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx6dl.dtsi" +#include "imx6qdl-phytec-pfla02.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 Dual Lite"; + compatible = "phytec,imx6dl-pfla02", "fsl,imx6dl"; + + memory { + reg = <0x10000000 0x40000000>; + }; +}; + +&ecspi3 { + status = "okay"; +}; + +&flash { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0x80000>; + }; + + partition@1 { + label = "barebox-environment"; + reg = <0x80000 0x10000>; + }; +}; diff --git a/arch/arm/dts/imx6q-phytec-pbab01.dts b/arch/arm/dts/imx6q-phytec-pbab01.dts index b35b2e5c30..26046e01c3 100644 --- a/arch/arm/dts/imx6q-phytec-pbab01.dts +++ b/arch/arm/dts/imx6q-phytec-pbab01.dts @@ -11,10 +11,11 @@ /dts-v1/; #include "imx6q-phytec-pfla02.dtsi" +#include "imx6qdl-phytec-pbab01.dtsi" / { model = "Phytec phyFLEX-i.MX6 Quad Carrier-Board"; - compatible = "phytec,imx6q-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q"; + compatible = "phytec,imx6x-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q"; chosen { linux,stdout-path = &uart4; @@ -25,23 +26,3 @@ }; }; }; - -&fec { - status = "okay"; -}; - -&uart1 { - status = "okay"; -}; - -&uart4 { - status = "okay"; -}; - -&usdhc2 { - status = "okay"; -}; - -&usdhc3 { - status = "okay"; -}; diff --git a/arch/arm/dts/imx6q-phytec-pfla02.dtsi b/arch/arm/dts/imx6q-phytec-pfla02.dtsi index 402eee804d..781a90ae9d 100644 --- a/arch/arm/dts/imx6q-phytec-pfla02.dtsi +++ b/arch/arm/dts/imx6q-phytec-pfla02.dtsi @@ -10,9 +10,10 @@ */ #include "imx6q.dtsi" +#include "imx6qdl-phytec-pfla02.dtsi" / { - model = "Phytec phyFLEX-i.MX6 Ouad"; + model = "Phytec phyFLEX-i.MX6 Quad"; compatible = "phytec,imx6q-pfla02", "fsl,imx6q"; memory { @@ -21,165 +22,7 @@ }; &ecspi3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi3>; status = "okay"; - fsl,spi-num-chipselects = <1>; - cs-gpios = <&gpio4 24 0>; - - flash: m25p80@0 { - compatible = "m25p80"; - spi-max-frequency = <20000000>; - reg = <0>; - }; -}; - -&i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - - eeprom@50 { - compatible = "atmel,24c32"; - reg = <0x50>; - }; - - pmic@58 { - compatible = "dialog,da9063"; - reg = <0x58>; - interrupt-parent = <&gpio4>; - interrupts = <17 0x8>; /* active-low GPIO4_17 */ - - regulators { - vddcore_reg: bcore1 { - regulator-min-microvolt = <730000>; - regulator-max-microvolt = <1380000>; - regulator-always-on; - }; - - vddsoc_reg: bcore2 { - regulator-min-microvolt = <730000>; - regulator-max-microvolt = <1380000>; - regulator-always-on; - }; - - vdd_ddr3_reg: bpro { - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - regulator-always-on; - }; - - vdd_3v3_reg: bperi { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_buckmem_reg: bmem { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_eth_reg: bio { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-always-on; - }; - - vdd_eth_io_reg: ldo4 { - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; - - vdd_mx6_snvs_reg: ldo5 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; - }; - - vdd_3v3_pmic_io_reg: ldo6 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_sd0_reg: ldo9 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_sd1_reg: ldo10 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_mx6_high_reg: ldo11 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; - }; - }; - }; -}; - -&iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx6q-phytec-pfla02 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ - MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ - >; - }; - - pinctrl_ecspi3: ecspi3grp { - fsl,pins = <MX6QDL_ECSPI3_PINGRP1>; - }; - - pinctrl_enet: enetgrp { - fsl,pins = <MX6QDL_ENET_PINGRP3>; - }; - - pinctrl_gpmi_nand: gpmigrp { - fsl,pins = <MX6QDL_GPMI_NAND_PINGRP1>; - }; - - pinctrl_i2c1: i2c1grp { - fsl,pins = <MX6QDL_I2C1_PINGRP1>; - }; - - pinctrl_uart4: uart4grp { - fsl,pins = <MX6QDL_UART4_PINGRP1>; - }; - - pinctrl_usdhc2: usdhc2grp { - fsl,pins = <MX6QDL_USDHC2_PINGRP_D4>; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = <MX6QDL_USDHC3_PINGRP_D4>; - }; - - pinctrl_usdhc3_cdwp: usdhc3cdwp { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 - >; - }; - }; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet>; - phy-mode = "rgmii"; - phy-reset-gpios = <&gpio3 23 0>; - status = "disabled"; }; &flash { @@ -196,49 +39,3 @@ reg = <0x80000 0x10000>; }; }; - -&gpmi { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpmi_nand>; - nand-on-flash-bbt; - status = "okay"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "barebox"; - reg = <0x0 0x200000>; - }; - - partition@1 { - label = "ubi"; - reg = <0x200000 0x3fe00000>; - }; -}; - -&ocotp { - barebox,provide-mac-address = <&fec 0x620>; -}; - -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4>; - status = "disabled"; -}; - -&usdhc2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc2>; - cd-gpios = <&gpio1 4 0>; - wp-gpios = <&gpio1 2 0>; - status = "disabled"; -}; - -&usdhc3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3 - &pinctrl_usdhc3_cdwp>; - cd-gpios = <&gpio1 27 0>; - wp-gpios = <&gpio1 29 0>; - status = "disabled"; -}; diff --git a/arch/arm/dts/imx6q-var-custom.dts b/arch/arm/dts/imx6q-var-custom.dts new file mode 100644 index 0000000000..bb1193f9a4 --- /dev/null +++ b/arch/arm/dts/imx6q-var-custom.dts @@ -0,0 +1,149 @@ +/* + * Copyright 2013 Michael Burkey + * Based on code written by Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * + * environment@0 { + compatible = "barebox,environment"; + device-path = &usdhc2, "partname:barebox-environment"; + }; + + * + */ + +/dts-v1/; +#include "imx6q-var-som.dtsi" + +/ { + model = "Variscite i.MX6 Quad Custom Carrier-Board"; + compatible = "variscite,imx6q-custom", "variscite,imx6q-som", "fsl,imx6q"; + + chosen { + linux,stdout-path = &uart1; + + environment@0 { + compatible = "barebox,environment"; + device-path = &gpmi, "partname:barebox-environment"; + }; + + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-variscite-custom { + pinctrl_i2c1: i2c1grp { + fsl,pins = <MX6QDL_I2C1_PINGRP1>; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = <MX6QDL_I2C3_PINGRP3>; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = <MX6QDL_USDHC2_PINGRP_D4>; + }; + + pinctrl_usdhc2_cd: usdhc2cd { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x80000000 + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = <MX6QDL_UART1_PINGRP1>; + }; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + status = "okay"; + display-timings { + native-mode = &claawvga; + claawvga: claawvga { + native-mode; + clock-frequency = <35714000>; + hactive = <800>; + vactive = <480>; + hback-porch = <28>; + hfront-porch = <17>; + vback-porch = <13>; + vfront-porch = <20>; + hsync-len = <20>; + vsync-len = <13>; + }; + }; + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +&usdhc2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio4 14 0>; + wp-gpios = <&gpio4 15 0>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0x200000>; + }; + + partition@1 { + label = "barebox-environment"; + reg = <0x200000 0x20000>; + }; + + partition@2 { + label = "kernel"; + reg = <0x220000 0x600000>; + }; + + partition@3 { + label = "rootfs"; + reg = <0x820000 0x18000000>; + }; +}; + +&usbh1 { + status = "okay"; + disable-over-current; + dr_mode = "host"; + phy_type = "utmi"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; +}; + +&i2c3 { + status = "okay"; + clock-frequency = <1000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; +}; diff --git a/arch/arm/dts/imx6q-var-som.dtsi b/arch/arm/dts/imx6q-var-som.dtsi new file mode 100644 index 0000000000..f423f27359 --- /dev/null +++ b/arch/arm/dts/imx6q-var-som.dtsi @@ -0,0 +1,99 @@ +/* + * Copyright 2013 Michael Burkey + * Based on code written by Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx6q.dtsi" + +/ { + model = "Variscite i.MX6 Quad SOM"; + compatible = "variscite,imx6q-som", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x40000000>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + nand-on-flash-bbt; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "barebox"; + reg = <0x0 0x200000>; + }; + + partition@1 { + label = "barebox-environment"; + reg = <0x200000 0x20000>; + }; + + partition@2 { + label = "kernel"; + reg = <0x220000 0x600000>; + }; + + partition@3 { + label = "rootfs"; + reg = <0x820000 0x1F7E0000>; + }; +}; + +&hdmi { + status = "okay"; + ddc-i2c-bus = <&i2c2>; +}; + +&i2c2 { + status = "okay"; + clock-frequency = <1000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-variscite-som { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 + MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x80000000 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_ENET_PINGRP_RGMII_MD(0x1b0b0, 0x1b0b0) + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 /* KSZ9031 PHY Reset */ + >; + }; + + pinctrl_gpmi_nand: gpmigrp { + fsl,pins = <MX6QDL_GPMI_NAND_PINGRP1>; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = <MX6QDL_I2C2_PINGRP2>; + }; + }; +}; diff --git a/arch/arm/dts/imx6q.dtsi b/arch/arm/dts/imx6q.dtsi index 52a9a2b372..2b8ec43e03 100644 --- a/arch/arm/dts/imx6q.dtsi +++ b/arch/arm/dts/imx6q.dtsi @@ -16,6 +16,7 @@ / { aliases { spi4 = &ecspi5; + ipu1 = &ipu2; }; cpus { @@ -157,6 +158,10 @@ }; }; +&hdmi { + compatible = "fsl,imx6q-hdmi"; +}; + &ldb { clocks = <&clks 33>, <&clks 34>, <&clks 39>, <&clks 40>, <&clks 41>, <&clks 42>, diff --git a/arch/arm/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/dts/imx6qdl-phytec-pbab01.dtsi new file mode 100644 index 0000000000..8f5dea7407 --- /dev/null +++ b/arch/arm/dts/imx6qdl-phytec-pbab01.dtsi @@ -0,0 +1,43 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + chosen { + environment@0 { + compatible = "barebox,environment"; + device-path = &flash, "partname:barebox-environment"; + }; + }; +}; + +&fec { + status = "okay"; +}; + +&ocotp { + barebox,provide-mac-address = <&fec 0x620>; +}; + +&uart1 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&usdhc2 { + status = "okay"; +}; + +&usdhc3 { + status = "okay"; +}; diff --git a/arch/arm/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/dts/imx6qdl-phytec-pfla02.dtsi new file mode 100644 index 0000000000..d1eb9d0b09 --- /dev/null +++ b/arch/arm/dts/imx6qdl-phytec-pfla02.dtsi @@ -0,0 +1,171 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +&ecspi3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3>; + status = "disabled"; + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 24 0>; + + flash: m25p80@0 { + compatible = "m25p80"; + spi-max-frequency = <20000000>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + status = "disabled"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + nand-on-flash-bbt; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + ecspi3 { + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x80000000 + >; + }; + }; + + enet { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + >; + }; + }; + + gpmi-nand { + pinctrl_gpmi_nand: gpmi-nand { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_NANDF_CS2__NAND_CE2_B 0xb0b1 + MX6QDL_PAD_NANDF_CS3__NAND_CE3_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + }; + + hog { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + >; + }; + }; + + uart4 { + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + }; + + usdhc2 { + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + }; + + usdhc3 { + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 + >; + }; + }; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "disabled"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio1 4 0>; + wp-gpios = <&gpio1 2 0>; + status = "disabled"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio1 27 0>; + wp-gpios = <&gpio1 29 0>; + status = "disabled"; +}; diff --git a/arch/arm/dts/imx6qdl.dtsi b/arch/arm/dts/imx6qdl.dtsi index 70424d2cb7..8dfd7de48c 100644 --- a/arch/arm/dts/imx6qdl.dtsi +++ b/arch/arm/dts/imx6qdl.dtsi @@ -45,6 +45,7 @@ spi3 = &ecspi4; usbphy0 = &usbphy1; usbphy1 = &usbphy2; + ipu0 = &ipu1; }; intc: interrupt-controller@00a01000 { @@ -664,6 +665,17 @@ }; }; + hdmi: hdmi@0120000 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + status = "disabled"; + }; + dcic1: dcic@020e4000 { reg = <0x020e4000 0x4000>; interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/dts/imx6s-phytec-pbab01.dts b/arch/arm/dts/imx6s-phytec-pbab01.dts new file mode 100644 index 0000000000..95841de7b8 --- /dev/null +++ b/arch/arm/dts/imx6s-phytec-pbab01.dts @@ -0,0 +1,25 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; + +#include "imx6s-phytec-pfla02.dtsi" +#include "imx6qdl-phytec-pbab01.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 Single Carrier-Board"; + compatible = "phytec,imx6x-pbab01", "phytec,imx6s-pfla02", "fsl,imx6dl"; + + chosen { + linux,stdout-path = &uart4; + + }; +}; diff --git a/arch/arm/dts/imx6s-phytec-pfla02.dtsi b/arch/arm/dts/imx6s-phytec-pfla02.dtsi new file mode 100644 index 0000000000..83224262b3 --- /dev/null +++ b/arch/arm/dts/imx6s-phytec-pfla02.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx6dl.dtsi" +#include "imx6qdl-phytec-pfla02.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 Single"; + compatible = "phytec,imx6s-pfla02", "fsl,imx6dl"; + + memory { + reg = <0x10000000 0x20000000>; + }; +}; diff --git a/arch/arm/dts/virt2real.dts b/arch/arm/dts/virt2real.dts new file mode 100644 index 0000000000..09aec1f722 --- /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 28afaa39e4..52114d0c4e 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -3,6 +3,13 @@ #include <memory.h> +#include <linux/const.h> +/* + * 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 758df3f541..1d2de48df2 100644 --- a/arch/arm/mach-arm.dox +++ b/arch/arm/mach-arm.dox @@ -54,6 +54,8 @@ For details on specific architectures: @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-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index 7132489132..0e213ce9da 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -52,6 +52,7 @@ #define ARCH_EXID_SAMA5D33 0x00414300 #define ARCH_EXID_SAMA5D34 0x00414301 #define ARCH_EXID_SAMA5D35 0x00584300 +#define ARCH_EXID_SAMA5D36 0x00004301 #define ARCH_FAMILY_AT91X92 0x09200000 #define ARCH_FAMILY_AT91SAM9 0x01900000 @@ -104,7 +105,7 @@ enum at91_soc_subtype { /* SAMA5D3 */ AT91_SOC_SAMA5D31, AT91_SOC_SAMA5D33, AT91_SOC_SAMA5D34, - AT91_SOC_SAMA5D35, + AT91_SOC_SAMA5D35, AT91_SOC_SAMA5D36, /* Unknown subtype */ AT91_SOC_SUBTYPE_NONE @@ -206,12 +207,14 @@ static inline int at91_soc_is_detected(void) #define cpu_is_sama5d33() (at91_soc_initdata.subtype == AT91_SOC_SAMA5D33) #define cpu_is_sama5d34() (at91_soc_initdata.subtype == AT91_SOC_SAMA5D34) #define cpu_is_sama5d35() (at91_soc_initdata.subtype == AT91_SOC_SAMA5D35) +#define cpu_is_sama5d36() (at91_soc_initdata.subtype == AT91_SOC_SAMA5D36) #else #define cpu_is_sama5d3() (0) #define cpu_is_sama5d31() (0) #define cpu_is_sama5d33() (0) #define cpu_is_sama5d34() (0) #define cpu_is_sama5d35() (0) +#define cpu_is_sama5d36() (0) #endif /* diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c index 1bfae14f63..85efb2d78f 100644 --- a/arch/arm/mach-at91/sama5d3.c +++ b/arch/arm/mach-at91/sama5d3.c @@ -348,11 +348,13 @@ static void __init sama5d3_register_clocks(void) if ( cpu_is_sama5d33() || cpu_is_sama5d34() - || cpu_is_sama5d35() ) + || cpu_is_sama5d35() + || cpu_is_sama5d36()) clk_register(&macb0_clk); if ( cpu_is_sama5d31() - || cpu_is_sama5d35() ) + || cpu_is_sama5d35() + || cpu_is_sama5d36()) clk_register(&macb1_clk); if (!cpu_is_sama5d35()) diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 65d0588b43..7a7de98045 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -162,6 +162,8 @@ static void __init soc_detect(u32 dbgu_base) break; case ARCH_EXID_SAMA5D35: at91_soc_initdata.subtype = AT91_SOC_SAMA5D35; + case ARCH_EXID_SAMA5D36: + at91_soc_initdata.subtype = AT91_SOC_SAMA5D36; break; } } @@ -205,6 +207,7 @@ static const char *soc_subtype_name[] = { [AT91_SOC_SAMA5D33] = "sama5d33", [AT91_SOC_SAMA5D34] = "sama5d34", [AT91_SOC_SAMA5D35] = "sama5d35", + [AT91_SOC_SAMA5D36] = "sama5d36", [AT91_SOC_SUBTYPE_NONE] = "Unknown" }; diff --git a/arch/arm/mach-clps711x/clock.c b/arch/arm/mach-clps711x/clock.c index 7658c9aa7c..548b333b11 100644 --- a/arch/arm/mach-clps711x/clock.c +++ b/arch/arm/mach-clps711x/clock.c @@ -95,9 +95,9 @@ static __init int clps711x_clk_init(void) clks[timer_hf].clk = clk_fixed(clks[timer_hf].name, f_timer_hf); clks[timer_lf].clk = clk_fixed(clks[timer_lf].name, f_timer_lf); clks[tc1].clk = clk_mux(clks[tc1].name, IOMEM(SYSCON1), 5, 1, - tc_sel_clks, ARRAY_SIZE(tc_sel_clks)); + tc_sel_clks, ARRAY_SIZE(tc_sel_clks), 0); clks[tc2].clk = clk_mux(clks[tc2].name, IOMEM(SYSCON1), 7, 1, - tc_sel_clks, ARRAY_SIZE(tc_sel_clks)); + tc_sel_clks, ARRAY_SIZE(tc_sel_clks), 0); clps711x_clk_register(dummy); clps711x_clk_register(cpu); diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig new file mode 100644 index 0000000000..3165d5086d --- /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 0000000000..b96d4146f6 --- /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 0000000000..587f408cf8 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/debug_ll.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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 <asm/io.h> +#include <mach/serial.h> + +#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 0000000000..ea9f481844 --- /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 <asm/memory.h> + +/* + * 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 <chipname>.h, + * and the chip/board init code should then explicitly include + * <chipname>.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 0000000000..bc7449f3d7 --- /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. <source@mvista.com> + * + * 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 <mach/hardware.h> + +#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 0000000000..34781b6ec5 --- /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. <source@mvista.com> + * + * 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 <mach/hardware.h> + +#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 0000000000..789eacc42a --- /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 0000000000..60f0d192a3 --- /dev/null +++ b/arch/arm/mach-davinci/time.c @@ -0,0 +1,209 @@ +/* + * DaVinci timer subsystem + * + * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> + * + * 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 <common.h> +#include <io.h> +#include <init.h> +#include <clock.h> + +#include <mach/time.h> + +/* 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/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index b7e7533e84..d40c9447ea 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -39,6 +39,7 @@ config ARCH_TEXT_BASE default 0x4fc00000 if MACH_PHYTEC_PFLA02 default 0x4fc00000 if MACH_DFI_FS700_M60 default 0x4fc00000 if MACH_UDOO + default 0x4fc00000 if MACH_VARISCITE_MX6 config ARCH_IMX_INTERNAL_BOOT bool "support internal boot mode" @@ -109,6 +110,12 @@ config BAREBOX_UPDATE_IMX_EXTERNAL_NAND depends on BAREBOX_UPDATE default y +config BAREBOX_UPDATE_IMX6_NAND + bool + depends on ARCH_IMX6 + depends on BAREBOX_UPDATE + default y + comment "Freescale i.MX System-on-Chip" config ARCH_IMX1 @@ -202,7 +209,7 @@ config MACH_FREESCALE_MX53_VMX53 module equipped with a Freescale i.MX53 Processor config MACH_PHYTEC_PFLA02 - bool "Phytec phyFLEX-i.MX6 Ouad" + bool "Phytec phyFLEX-i.MX6" select ARCH_IMX6 config MACH_DFI_FS700_M60 @@ -247,6 +254,11 @@ config MACH_UDOO bool "Freescale i.MX6 UDOO Board" select ARCH_IMX6 +config MACH_VARISCITE_MX6 + bool "Variscite i.MX6 Quad SOM" + select ARCH_IMX6 + + endif # ---------------------------------------------------------- diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index b3f00f9cc3..03e5b102fa 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -20,4 +20,5 @@ obj-y += devices.o imx.o esdctl.o obj-y += boot.o obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o +obj-$(CONFIG_BAREBOX_UPDATE_IMX6_NAND) += imx6-bbu-nand.o pbl-y += esdctl.o diff --git a/arch/arm/mach-imx/clk-imx6.c b/arch/arm/mach-imx/clk-imx6.c index 5560fff7ce..518fc00d94 100644 --- a/arch/arm/mach-imx/clk-imx6.c +++ b/arch/arm/mach-imx/clk-imx6.c @@ -19,6 +19,8 @@ #include <linux/clkdev.h> #include <linux/err.h> #include <mach/imx6-regs.h> +#include <mach/revision.h> +#include <mach/imx6.h> #include "clk.h" @@ -84,8 +86,10 @@ enum mx6q_clks { usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg, pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg, ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5, - sata_ref, pcie_ref, sata_ref_100m, pcie_ref_125m, enet_ref, - clk_max + sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, + usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, + spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, + lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max }; static struct clk *clks[clk_max]; @@ -171,6 +175,62 @@ static const char *cko1_sels[] = { "pll4_audio", }; +static const char *ipu_sels[] = { + "mmdc_ch0_axi_podf", + "pll2_pfd2_396m", + "pll3_120m", + "pll3_pfd1_540m", +}; + +static const char *ldb_di_sels[] = { + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "mmdc_ch1_axi_podf", + "pll3_usb_otg", +}; + +static const char *ipu_di_pre_sels[] = { + "mmdc_ch0_axi", + "pll3_usb_otg", + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "pll3_pfd1_540m", +}; + +static const char *ipu1_di0_sels[] = { + "ipu1_di0_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu1_di1_sels[] = { + "ipu1_di1_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu2_di0_sels[] = { + "ipu2_di0_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu2_di1_sels[] = { + "ipu2_di1_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + static struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -179,6 +239,86 @@ static struct clk_div_table clk_enet_ref_table[] = { { }, }; +static struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { /* sentinel */ } +}; + +static struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { /* sentinel */ } +}; + +static void imx6_add_video_clks(void __iomem *anab, void __iomem *cb) +{ + clks[pll5_post_div] = imx_clk_divider_table("pll5_post_div", "pll5_video", anab + 0xa0, 19, 2, post_div_table); + clks[pll5_video_div] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", anab + 0x170, 30, 2, video_div_table); + + clks[ipu1_sel] = imx_clk_mux("ipu1_sel", cb + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clks[ipu2_sel] = imx_clk_mux("ipu2_sel", cb + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clks[ldb_di0_sel] = imx_clk_mux_p("ldb_di0_sel", cb + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clks[ldb_di1_sel] = imx_clk_mux_p("ldb_di1_sel", cb + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clks[ipu1_di0_pre_sel] = imx_clk_mux_p("ipu1_di0_pre_sel", cb + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[ipu1_di1_pre_sel] = imx_clk_mux_p("ipu1_di1_pre_sel", cb + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[ipu2_di0_pre_sel] = imx_clk_mux_p("ipu2_di0_pre_sel", cb + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[ipu2_di1_pre_sel] = imx_clk_mux_p("ipu2_di1_pre_sel", cb + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[ipu1_di0_sel] = imx_clk_mux_p("ipu1_di0_sel", cb + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); + clks[ipu1_di1_sel] = imx_clk_mux_p("ipu1_di1_sel", cb + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); + clks[ipu2_di0_sel] = imx_clk_mux_p("ipu2_di0_sel", cb + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); + clks[ipu2_di1_sel] = imx_clk_mux_p("ipu2_di1_sel", cb + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); + + clks[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", cb + 0x3c, 11, 3); + clks[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", cb + 0x3c, 16, 3); + clks[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_div_3_5", cb + 0x20, 10, 1); + clks[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clks[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_div_3_5", cb + 0x20, 11, 1); + clks[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", cb + 0x34, 3, 3); + clks[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", cb + 0x34, 12, 3); + clks[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", cb + 0x38, 3, 3); + clks[ipu2_di1_pre] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", cb + 0x38, 12, 3); + + clkdev_add_physbase(clks[ipu1_podf], MX6_IPU1_BASE_ADDR, "bus"); + clkdev_add_physbase(clks[ipu1_di0_sel], MX6_IPU1_BASE_ADDR, "di0"); + clkdev_add_physbase(clks[ipu1_di1_sel], MX6_IPU1_BASE_ADDR, "di1"); + clkdev_add_physbase(clks[ipu2_podf], MX6_IPU2_BASE_ADDR, "bus"); + clkdev_add_physbase(clks[ipu2_di0_sel], MX6_IPU2_BASE_ADDR, "di0"); + clkdev_add_physbase(clks[ipu2_di1_sel], MX6_IPU2_BASE_ADDR, "di1"); + + clkdev_add_physbase(clks[ldb_di0_sel], 0x020e0008, "di0_pll"); + clkdev_add_physbase(clks[ldb_di1_sel], 0x020e0008, "di1_pll"); + clkdev_add_physbase(clks[ipu1_di0_sel], 0x020e0008, "di0_sel"); + clkdev_add_physbase(clks[ipu1_di1_sel], 0x020e0008, "di1_sel"); + clkdev_add_physbase(clks[ipu2_di0_sel], 0x020e0008, "di2_sel"); + clkdev_add_physbase(clks[ipu2_di1_sel], 0x020e0008, "di3_sel"); + clkdev_add_physbase(clks[ldb_di0], 0x020e0008, "di0"); + clkdev_add_physbase(clks[ldb_di1], 0x020e0008, "di1"); + clkdev_add_physbase(clks[ahb], 0x00120000, "iahb"); + clkdev_add_physbase(clks[pll3_pfd1_540m], 0x00120000, "isfr"); + + clk_set_parent(clks[ipu1_di0_sel], clks[ipu1_di0_pre]); + clk_set_parent(clks[ipu1_di1_sel], clks[ipu1_di1_pre]); + clk_set_parent(clks[ipu2_di0_sel], clks[ipu2_di0_pre]); + clk_set_parent(clks[ipu2_di1_sel], clks[ipu2_di1_pre]); + + clk_set_parent(clks[ipu1_di0_pre_sel], clks[pll5_video_div]); + clk_set_parent(clks[ipu1_di1_pre_sel], clks[pll5_video_div]); + clk_set_parent(clks[ipu2_di0_pre_sel], clks[pll5_video_div]); + clk_set_parent(clks[ipu2_di1_pre_sel], clks[pll5_video_div]); + + if ((imx_silicon_revision() != IMX_CHIP_REV_1_0) || + cpu_is_mx6dl()) { + clk_set_parent(clks[ldb_di0_sel], clks[pll5_video_div]); + clk_set_parent(clks[ldb_di1_sel], clks[pll5_video_div]); + } + +} + static int imx6_ccm_probe(struct device_d *dev) { void __iomem *base, *anatop_base, *ccm_base; @@ -214,7 +354,7 @@ static int imx6_ccm_probe(struct device_d *dev) clks[sata_ref_100m] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20); clks[pcie_ref_125m] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); - clks[enet_ref] = clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table); + clks[enet_ref] = imx_clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table); /* name parent_name reg idx */ clks[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); @@ -281,7 +421,6 @@ static int imx6_ccm_probe(struct device_d *dev) clks[arm] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); clks[ahb] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); - clkdev_add_physbase(clks[uart_serial_podf], MX6_UART1_BASE_ADDR, NULL); clkdev_add_physbase(clks[uart_serial_podf], MX6_UART2_BASE_ADDR, NULL); clkdev_add_physbase(clks[uart_serial_podf], MX6_UART3_BASE_ADDR, NULL); @@ -310,10 +449,16 @@ static int imx6_ccm_probe(struct device_d *dev) clkdev_add_physbase(clks[ipg_per], MX6_PWM3_BASE_ADDR, "per"); clkdev_add_physbase(clks[ipg_per], MX6_PWM4_BASE_ADDR, "per"); + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + imx6_add_video_clks(anatop_base, ccm_base); + writel(0xffffffff, ccm_base + CCGR0); writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */ writel(0xffffffff, ccm_base + CCGR2); - writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */ + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + writel(0xffffffff, ccm_base + CCGR3); /* gate OpenVG */ + else + writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */ writel(0xffffffff, ccm_base + CCGR4); writel(0xffffffff, ccm_base + CCGR5); writel(0xffff3fff, ccm_base + CCGR6); /* gate VPU */ diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 4a7298d846..32a02db178 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -4,25 +4,39 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { - return clk_divider(name, parent, reg, shift, width); + return clk_divider(name, parent, reg, shift, width, CLK_SET_RATE_PARENT); +} + +static inline struct clk *imx_clk_divider_table(const char *name, + const char *parent, void __iomem *reg, u8 shift, u8 width, + const struct clk_div_table *table) +{ + return clk_divider_table(name, parent, reg, shift, width, table, + CLK_SET_RATE_PARENT); } static inline struct clk *imx_clk_fixed_factor(const char *name, const char *parent, unsigned int mult, unsigned int div) { - return clk_fixed_factor(name, parent, mult, div); + return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT); } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, u8 shift, u8 width, const char **parents, u8 num_parents) { - return clk_mux(name, reg, shift, width, parents, num_parents); + return clk_mux(name, reg, shift, width, parents, num_parents, 0); +} + +static inline struct clk *imx_clk_mux_p(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, u8 num_parents) +{ + return clk_mux(name, reg, shift, width, parents, num_parents, CLK_SET_RATE_PARENT); } static inline struct clk *imx_clk_gate(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_gate(name, parent, reg, shift); + return clk_gate(name, parent, reg, shift, CLK_SET_RATE_PARENT); } struct clk *imx_clk_pllv1(const char *name, const char *parent, diff --git a/arch/arm/mach-imx/imx6-bbu-nand.c b/arch/arm/mach-imx/imx6-bbu-nand.c new file mode 100644 index 0000000000..2d0705956c --- /dev/null +++ b/arch/arm/mach-imx/imx6-bbu-nand.c @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2014 Sascha Hauer, Pengutronix + * + * 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. + * + */ + +#define pr_fmt(fmt) "imx6-bbu-nand: " fmt + +#include <filetype.h> +#include <common.h> +#include <malloc.h> +#include <errno.h> +#include <fcntl.h> +#include <ioctl.h> +#include <sizes.h> +#include <bbu.h> +#include <fs.h> +#include <mach/bbu.h> +#include <linux/mtd/mtd-abi.h> +#include <linux/mtd/mtd.h> +#include <linux/stat.h> + +struct dbbt_block { + uint32_t Checksum; + uint32_t FingerPrint; + uint32_t Version; + uint32_t reserved; + uint32_t DBBTNumOfPages; +}; + +struct fcb_block { + uint32_t Checksum; /* First fingerprint in first byte */ + uint32_t FingerPrint; /* 2nd fingerprint at byte 4 */ + uint32_t Version; /* 3rd fingerprint at byte 8 */ + uint8_t DataSetup; + uint8_t DataHold; + uint8_t AddressSetup; + uint8_t DSAMPLE_TIME; + /* These are for application use only and not for ROM. */ + uint8_t NandTimingState; + uint8_t REA; + uint8_t RLOH; + uint8_t RHOH; + uint32_t PageDataSize; /* 2048 for 2K pages, 4096 for 4K pages */ + uint32_t TotalPageSize; /* 2112 for 2K pages, 4314 for 4K pages */ + uint32_t SectorsPerBlock; /* Number of 2K sections per block */ + uint32_t NumberOfNANDs; /* Total Number of NANDs - not used by ROM */ + uint32_t TotalInternalDie; /* Number of separate chips in this NAND */ + uint32_t CellType; /* MLC or SLC */ + uint32_t EccBlockNEccType; /* Type of ECC, can be one of BCH-0-20 */ + uint32_t EccBlock0Size; /* Number of bytes for Block0 - BCH */ + uint32_t EccBlockNSize; /* Block size in bytes for all blocks other than Block0 - BCH */ + uint32_t EccBlock0EccType; /* Ecc level for Block 0 - BCH */ + uint32_t MetadataBytes; /* Metadata size - BCH */ + uint32_t NumEccBlocksPerPage; /* Number of blocks per page for ROM use - BCH */ + uint32_t EccBlockNEccLevelSDK; /* Type of ECC, can be one of BCH-0-20 */ + uint32_t EccBlock0SizeSDK; /* Number of bytes for Block0 - BCH */ + uint32_t EccBlockNSizeSDK; /* Block size in bytes for all blocks other than Block0 - BCH */ + uint32_t EccBlock0EccLevelSDK; /* Ecc level for Block 0 - BCH */ + uint32_t NumEccBlocksPerPageSDK;/* Number of blocks per page for SDK use - BCH */ + uint32_t MetadataBytesSDK; /* Metadata size - BCH */ + uint32_t EraseThreshold; /* To set into BCH_MODE register */ + uint32_t BootPatch; /* 0 for normal boot and 1 to load patch starting next to FCB */ + uint32_t PatchSectors; /* Size of patch in sectors */ + uint32_t Firmware1_startingPage;/* Firmware image starts on this sector */ + uint32_t Firmware2_startingPage;/* Secondary FW Image starting Sector */ + uint32_t PagesInFirmware1; /* Number of sectors in firmware image */ + uint32_t PagesInFirmware2; /* Number of sector in secondary FW image */ + uint32_t DBBTSearchAreaStartAddress; /* Page address where dbbt search area begins */ + uint32_t BadBlockMarkerByte; /* Byte in page data that have manufacturer marked bad block marker, */ + /* this will be swapped with metadata[0] to complete page data. */ + uint32_t BadBlockMarkerStartBit;/* For BCH ECC sizes other than 8 and 16 the bad block marker does not */ + /* start at 0th bit of BadBlockMarkerByte. This field is used to get to */ + /* the start bit of bad block marker byte with in BadBlockMarkerByte */ + uint32_t BBMarkerPhysicalOffset;/* FCB value that gives byte offset for bad block marker on physical NAND page */ + uint32_t BCHType; + + uint32_t TMTiming2_ReadLatency; + uint32_t TMTiming2_PreambleDelay; + uint32_t TMTiming2_CEDelay; + uint32_t TMTiming2_PostambleDelay; + uint32_t TMTiming2_CmdAddPause; + uint32_t TMTiming2_DataPause; + uint32_t TMSpeed; + uint32_t TMTiming1_BusyTimeout; + + uint32_t DISBBM; /* the flag to enable (1)/disable(0) bi swap */ + uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */ +}; + +#define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) +#define GETBIT(v,n) (((v) >> (n)) & 0x1) + +static uint8_t calculate_parity_13_8(uint8_t d) +{ + uint8_t p = 0; + + p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0; + p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ GETBIT(d, 1)) << 1; + p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 2; + p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3; + p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 4; + return p; +} + +static void encode_hamming_13_8(void *_src, void *_ecc, size_t size) +{ + int i; + uint8_t *src = _src; + uint8_t *ecc = _ecc; + + for (i = 0; i < size; i++) + ecc[i] = calculate_parity_13_8(src[i]); +} + +static uint32_t calc_chksum(void *buf, size_t size) +{ + u32 chksum = 0; + u8 *bp = buf; + size_t i; + + for (i = 0; i < size; i++) + chksum += bp[i]; + + return ~chksum; +} + +static __maybe_unused void dump_fcb(void *buf) +{ + struct fcb_block *fcb = buf; + + pr_debug("Checksum: 0x%08x\n", fcb->Checksum); + pr_debug("FingerPrint: 0x%08x\n", fcb->FingerPrint); + pr_debug("Version: 0x%08x\n", fcb->Version); + pr_debug("DataSetup: 0x%02x\n", fcb->DataSetup); + pr_debug("DataHold: 0x%02x\n", fcb->DataHold); + pr_debug("AddressSetup: 0x%02x\n", fcb->AddressSetup); + pr_debug("DSAMPLE_TIME: 0x%02x\n", fcb->DSAMPLE_TIME); + pr_debug("NandTimingState: 0x%02x\n", fcb->NandTimingState); + pr_debug("REA: 0x%02x\n", fcb->REA); + pr_debug("RLOH: 0x%02x\n", fcb->RLOH); + pr_debug("RHOH: 0x%02x\n", fcb->RHOH); + pr_debug("PageDataSize: 0x%08x\n", fcb->PageDataSize); + pr_debug("TotalPageSize: 0x%08x\n", fcb->TotalPageSize); + pr_debug("SectorsPerBlock: 0x%08x\n", fcb->SectorsPerBlock); + pr_debug("NumberOfNANDs: 0x%08x\n", fcb->NumberOfNANDs); + pr_debug("TotalInternalDie: 0x%08x\n", fcb->TotalInternalDie); + pr_debug("CellType: 0x%08x\n", fcb->CellType); + pr_debug("EccBlockNEccType: 0x%08x\n", fcb->EccBlockNEccType); + pr_debug("EccBlock0Size: 0x%08x\n", fcb->EccBlock0Size); + pr_debug("EccBlockNSize: 0x%08x\n", fcb->EccBlockNSize); + pr_debug("EccBlock0EccType: 0x%08x\n", fcb->EccBlock0EccType); + pr_debug("MetadataBytes: 0x%08x\n", fcb->MetadataBytes); + pr_debug("NumEccBlocksPerPage: 0x%08x\n", fcb->NumEccBlocksPerPage); + pr_debug("EccBlockNEccLevelSDK: 0x%08x\n", fcb->EccBlockNEccLevelSDK); + pr_debug("EccBlock0SizeSDK: 0x%08x\n", fcb->EccBlock0SizeSDK); + pr_debug("EccBlockNSizeSDK: 0x%08x\n", fcb->EccBlockNSizeSDK); + pr_debug("EccBlock0EccLevelSDK: 0x%08x\n", fcb->EccBlock0EccLevelSDK); + pr_debug("NumEccBlocksPerPageSDK: 0x%08x\n", fcb->NumEccBlocksPerPageSDK); + pr_debug("MetadataBytesSDK: 0x%08x\n", fcb->MetadataBytesSDK); + pr_debug("EraseThreshold: 0x%08x\n", fcb->EraseThreshold); + pr_debug("BootPatch: 0x%08x\n", fcb->BootPatch); + pr_debug("PatchSectors: 0x%08x\n", fcb->PatchSectors); + pr_debug("Firmware1_startingPage: 0x%08x\n", fcb->Firmware1_startingPage); + pr_debug("Firmware2_startingPage: 0x%08x\n", fcb->Firmware2_startingPage); + pr_debug("PagesInFirmware1: 0x%08x\n", fcb->PagesInFirmware1); + pr_debug("PagesInFirmware2: 0x%08x\n", fcb->PagesInFirmware2); + pr_debug("DBBTSearchAreaStartAddress: 0x%08x\n", fcb->DBBTSearchAreaStartAddress); + pr_debug("BadBlockMarkerByte: 0x%08x\n", fcb->BadBlockMarkerByte); + pr_debug("BadBlockMarkerStartBit: 0x%08x\n", fcb->BadBlockMarkerStartBit); + pr_debug("BBMarkerPhysicalOffset: 0x%08x\n", fcb->BBMarkerPhysicalOffset); + pr_debug("BCHType: 0x%08x\n", fcb->BCHType); + pr_debug("TMTiming2_ReadLatency: 0x%08x\n", fcb->TMTiming2_ReadLatency); + pr_debug("TMTiming2_PreambleDelay: 0x%08x\n", fcb->TMTiming2_PreambleDelay); + pr_debug("TMTiming2_CEDelay: 0x%08x\n", fcb->TMTiming2_CEDelay); + pr_debug("TMTiming2_PostambleDelay: 0x%08x\n", fcb->TMTiming2_PostambleDelay); + pr_debug("TMTiming2_CmdAddPause: 0x%08x\n", fcb->TMTiming2_CmdAddPause); + pr_debug("TMTiming2_DataPause: 0x%08x\n", fcb->TMTiming2_DataPause); + pr_debug("TMSpeed: 0x%08x\n", fcb->TMSpeed); + pr_debug("TMTiming1_BusyTimeout: 0x%08x\n", fcb->TMTiming1_BusyTimeout); + pr_debug("DISBBM: 0x%08x\n", fcb->DISBBM); + pr_debug("BBMarkerPhysOfsInSpareData: 0x%08x\n", fcb->BBMarkerPhysicalOffsetInSpareData); +} + +static __maybe_unused ssize_t raw_read_page(struct mtd_info *mtd, void *dst, loff_t offset) +{ + struct mtd_oob_ops ops; + ssize_t ret; + + ops.mode = MTD_OPS_RAW; + ops.ooboffs = 0; + ops.datbuf = dst; + ops.len = mtd->writesize; + ops.oobbuf = dst + mtd->writesize; + ops.ooblen = mtd->oobsize; + ret = mtd_read_oob(mtd, offset, &ops); + + return ret; +} + +static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset) +{ + struct mtd_oob_ops ops; + ssize_t ret; + + ops.mode = MTD_OPS_RAW; + ops.ooboffs = 0; + ops.datbuf = buf; + ops.len = mtd->writesize; + ops.oobbuf = buf + mtd->writesize; + ops.ooblen = mtd->oobsize; + ret = mtd_write_oob(mtd, offset, &ops); + + return ret; +} + +static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) +{ + fcb->FingerPrint = 0x20424346; + fcb->Version = 0x01000000; + fcb->PageDataSize = mtd->writesize; + fcb->TotalPageSize = mtd->writesize + mtd->oobsize; + fcb->SectorsPerBlock = mtd->erasesize / mtd->writesize; + + if (mtd->writesize == 2048) { + fcb->EccBlock0EccType = 4; + } else if (mtd->writesize == 4096) { + if (mtd->oobsize == 218) { + fcb->EccBlock0EccType = 8; + } else if (mtd->oobsize == 128) { + fcb->EccBlock0EccType = 4; + } else { + pr_err("Illegal oobsize %d\n", mtd->oobsize); + return -EINVAL; + } + } else { + pr_err("Illegal writesize %d\n", mtd->writesize); + return -EINVAL; + } + + fcb->EccBlockNEccType = fcb->EccBlock0EccType; + + /* Also hardcoded in kobs-ng */ + fcb->DataSetup = 80; + fcb->DataHold = 60; + fcb->AddressSetup = 25; + fcb->DSAMPLE_TIME = 6; + fcb->MetadataBytes = 0x0000000a; + fcb->EccBlock0Size = 0x00000200; + fcb->EccBlockNSize = 0x00000200; + + fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1; + + /* DBBT search area starts at third block */ + fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2; + + if (mtd->writesize == 2048) { + fcb->BadBlockMarkerByte = 0x000007cf; + } else { + pr_err("BadBlockMarkerByte unknown for writesize %d\n", mtd->writesize); + return -EINVAL; + } + + fcb->BBMarkerPhysicalOffset = mtd->writesize; + + fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4); + + return 0; +} + +static int imx6_bbu_erase(struct mtd_info *mtd) +{ + uint64_t offset = 0; + int len = SZ_2M; + struct erase_info erase; + int ret; + + while (len > 0) { + pr_debug("erasing at 0x%08llx\n", offset); + if (mtd_block_isbad(mtd, offset)) { + offset += mtd->erasesize; + pr_debug("erase skip block @ 0x%08llx\n", offset); + continue; + } + + memset(&erase, 0, sizeof(erase)); + erase.addr = offset; + erase.len = mtd->erasesize; + + ret = mtd_erase(mtd, &erase); + if (ret) + return ret; + + offset += mtd->erasesize; + len -= mtd->erasesize; + } + + return 0; +} + +static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len) +{ + uint64_t offset = block * mtd->erasesize; + int ret; + size_t written; + + while (len > 0) { + int now = min(len, mtd->erasesize); + + pr_debug("writing %p at 0x%08llx, left 0x%08x\n", + buf, offset, len); + + if (mtd_block_isbad(mtd, offset)) { + offset += mtd->erasesize; + block++; + pr_debug("write skip block @ 0x%08llx\n", offset); + continue; + } + + ret = mtd_write(mtd, offset, now, &written, buf); + if (ret) + return ret; + + offset += now; + len -= now; + buf += now; + block++; + } + + return block; +} + +static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last) +{ + int n; + int n_bad_blocks = 0; + uint32_t *bb = buf + 0x8; + uint32_t *n_bad_blocksp = buf + 0x4; + + for (n = 0; n <= block_last; n++) { + loff_t offset = n * mtd->erasesize; + if (mtd_block_isbad(mtd, offset)) { + n_bad_blocks++; + *bb = n; + bb++; + } + } + + *n_bad_blocksp = n_bad_blocks; + + return n_bad_blocks; +} + +static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) +{ + struct cdev *bcb_cdev; + struct mtd_info *mtd; + int ret, block_fw1, block_fw2, block_last; + struct fcb_block *fcb; + struct dbbt_block *dbbt; + void *fcb_raw_page, *dbbt_page, *dbbt_data_page; + void *ecc; + int written; + void *fw; + unsigned fw_size; + int i; + + if (file_detect_type(data->image, data->len) != filetype_arm_barebox && + !bbu_force(data, "Not an ARM barebox image")) + return -EINVAL; + + ret = bbu_confirm(data); + if (ret) + return ret; + + bcb_cdev = cdev_by_name("nand0"); + if (!bcb_cdev) { + pr_err("%s: No FCB device!\n", __func__); + return -ENODEV; + } + + mtd = bcb_cdev->mtd; + + fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize); + + fcb = fcb_raw_page + 12; + ecc = fcb_raw_page + 512 + 12; + + dbbt_page = xzalloc(mtd->writesize); + dbbt_data_page = xzalloc(mtd->writesize); + dbbt = dbbt_page; + + /* + * We have to write one additional page to make the ROM happy. + * Maybe the PagesInFirmwarex fields are really the number of pages - 1. + * kobs-ng has the same. + */ + fw_size = ALIGN(data->len + mtd->writesize, mtd->writesize); + fw = xzalloc(fw_size); + memcpy(fw, data->image, data->len); + + block_fw1 = 4; + + ret = imx6_bbu_erase(mtd); + if (ret) + goto out; + + ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size); + if (ret < 0) + goto out; + + block_fw2 = ret; + + ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size); + if (ret < 0) + goto out; + + block_last = ret; + + fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize; + fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize; + fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize; + fcb->PagesInFirmware2 = fcb->PagesInFirmware1; + + fcb_create(fcb, mtd); + encode_hamming_13_8(fcb, ecc, 512); + ret = raw_write_page(mtd, fcb_raw_page, 0); + if (ret) + goto out; + + ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize); + if (ret) + goto out; + + dbbt->Checksum = 0; + dbbt->FingerPrint = 0x54424244; + dbbt->Version = 0x01000000; + + ret = dbbt_data_create(mtd, dbbt_data_page, block_last); + if (ret < 0) + goto out; + + if (ret > 0) + dbbt->DBBTNumOfPages = 1; + + for (i = 2; i < 4; i++) { + ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page); + if (ret) + goto out; + + if (dbbt->DBBTNumOfPages > 0) { + ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4, + 2048, &written, dbbt_data_page); + if (ret) + goto out; + } + } + +out: + free(dbbt_page); + free(dbbt_data_page); + free(fcb_raw_page); + free(fw); + + return ret; +} + +int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + struct bbu_handler *handler; + int ret; + + handler = xzalloc(sizeof(*handler)); + handler->devicefile = "/dev/nand0"; + handler->name = name; + handler->flags = flags; + handler->handler = imx6_bbu_nand_update; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index 304b1c0f2e..e14ce90b46 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -15,6 +15,7 @@ #include <common.h> #include <io.h> #include <sizes.h> +#include <mfd/imx6q-iomuxc-gpr.h> #include <mach/imx6.h> #include <mach/generic.h> #include <mach/revision.h> @@ -28,7 +29,9 @@ void imx6_init_lowlevel(void) { void __iomem *aips1 = (void *)MX6_AIPS1_ON_BASE_ADDR; void __iomem *aips2 = (void *)MX6_AIPS2_ON_BASE_ADDR; + void __iomem *iomux = (void *)MX6_IOMUXC_BASE_ADDR; int is_imx6q = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6Q; + uint32_t val; /* * Set all MPROTx to be non-bufferable, trusted for R/W, @@ -87,6 +90,22 @@ void imx6_init_lowlevel(void) BM_ANADIG_PFD_528_PFD0_CLKGATE, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); + val = readl(iomux + IOMUXC_GPR4); + val |= IMX6Q_GPR4_VPU_WR_CACHE_SEL | IMX6Q_GPR4_VPU_RD_CACHE_SEL | + IMX6Q_GPR4_VPU_P_WR_CACHE_VAL | IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK | + IMX6Q_GPR4_IPU_WR_CACHE_CTL | IMX6Q_GPR4_IPU_RD_CACHE_CTL; + writel(val, iomux + IOMUXC_GPR4); + + /* Increase IPU read QoS priority */ + val = readl(iomux + IOMUXC_GPR6); + val &= ~(IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK | IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK); + val |= (0xf << 16) | (0x7 << 20); + writel(val, iomux + IOMUXC_GPR6); + + val = readl(iomux + IOMUXC_GPR7); + val &= ~(IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK | IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK); + val |= (0xf << 16) | (0x7 << 20); + writel(val, iomux + IOMUXC_GPR7); } int imx6_init(void) diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h index 3cd3b1e4cf..1644d85250 100644 --- a/arch/arm/mach-imx/include/mach/bbu.h +++ b/arch/arm/mach-imx/include/mach/bbu.h @@ -33,6 +33,8 @@ int imx6_bbu_internal_spi_i2c_register_handler(const char *name, char *devicefil unsigned long flags, struct imx_dcd_v2_entry *dcd, int dcdsize, unsigned long app_dest); +int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); + #else static inline int imx51_bbu_internal_mmc_register_handler(const char *name, char *devicefile, @@ -77,6 +79,10 @@ static inline int imx6_bbu_internal_spi_i2c_register_handler(const char *name, c return -ENOSYS; } +static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + return -ENOSYS; +} #endif #if defined(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) diff --git a/arch/arm/mach-imx/include/mach/imx6-regs.h b/arch/arm/mach-imx/include/mach/imx6-regs.h index 833280af53..facbe51b70 100644 --- a/arch/arm/mach-imx/include/mach/imx6-regs.h +++ b/arch/arm/mach-imx/include/mach/imx6-regs.h @@ -26,6 +26,9 @@ #define MX6_SPBA_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x3C000) #define MX6_VPU_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x40000) +#define MX6_IPU1_BASE_ADDR 0x02400000 +#define MX6_IPU2_BASE_ADDR 0x02800000 + /* ATZ#1- On Platform */ #define MX6_AIPS1_ON_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x7C000) diff --git a/arch/arm/mach-zynq/clk-zynq7000.c b/arch/arm/mach-zynq/clk-zynq7000.c index 6472c642fd..ea637d7634 100644 --- a/arch/arm/mach-zynq/clk-zynq7000.c +++ b/arch/arm/mach-zynq/clk-zynq7000.c @@ -374,11 +374,11 @@ static int zynq_clock_probe(struct device_d *dev) clks[uart_clk] = zynq_periph_clk("uart_clk", slcr_base + 0x154); - clks[uart0] = clk_gate("uart0", "uart_clk", slcr_base + 0x154, 0); - clks[uart1] = clk_gate("uart1", "uart_clk", slcr_base + 0x154, 1); + clks[uart0] = clk_gate("uart0", "uart_clk", slcr_base + 0x154, 0, 0); + clks[uart1] = clk_gate("uart1", "uart_clk", slcr_base + 0x154, 1, 0); - clks[gem0] = clk_gate("gem0", "io_pll", slcr_base + 0x140, 0); - clks[gem1] = clk_gate("gem1", "io_pll", slcr_base + 0x144, 1); + clks[gem0] = clk_gate("gem0", "io_pll", slcr_base + 0x140, 0, 0); + clks[gem1] = clk_gate("gem1", "io_pll", slcr_base + 0x144, 1, 0); clks[cpu_clk] = zynq_cpu_clk("cpu_clk", slcr_base + 0x120); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b819b49d1c..9a240b7822 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -54,6 +54,19 @@ config MACH_MIPS_AR231X select DRIVER_SERIAL_NS16550 select HAS_DEBUG_LL +config MACH_MIPS_ATH79 + bool "Atheros AR71XX/AR724X/AR913X/AR933X based boards" + select SYS_HAS_CPU_MIPS32_R2 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select CSRC_R4K_LIB + select HAS_DEBUG_LL + select HAVE_CLK + select COMMON_CLK + select COMMON_CLK_OF_PROVIDER + select CLKDEV_LOOKUP + select OFTREE + config MACH_MIPS_BCM47XX bool "Broadcom BCM47xx-based boards" select CSRC_R4K_LIB @@ -80,6 +93,7 @@ endchoice source arch/mips/mach-malta/Kconfig source arch/mips/mach-ar231x/Kconfig +source arch/mips/mach-ath79/Kconfig source arch/mips/mach-bcm47xx/Kconfig source arch/mips/mach-loongson/Kconfig source arch/mips/mach-xburst/Kconfig diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 8986fcf46f..b3bacf3be1 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -78,6 +78,9 @@ board-$(CONFIG_BOARD_QEMU_MALTA) := qemu-malta machine-$(CONFIG_MACH_MIPS_AR231X) := ar231x board-$(CONFIG_BOARD_NETGEAR_WG102) := netgear-wg102 +machine-$(CONFIG_MACH_MIPS_ATH79) := ath79 +board-$(CONFIG_BOARD_TPLINK_MR3020) := tplink-mr3020 + machine-$(CONFIG_MACH_MIPS_BCM47XX) := bcm47xx board-$(CONFIG_BOARD_DLINK_DIR320) := dlink-dir-320 @@ -85,7 +88,7 @@ machine-$(CONFIG_MACH_MIPS_LOONGSON) := loongson board-$(CONFIG_BOARD_LOONGSON_TECH_LS1B) := loongson-ls1b machine-$(CONFIG_MACH_MIPS_XBURST) := xburst -board-$(CONFIG_BOARD_RZX50) := rzx50 +board-$(CONFIG_BOARD_RZX50) := ritmix-rzx50 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y)) diff --git a/arch/mips/boards/ritmix-rzx50/Makefile b/arch/mips/boards/ritmix-rzx50/Makefile new file mode 100644 index 0000000000..31c062987f --- /dev/null +++ b/arch/mips/boards/ritmix-rzx50/Makefile @@ -0,0 +1 @@ +obj-y += serial.o diff --git a/arch/mips/boards/rzx50/include/board/board_pbl_start.h b/arch/mips/boards/ritmix-rzx50/include/board/board_pbl_start.h index fb914d99f2..fb914d99f2 100644 --- a/arch/mips/boards/rzx50/include/board/board_pbl_start.h +++ b/arch/mips/boards/ritmix-rzx50/include/board/board_pbl_start.h diff --git a/arch/mips/boards/rzx50/include/board/debug_ll.h b/arch/mips/boards/ritmix-rzx50/include/board/debug_ll.h index 7ae0e2a4fd..7ae0e2a4fd 100644 --- a/arch/mips/boards/rzx50/include/board/debug_ll.h +++ b/arch/mips/boards/ritmix-rzx50/include/board/debug_ll.h diff --git a/arch/mips/boards/rzx50/rzx50.dox b/arch/mips/boards/ritmix-rzx50/ritmix-rzx50.dox index 963473cb51..5ec819462b 100644 --- a/arch/mips/boards/rzx50/rzx50.dox +++ b/arch/mips/boards/ritmix-rzx50/ritmix-rzx50.dox @@ -1,4 +1,4 @@ -/** @page rzx50 Ritmix RZX-50 game console +/** @page ritmix-rzx50 Ritmix RZX-50 game console Ritmix RZX-50 is a portable game console for the Russian market. diff --git a/arch/mips/boards/rzx50/serial.c b/arch/mips/boards/ritmix-rzx50/serial.c index 566356aaa5..f1e8da0072 100644 --- a/arch/mips/boards/rzx50/serial.c +++ b/arch/mips/boards/ritmix-rzx50/serial.c @@ -17,16 +17,11 @@ #include <common.h> #include <init.h> -#include <mach/devices.h> -#include <mach/jz4750d_regs.h> -static int rzx50_console_init(void) +static int rzx50_hostname_init(void) { barebox_set_hostname("rzx50"); - /* Register the serial port */ - jz_add_uart(DEVICE_ID_DYNAMIC, UART1_BASE, 12000000); - return 0; } -console_initcall(rzx50_console_init); +console_initcall(rzx50_hostname_init); diff --git a/arch/mips/boards/rzx50/Makefile b/arch/mips/boards/rzx50/Makefile deleted file mode 100644 index ff1a655afe..0000000000 --- a/arch/mips/boards/rzx50/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial.o diff --git a/arch/mips/boards/tplink-mr3020/Makefile b/arch/mips/boards/tplink-mr3020/Makefile new file mode 100644 index 0000000000..dcfc2937d3 --- /dev/null +++ b/arch/mips/boards/tplink-mr3020/Makefile @@ -0,0 +1 @@ +obj-y += board.o diff --git a/arch/mips/boards/tplink-mr3020/board.c b/arch/mips/boards/tplink-mr3020/board.c new file mode 100644 index 0000000000..318998cc49 --- /dev/null +++ b/arch/mips/boards/tplink-mr3020/board.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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 <common.h> +#include <init.h> + +static int model_hostname_init(void) +{ + barebox_set_hostname("mr3020"); + + return 0; +} +postcore_initcall(model_hostname_init); diff --git a/arch/mips/boards/tplink-mr3020/tplink-mr3020.dox b/arch/mips/boards/tplink-mr3020/tplink-mr3020.dox new file mode 100644 index 0000000000..16fe4653d8 --- /dev/null +++ b/arch/mips/boards/tplink-mr3020/tplink-mr3020.dox @@ -0,0 +1,64 @@ +/** @page tplink-mr3020 TP-LINK MR3020 wireless router + +The router has +@li Atheros ar9331 SoC; +@li 32 MiB SDRAM; +@li 4 MiB NOR type SPI Flash Memory; +@li RS232 serial interface (LV-TTL levels on board!); +@li 1 USB interface; +@li 1 Ethernet interfaces; +@li 802.11b/g/n (WiFi) interface; +@li LEDs & buttons. + +The router uses U-Boot 1.1.4 as firmware. + +Barebox can be started from U-Boot using tftp. +But you have to encode barebox image in a very special way. + +First obtain 'lzma' and 'mktplinkfw' utilities. + +The 'lzma' utility can be obtained in Debian/Ubuntu +distro by installing lzma package. + +The 'mktplinkfw' utility can be obtained from openwrt, e.g.: + +@verbatim +$ OWRTPREF=https://raw.githubusercontent.com/mirrors/openwrt/master +$ curl -OL $OWRTPREF/tools/firmware-utils/src/mktplinkfw.c \ + -OL $OWRTPREF/tools/firmware-utils/src/md5.c \ + -OL $OWRTPREF/tools/firmware-utils/src/md5.h +$ cc -o mktplinkfw mktplinkfw.c md5.c +@endverbatim + +To convert your barebox.bin to U-Boot-loadable image (6F01A8C0.img) +use this command sequence: + +@verbatim +$ lzma -c -k barebox.bin > barebox.lzma +$ ./FW/mktplinkfw -c -H 0x07200103 -W 1 -N TL-WR720N-v3 \ + -s -F 4Mlzma -k barebox.lzma -o 6F01A8C0.img +@endverbatim + +You must setup tftp-server on host 192.168.0.1. +Put your 6F01A8C0.img to tftp-server directory +(usual /tftpboot or /srv/tftp). +Connect your board to your tftp-server network via Ethernet. + +Next, setup network on MR3020 and run 6F01A8C0.img, e.g.: +@verbatim +hornet> set ipaddr 192.168.0.2 +hornet> set serverip 192.168.0.1 +hornet> tftpboot 0x81000000 6F01A8C0.img +hornet> bootm 0x81000000 +@endverbatim + +TP-LINK MR3020 links: +@li http://www.tp-link.com/en/products/details/?model=TL-MR3020 +@li http://wiki.openwrt.org/toh/tp-link/tl-mr3020 +@li https://wikidevi.com/wiki/TP-LINK_TL-MR3020 + +See also: +@li http://www.eeboard.com/wp-content/uploads/downloads/2013/08/AR9331.pdf +@li http://squonk42.github.io/TL-WR703N/ + +*/ diff --git a/arch/mips/configs/rzx50_defconfig b/arch/mips/configs/ritmix-rzx50_defconfig index 7691bae6e6..7691bae6e6 100644 --- a/arch/mips/configs/rzx50_defconfig +++ b/arch/mips/configs/ritmix-rzx50_defconfig diff --git a/arch/mips/configs/tplink-mr3020_defconfig b/arch/mips/configs/tplink-mr3020_defconfig new file mode 100644 index 0000000000..2e925d9e3c --- /dev/null +++ b/arch/mips/configs/tplink-mr3020_defconfig @@ -0,0 +1,29 @@ +CONFIG_BUILTIN_DTB=y +CONFIG_BUILTIN_DTB_NAME="tplink-mr3020" +CONFIG_MACH_MIPS_ATH79=y +CONFIG_LONGHELP=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_LET=y +CONFIG_CMD_GLOBAL=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_MM=y +CONFIG_CMD_SHA1SUM=y +# CONFIG_CMD_BOOTM 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_CLK=y +CONFIG_OFDEVICE=y +CONFIG_DRIVER_SERIAL_AR933X=y +# CONFIG_SPI is not set +CONFIG_MD5=y +CONFIG_SHA224=y +CONFIG_SHA256=y diff --git a/arch/mips/dts/ar9331.dtsi b/arch/mips/dts/ar9331.dtsi new file mode 100644 index 0000000000..890fda8ab5 --- /dev/null +++ b/arch/mips/dts/ar9331.dtsi @@ -0,0 +1,26 @@ +#include <dt-bindings/clock/ar933x-clk.h> + +#include "skeleton.dtsi" + +/ { + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + device_type = "soc"; + ranges; + + serial0: serial@b8020000 { + compatible = "qca,ar9330-uart"; + reg = <0xb8020000 0x14>; + clocks = <&ar9331_clk AR933X_CLK_UART>; + status = "disabled"; + }; + + ar9331_clk: clock { + compatible = "qca,ar933x-clk"; + reg = <0xb8050000 0x48>; + #clock-cells = <1>; + }; + }; +}; diff --git a/arch/mips/dts/include/dt-bindings b/arch/mips/dts/include/dt-bindings new file mode 120000 index 0000000000..0cecb3d080 --- /dev/null +++ b/arch/mips/dts/include/dt-bindings @@ -0,0 +1 @@ +../../../../include/dt-bindings
\ No newline at end of file diff --git a/arch/mips/dts/jz4755.dtsi b/arch/mips/dts/jz4755.dtsi new file mode 100644 index 0000000000..44ff912916 --- /dev/null +++ b/arch/mips/dts/jz4755.dtsi @@ -0,0 +1,35 @@ +#include "skeleton.dtsi" + +/ { + soc { + compatible = "simple-bus"; + model = "Ingenic JZ4755"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + serial0: serial@b0030000 { + compatible = "ingenic,jz4740-uart"; + reg = <0xb0030000 0x20>; + reg-shift = <2>; + clock-frequency = <12000000>; + status = "disabled"; + }; + + serial1: serial@b0031000 { + compatible = "ingenic,jz4740-uart"; + reg = <0xb0031000 0x20>; + reg-shift = <2>; + clock-frequency = <12000000>; + status = "disabled"; + }; + + serial2: serial@b0032000 { + compatible = "ingenic,jz4740-uart"; + reg = <0xb0032000 0x20>; + reg-shift = <2>; + clock-frequency = <12000000>; + status = "disabled"; + }; + }; +}; diff --git a/arch/mips/dts/qemu-malta.dts b/arch/mips/dts/qemu-malta.dts index b6b69c4955..67fe591f1f 100644 --- a/arch/mips/dts/qemu-malta.dts +++ b/arch/mips/dts/qemu-malta.dts @@ -25,6 +25,14 @@ clock-frequency = <1843200>; }; + uart2: serial@bf000900 { + compatible = "ns16550a"; + reg = <0xbf000900 0x40>; + reg-shift = <3>; + /* no matter for emulated port */ + clock-frequency = <1843200>; + }; + nor0: flash@be000000 { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/mips/dts/rzx50.dts b/arch/mips/dts/rzx50.dts index 69320ddbb3..360c1bf5de 100644 --- a/arch/mips/dts/rzx50.dts +++ b/arch/mips/dts/rzx50.dts @@ -1,6 +1,6 @@ /dts-v1/; -/include/ "skeleton.dtsi" +#include "jz4755.dtsi" / { model = "Ritmix RZX-50"; @@ -10,3 +10,7 @@ reg = <0x00000000 0x4000000>; }; }; + +&serial1 { + status = "okay"; +}; diff --git a/arch/mips/dts/tplink-mr3020.dts b/arch/mips/dts/tplink-mr3020.dts new file mode 100644 index 0000000000..5d613d80bb --- /dev/null +++ b/arch/mips/dts/tplink-mr3020.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +#include <ar9331.dtsi> + +/ { + model = "TP-LINK MR3020"; + compatible = "tplink,mr3020"; + + memory { + reg = <0x00000000 0x2000000>; + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/mips/include/asm/debug_ll_ns16550.h b/arch/mips/include/asm/debug_ll_ns16550.h index f36010ce07..032f0a2869 100644 --- a/arch/mips/include/asm/debug_ll_ns16550.h +++ b/arch/mips/include/asm/debug_ll_ns16550.h @@ -59,9 +59,11 @@ static __inline__ void PUTC_LL(char ch) { +#ifdef CONFIG_DEBUG_LL while (!(__raw_readb((u8 *)DEBUG_LL_UART_ADDR + UART_LSR) & UART_LSR_THRE)) ; __raw_writeb(ch, (u8 *)DEBUG_LL_UART_ADDR + UART_THR); +#endif /* CONFIG_DEBUG_LL */ } #else /* __ASSEMBLY__ */ /* diff --git a/arch/mips/lib/barebox.lds.S b/arch/mips/lib/barebox.lds.S index bc78d2be8c..4ee4252b6d 100644 --- a/arch/mips/lib/barebox.lds.S +++ b/arch/mips/lib/barebox.lds.S @@ -69,6 +69,8 @@ SECTIONS __usymtab : { BAREBOX_SYMS } __usymtab_end = .; + .oftables : { BAREBOX_CLK_TABLE() } + .dtb : { BAREBOX_DTB() } _edata = .; diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig new file mode 100644 index 0000000000..96fffd3fa2 --- /dev/null +++ b/arch/mips/mach-ath79/Kconfig @@ -0,0 +1,15 @@ +if MACH_MIPS_ATH79 + +config ARCH_TEXT_BASE + hex + default 0xa0800000 + +choice + prompt "Board type" + +config BOARD_TPLINK_MR3020 + bool "TP-LINK MR3020" + +endchoice + +endif diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile new file mode 100644 index 0000000000..f3cc6684b8 --- /dev/null +++ b/arch/mips/mach-ath79/Makefile @@ -0,0 +1 @@ +obj-y += reset.o diff --git a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h new file mode 100644 index 0000000000..0c6ddd6388 --- /dev/null +++ b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h @@ -0,0 +1,64 @@ +/* + * Atheros AR71XX/AR724X/AR913X SoC register definitions + * + * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * + * 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. + */ + +#ifndef __ASM_MACH_AR71XX_REGS_H +#define __ASM_MACH_AR71XX_REGS_H + +#include <linux/bitops.h> + +#define AR71XX_APB_BASE 0x18000000 + +#define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) +#define AR71XX_PLL_SIZE 0x100 +#define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) +#define AR71XX_RESET_SIZE 0x100 + +#define AR933X_UART_BASE (AR71XX_APB_BASE + 0x00020000) +#define AR933X_UART_SIZE 0x14 + +/* + * PLL block + */ +#define AR933X_PLL_CPU_CONFIG_REG 0x00 +#define AR933X_PLL_CPU_CONFIG2_REG 0x04 +#define AR933X_PLL_CLOCK_CTRL_REG 0x08 +#define AR933X_PLL_DITHER_FRAC_REG 0x10 +#define AR933X_PLL_DITHER_REG 0x14 + +#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT 10 +#define AR933X_PLL_CPU_CONFIG_NINT_MASK 0x3f +#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT 16 +#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f +#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT 23 +#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK 0x7 + +#define AR933X_PLL_CLOCK_CTRL_BYPASS BIT(2) +#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT 5 +#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK 0x3 +#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT 10 +#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK 0x3 +#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 +#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 + +/* + * RESET block + */ +#define AR933X_RESET_REG_RESET_MODULE 0x1c +#define AR933X_RESET_REG_BOOTSTRAP 0xac + +#define AR71XX_RESET_FULL_CHIP BIT(24) + +#define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) + +#endif /* __ASM_MACH_AR71XX_REGS_H */ diff --git a/arch/mips/mach-ath79/include/mach/ath79.h b/arch/mips/mach-ath79/include/mach/ath79.h new file mode 100644 index 0000000000..ff53406fb0 --- /dev/null +++ b/arch/mips/mach-ath79/include/mach/ath79.h @@ -0,0 +1,33 @@ +/* + * Atheros AR71XX/AR724X/AR913X common definitions + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * Parts of this file are based on Atheros' 2.6.15 BSP + * + * 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. + */ + +#ifndef __ASM_MACH_ATH79_H +#define __ASM_MACH_ATH79_H + +#include <common.h> +#include <io.h> +#include <asm/memory.h> + +#include <mach/ar71xx_regs.h> + +static inline void ath79_reset_wr(unsigned reg, u32 val) +{ + __raw_writel(val, (char *)KSEG1ADDR(AR71XX_RESET_BASE + reg)); +} + +static inline u32 ath79_reset_rr(unsigned reg) +{ + return __raw_readl((char *)KSEG1ADDR(AR71XX_RESET_BASE + reg)); +} + +#endif /* __ASM_MACH_ATH79_H */ diff --git a/arch/mips/mach-ath79/include/mach/debug_ll.h b/arch/mips/mach-ath79/include/mach/debug_ll.h new file mode 100644 index 0000000000..de4c00dfd1 --- /dev/null +++ b/arch/mips/mach-ath79/include/mach/debug_ll.h @@ -0,0 +1,56 @@ +/* + * based on linux.git/drivers/tty/serial/ar933x_uart.c + * + * 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 __AR933X_DEBUG_LL__ +#define __AR933X_DEBUG_LL__ + +#include <io.h> +#include <linux/bitops.h> +#include <asm/addrspace.h> + +#include <mach/ar71xx_regs.h> + +#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_TX_CSR BIT(9) + +#define DEBUG_LL_UART_ADDR KSEG1ADDR(AR933X_UART_BASE) + +static inline void ar933x_debug_ll_writel(u32 b, int offset) +{ + cpu_writel(b, (u8 *)DEBUG_LL_UART_ADDR + offset); +} + +static inline u32 ar933x_debug_ll_readl(int offset) +{ + return cpu_readl((u8 *)DEBUG_LL_UART_ADDR + offset); +} + +static inline void PUTC_LL(int ch) +{ + u32 data; + + /* wait transmitter ready */ + data = ar933x_debug_ll_readl(AR933X_UART_DATA_REG); + while (!(data & AR933X_UART_DATA_TX_CSR)) + data = ar933x_debug_ll_readl(AR933X_UART_DATA_REG); + + data = (ch & AR933X_UART_DATA_TX_RX_MASK) | AR933X_UART_DATA_TX_CSR; + ar933x_debug_ll_writel(data, AR933X_UART_DATA_REG); +} + +#endif /* __AR933X_DEBUG_LL__ */ diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c new file mode 100644 index 0000000000..a0e9b349ca --- /dev/null +++ b/arch/mips/mach-ath79/reset.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Du Huanpeng <u74147@gmail.com> + * + * 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 <common.h> +#include <mach/ath79.h> + +void __noreturn reset_cpu(ulong addr) +{ + ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, AR71XX_RESET_FULL_CHIP); + /* + * Used to command a full chip reset. This is the software equivalent of + * pulling the reset pin. The system will reboot with PLL disabled. + * Always zero when read. + */ + unreachable(); + /*NOTREACHED*/ +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/mips/mach-malta/include/mach/hardware.h b/arch/mips/mach-malta/include/mach/hardware.h index 9345a67593..ba28cb86de 100644 --- a/arch/mips/mach-malta/include/mach/hardware.h +++ b/arch/mips/mach-malta/include/mach/hardware.h @@ -20,6 +20,9 @@ #define MALTA_PIIX4_UART0 0xb80003f8 +#define MALTA_CBUS_UART 0xbf000900 +#define MALTA_CBUS_UART_SHIFT 3 + /* * Reset register. */ diff --git a/arch/mips/mach-xburst/Makefile b/arch/mips/mach-xburst/Makefile index 3e0cd7324e..e5634ba9cc 100644 --- a/arch/mips/mach-xburst/Makefile +++ b/arch/mips/mach-xburst/Makefile @@ -1,2 +1 @@ -obj-y += serial.o obj-$(CONFIG_CPU_JZ4755) += csrc-jz4750.o reset-jz4750.o diff --git a/arch/mips/mach-xburst/mach-xburst.dox b/arch/mips/mach-xburst/mach-xburst.dox index a5e524d25c..052c05e7ae 100644 --- a/arch/mips/mach-xburst/mach-xburst.dox +++ b/arch/mips/mach-xburst/mach-xburst.dox @@ -2,6 +2,6 @@ @section xburst_boards XBurst-based boards -@li @subpage rzx50 +@li @subpage ritmix-rzx50 */ diff --git a/arch/mips/mach-xburst/serial.c b/arch/mips/mach-xburst/serial.c deleted file mode 100644 index acf5648467..0000000000 --- a/arch/mips/mach-xburst/serial.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> - * - * Based on the linux kernel JZ4740 serial support: - * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> - * - * 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 <common.h> -#include <ns16550.h> -#include <io.h> -#include <mach/devices.h> - -#define JZ_UART_SHIFT 2 - -#define ier (1 << JZ_UART_SHIFT) -#define fcr (2 << JZ_UART_SHIFT) - -static void jz_serial_reg_write(unsigned int val, unsigned long base, - unsigned char reg_offset) -{ - switch (reg_offset) { - case fcr: - val |= 0x10; /* Enable uart module */ - break; - case ier: - val |= (val & 0x4) << 2; - break; - default: - break; - } - - writeb(val & 0xff, (void *)(base + reg_offset)); -} - -struct device_d *jz_add_uart(int id, unsigned long base, unsigned int clock) -{ - struct NS16550_plat *serial_plat; - - serial_plat = xzalloc(sizeof(*serial_plat)); - - serial_plat->shift = JZ_UART_SHIFT; - serial_plat->reg_write = &jz_serial_reg_write; - serial_plat->clock = clock; - - return add_ns16550_device(id, base, 8 << JZ_UART_SHIFT, - IORESOURCE_MEM_8BIT, serial_plat); -} diff --git a/commands/Kconfig b/commands/Kconfig index 352e8bf46f..cc014f30ac 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -90,6 +90,14 @@ config CMD_MENU_MANAGEMENT depends on CMD_MENU prompt "menu scripts management" +config CMD_MENUTREE + bool + depends on MENU + select MENUTREE + prompt "menutree" + help + The menutree command allows to create a menu from a directory structure + config CMD_LOGIN tristate select PASSWORD diff --git a/commands/Makefile b/commands/Makefile index 91ec0e9fa9..e463031455 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -94,3 +94,4 @@ obj-$(CONFIG_CMD_DETECT) += detect.o obj-$(CONFIG_CMD_BOOT) += boot.o obj-$(CONFIG_CMD_DEVINFO) += devinfo.o obj-$(CONFIG_CMD_READF) += readf.o +obj-$(CONFIG_CMD_MENUTREE) += menutree.o diff --git a/commands/boot.c b/commands/boot.c index bb8d07fce4..4a839790d1 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -106,6 +106,11 @@ static void bootsource_action(struct menu *m, struct menu_entry *me) static int bootscript_create_entry(struct blspec *blspec, const char *name) { struct blspec_entry *be; + enum filetype type; + + type = file_name_detect_type(name); + if (type != filetype_sh) + return -EINVAL; be = blspec_entry_alloc(blspec); be->me.type = MENU_ENTRY_NORMAL; @@ -238,7 +243,7 @@ static struct blspec *bootentries_collect(char *entries[], int num_entries) static void bootsources_menu(char *entries[], int num_entries) { struct blspec *blspec = NULL; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; struct menu_entry *back_entry; if (!IS_ENABLED(CONFIG_MENU)) { @@ -247,10 +252,16 @@ static void bootsources_menu(char *entries[], int num_entries) } blspec = bootentries_collect(entries, num_entries); + if (blspec) + return; + + entry_default = blspec_entry_default(blspec); blspec_for_each_entry(blspec, entry) { entry->me.action = bootsource_action; menu_add_entry(blspec->menu, &entry->me); + if (entry == entry_default) + menu_set_selected_entry(blspec->menu, &entry->me); } back_entry = xzalloc(sizeof(*back_entry)); @@ -275,14 +286,23 @@ static void bootsources_menu(char *entries[], int num_entries) static void bootsources_list(char *entries[], int num_entries) { struct blspec *blspec; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; blspec = bootentries_collect(entries, num_entries); + if (!blspec) + return; + + entry_default = blspec_entry_default(blspec); - printf("%-20s %-20s %s\n", "device", "hwdevice", "title"); - printf("%-20s %-20s %s\n", "------", "--------", "-----"); + printf(" %-20s %-20s %s\n", "device", "hwdevice", "title"); + printf(" %-20s %-20s %s\n", "------", "--------", "-----"); blspec_for_each_entry(blspec, entry) { + if (entry == entry_default) + printf("* "); + else + printf(" "); + if (entry->scriptpath) printf("%-40s %s\n", basename(entry->scriptpath), entry->me.display); else @@ -307,7 +327,7 @@ static void bootsources_list(char *entries[], int num_entries) static int boot(const char *name) { struct blspec *blspec; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; int ret; blspec = blspec_alloc(); @@ -320,7 +340,19 @@ static int boot(const char *name) return -ENOENT; } + entry_default = blspec_entry_default(blspec); + if (entry_default) { + ret = boot_entry(entry_default); + if (!ret) + return ret; + printf("booting %s failed: %s\n", entry_default->me.display, + strerror(-ret)); + } + blspec_for_each_entry(blspec, entry) { + if (entry == entry_default) + continue; + printf("booting %s\n", entry->me.display); ret = boot_entry(entry); if (!ret) @@ -333,9 +365,11 @@ static int boot(const char *name) static int do_boot(int argc, char *argv[]) { - const char *sources = NULL; - char *source, *freep; + char *freep = NULL; int opt, ret = 0, do_list = 0, do_menu = 0; + char **sources; + int num_sources; + int i; verbose = 0; dryrun = 0; @@ -361,47 +395,62 @@ static int do_boot(int argc, char *argv[]) } } - if (do_list) { - bootsources_list(&argv[optind], argc - optind); - return 0; - } + if (optind < argc) { + num_sources = argc - optind; + sources = xmemdup(&argv[optind], sizeof(char *) * num_sources); + } else { + const char *def; + char *sep; - if (do_menu) { - bootsources_menu(&argv[optind], argc - optind); - return 0; - } + def = getenv("global.boot.default"); + if (!def) + return 0; - if (optind < argc) { - while (optind < argc) { - source = argv[optind]; - optind++; - ret = boot(source); - if (!ret) + sep = freep = xstrdup(def); + + num_sources = 0; + + while (1) { + num_sources++; + + sep = strchr(sep, ' '); + if (!sep) break; + sep++; + } + + sources = xmalloc(sizeof(char *) * num_sources); + + sep = freep; + + for (i = 0; i < num_sources; i++) { + sources[i] = sep; + sep = strchr(sep, ' '); + if (sep) + *sep = 0; + sep++; } - return ret; } - sources = getenv("global.boot.default"); - if (!sources) - return 0; + if (do_list) { + bootsources_list(sources, num_sources); + goto out; + } - freep = source = xstrdup(sources); + if (do_menu) { + bootsources_menu(sources, num_sources); + goto out; + } - while (1) { - char *sep = strchr(source, ' '); - if (sep) - *sep = 0; - ret = boot(source); + for (i = 0; i < num_sources; i++) { + ret = boot(sources[i]); if (!ret) break; - - if (sep) - source = sep + 1; - else - break; + goto out; } +out: + free(sources); free(freep); return ret; diff --git a/commands/menutree.c b/commands/menutree.c new file mode 100644 index 0000000000..3b1a263584 --- /dev/null +++ b/commands/menutree.c @@ -0,0 +1,60 @@ +/* + * 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 <command.h> +#include <common.h> +#include <getopt.h> +#include <menu.h> + +static int do_menutree(int argc, char *argv[]) +{ + int opt, ret; + char *path = "/env/menu"; + + while ((opt = getopt(argc, argv, "m:")) > 0) { + switch (opt) { + case 'm': + path = optarg; + break; + } + } + + ret = menutree(path, 1); + + return ret; +} + +BAREBOX_CMD_HELP_START(menutree) +BAREBOX_CMD_HELP_USAGE("menutree [OPTIONS]\n") +"\n" +"Create a menu from a directory structure\n" +"Each menu entry is described by a subdirectory. Each subdirectory\n" +"can contain the following files which further describe the entry:\n" +"\n" +"title - A file containing the title of the entry as shown in the menu\n" +"box - If present, the entry is a 'bool' entry. The file contains a variable\n" +" name from which the current state of the bool is taken from and saved\n" +" to.\n" +"action - if present this file contains a shell script which is executed when\n" +" when the entry is selected.\n" +"If neither 'box' or 'action' are present this entry is considered a submenu\n" +"containing more entries.\n" +"\n" +"Options:\n" +" -m <dir> directory where the menu starts (/env/menu)\n" + +BAREBOX_CMD_HELP_END + + +BAREBOX_CMD_START(menutree) + .cmd = do_menutree, + .usage = "create a menu from a directory structure", + BAREBOX_CMD_HELP(cmd_menutree_help) +BAREBOX_CMD_END diff --git a/commands/nandtest.c b/commands/nandtest.c index 0da5444c02..c64f2443a8 100644 --- a/commands/nandtest.c +++ b/commands/nandtest.c @@ -277,7 +277,7 @@ static int do_nandtest(int argc, char *argv[]) } if (length + flash_offset > meminfo.size) { printf("Length 0x%08llx + offset 0x%08llx exceeds " - "device size 0x%08x\n", length, + "device size 0x%08llx\n", length, flash_offset, meminfo.size); goto err; } diff --git a/commands/partition.c b/commands/partition.c index 6d37471f4f..44b91d1a13 100644 --- a/commands/partition.c +++ b/commands/partition.c @@ -42,10 +42,11 @@ #define PART_ADD_DEVNAME (1 << 0) static int mtd_part_do_parse_one(char *devname, const char *partstr, - char **endp, unsigned long *offset, - off_t devsize, size_t *retsize, unsigned int pflags) + char **endp, loff_t *offset, + loff_t devsize, size_t *retsize, + unsigned int pflags) { - ulong size; + loff_t size; char *end; char buf[PATH_MAX] = {}; unsigned long flags = 0; @@ -58,11 +59,11 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr, size = SIZE_REMAINING; end = (char *)partstr + 1; } else { - size = strtoul_suffix(partstr, &end, 0); + size = strtoull_suffix(partstr, &end, 0); } if (*end == '@') - *offset = strtoul_suffix(end+1, &end, 0); + *offset = strtoull_suffix(end+1, &end, 0); if (size == SIZE_REMAINING) size = devsize - *offset; @@ -114,8 +115,8 @@ static int do_addpart(int argc, char *argv[]) { char *devname; char *endp; - unsigned long offset = 0; - off_t devsize; + loff_t offset = 0; + loff_t devsize; struct stat s; int opt; unsigned int flags = PART_ADD_DEVNAME; diff --git a/commands/trigger.c b/commands/trigger.c index 85f16b00bb..de50bddb05 100644 --- a/commands/trigger.c +++ b/commands/trigger.c @@ -34,6 +34,7 @@ static char *trigger_names[] = { [LED_TRIGGER_NET_RX] = "net rx", [LED_TRIGGER_NET_TX] = "net tx", [LED_TRIGGER_NET_TXRX] = "net", + [LED_TRIGGER_DEFAULT_ON] = "default on", }; static int do_trigger(int argc, char *argv[]) diff --git a/commands/ubi.c b/commands/ubi.c index 57ae79025d..8a409c28a8 100644 --- a/commands/ubi.c +++ b/commands/ubi.c @@ -15,12 +15,12 @@ static int do_ubimkvol(int argc, char *argv[]) { struct ubi_mkvol_req req; int fd, ret; - size_t size; + uint64_t size; if (argc != 4) return COMMAND_ERROR_USAGE; - size = strtoul_suffix(argv[3], NULL, 0); + size = strtoull_suffix(argv[3], NULL, 0); req.name_len = min_t(int, strlen(argv[2]), UBI_VOL_NAME_MAX); strncpy(req.name, argv[2], req.name_len); req.name[req.name_len] = 0; diff --git a/common/Kconfig b/common/Kconfig index 5989502a75..0031cc8770 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -62,6 +62,9 @@ config STDDEV config BAREBOX_UPDATE bool +config MENUTREE + bool + menu "General Settings" config LOCALVERSION @@ -602,7 +605,7 @@ config DEFAULT_ENVIRONMENT_GENERIC_NEW config DEFAULT_ENVIRONMENT_GENERIC_NEW_MENU bool depends on DEFAULT_ENVIRONMENT_GENERIC_NEW - depends on CONFIG_CMD_MENU_MANAGEMENT + depends on CMD_MENUTREE default y config DEFAULT_ENVIRONMENT_GENERIC_NEW_DFU diff --git a/common/Makefile b/common/Makefile index 667c7b36ba..204241c919 100644 --- a/common/Makefile +++ b/common/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o obj-$(CONFIG_SHELL_HUSH) += hush.o obj-$(CONFIG_SHELL_SIMPLE) += parser.o obj-$(CONFIG_UIMAGE) += image.o uimage.o +obj-$(CONFIG_MENUTREE) += menutree.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/blspec.c b/common/blspec.c index 9b4b096a0a..f165b77aaa 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -235,6 +235,78 @@ out: } /* + * entry_is_of_compatible - check if a bootspec entry is compatible with + * the current machine. + * + * returns true is the entry is compatible, false otherwise + */ +static bool entry_is_of_compatible(struct blspec_entry *entry) +{ + const char *devicetree; + const char *abspath; + size_t size; + void *fdt = NULL; + int ret; + struct device_node *root = NULL, *barebox_root; + const char *compat; + char *filename; + + /* If we don't have a root node every entry is compatible */ + barebox_root = of_get_root_node(); + if (!barebox_root) + return true; + + ret = of_property_read_string(barebox_root, "compatible", &compat); + if (ret) + return false; + + if (entry->rootpath) + abspath = entry->rootpath; + else + abspath = ""; + + /* If the entry doesn't specifiy a devicetree we are compatible */ + devicetree = blspec_entry_var_get(entry, "devicetree"); + if (!devicetree) + return true; + + if (!strcmp(devicetree, "none")) + return true; + + filename = asprintf("%s/%s", abspath, devicetree); + + fdt = read_file(filename, &size); + if (!fdt) { + ret = false; + goto out; + } + + root = of_unflatten_dtb(NULL, fdt); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + + if (of_device_is_compatible(root, compat)) { + ret = true; + goto out; + } + + pr_info("ignoring entry with incompatible devicetree \"%s\"\n", + (char *)of_get_property(root, "compatible", &size)); + + ret = false; + +out: + if (root) + of_delete_node(root); + free(filename); + free(fdt); + + return ret; +} + +/* * blspec_scan_directory - scan over a directory * * Given a root path collects all blspec entries found under /blspec/entries/. @@ -313,12 +385,17 @@ int blspec_scan_directory(struct blspec *blspec, const char *root) continue; } - found++; - entry->rootpath = xstrdup(root); entry->configpath = configname; entry->cdev = get_cdev_by_mountpath(root); + if (!entry_is_of_compatible(entry)) { + blspec_entry_free(entry); + continue; + } + + found++; + name = asprintf("%s/%s", dirname, d->d_name); if (entry_default && !strcmp(name, entry_default)) entry->boot_default = true; diff --git a/common/environment.c b/common/environment.c index 776fa3ad38..9f4e098285 100644 --- a/common/environment.c +++ b/common/environment.c @@ -253,9 +253,9 @@ static int envfs_check_data(struct envfs_super *super, const void *buf, size_t s return 0; } -static int envfs_load_data(void *buf, size_t size, const char *dir, unsigned flags) +static int envfs_load_data(struct envfs_super *super, void *buf, size_t size, + const char *dir, unsigned flags) { - struct envfs_super super; int fd, ret = 0; char *str, *tmp; int headerlen_full; @@ -281,7 +281,7 @@ static int envfs_load_data(void *buf, size_t size, const char *dir, unsigned fla inode_size = ENVFS_32(inode->size); inode_headerlen = ENVFS_32(inode->headerlen); namelen = strlen(inode->data) + 1; - if (super.major < 1) + if (super->major < 1) inode_end = &inode_end_dummy; else inode_end = (struct envfs_inode_end *)(buf + PAD4(namelen)); @@ -363,7 +363,7 @@ int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags) if (ret) return ret; - ret = envfs_load_data(buf, size, dir, flags); + ret = envfs_load_data(super, buf, size, dir, flags); return ret; } @@ -415,7 +415,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags) if (ret) goto out; - ret = envfs_load_data(buf, size, dir, flags); + ret = envfs_load_data(&super, buf, size, dir, flags); if (ret) goto out; diff --git a/common/hush.c b/common/hush.c index bd534c12f5..1447fdb7f1 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1637,6 +1637,39 @@ static void update_ifs_map(void) mapset(ifs, 2); /* also flow through if quoted */ } +/* + * shell_expand - Expand shell variables in a string. + * @str: The input string containing shell variables like + * $var or ${var} + * Return: The expanded string. Must be freed with free(). + */ +char *shell_expand(char *str) +{ + struct p_context ctx = {}; + o_string o = {}; + char *res, *parsed; + + remove_quotes_in_str(str); + + o.quote = 1; + + initialize_context(&ctx); + + parse_string(&o, &ctx, str); + + parsed = xmemdup(o.data, o.length + 1); + parsed[o.length] = 0; + + res = insert_var_value(parsed); + if (res != parsed) + free(parsed); + + free_pipe_list(ctx.list_head, 0); + b_free(&o); + + return res; +} + /* most recursion does not come through here, the exeception is * from builtin_source() */ static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int flag) diff --git a/common/menutree.c b/common/menutree.c new file mode 100644 index 0000000000..814512d7b7 --- /dev/null +++ b/common/menutree.c @@ -0,0 +1,181 @@ +/* + * 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 <environment.h> +#include <libbb.h> +#include <common.h> +#include <glob.h> +#include <menu.h> +#include <fs.h> + +#include <linux/stat.h> + +struct menutree { + char *action; + struct menu_entry me; +}; + +static void menutree_action_subdir(struct menu *m, struct menu_entry *me) +{ + struct menutree *mt = container_of(me, struct menutree, me); + + menutree(mt->action, 0); +} + +static void menutree_action(struct menu *m, struct menu_entry *me) +{ + struct menutree *mt = container_of(me, struct menutree, me); + + run_command(mt->action); +} + +static void setenv_bool(const char *var, bool val) +{ + const char *str; + + if (val) + str = "1"; + else + str = "0"; + + setenv(var, str); +} + +static void menutree_box(struct menu *m, struct menu_entry *me) +{ + struct menutree *mt = container_of(me, struct menutree, me); + + setenv_bool(mt->action, me->box_state); +} + +static void menutree_entry_free(struct menu_entry *me) +{ + struct menutree *mt = container_of(me, struct menutree, me); + + free(mt->action); + free(mt->me.display); + free(mt); +} + +/* + * menutree - show a menu constructed from a directory structure + * @path: the path to the directory structure + * + * Each menu entry is described by a subdirectory. Each subdirectory + * can contain the following files which further describe the entry: + * + * title - A file containing the title of the entry as shown in the menu + * box - If present, the entry is a 'bool' entry. The file contains a variable + * name from which the current state of the bool is taken from and saved + * to. + * action - if present this file contains a shell script which is executed when + * when the entry is selected. + * + * If neither 'box' or 'action' are present this entry is considered a submenu + * containing more entries. + */ +int menutree(const char *path, int toplevel) +{ + int ret; + struct menu *menu; + struct stat s; + char *box; + struct menutree *mt; + glob_t g; + int i; + char *globpath, *display; + + menu = menu_alloc(); + + globpath = asprintf("%s/*", path); + ret = glob(globpath, 0, NULL, &g); + free(globpath); + if (ret == GLOB_NOMATCH) { + ret = -EINVAL; + goto out; + } + + display = read_file_line("%s/title", path); + if (!display) { + eprintf("no title found in %s/title\n", path); + ret = -EINVAL; + goto out; + } + + menu->display = shell_expand(display); + free(display); + + for (i = 0; i < g.gl_pathc; i++) { + ret = stat(g.gl_pathv[i], &s); + if (ret) + goto out; + + if (!S_ISDIR(s.st_mode)) + continue; + + mt = xzalloc(sizeof(*mt)); + + display = read_file_line("%s/title", g.gl_pathv[i]); + if (!display) { + eprintf("no title found in %s/title\n", g.gl_pathv[i]); + ret = -EINVAL; + goto out; + } + + mt->me.display = shell_expand(display); + free(display); + mt->me.free = menutree_entry_free; + + box = read_file_line("%s/box", g.gl_pathv[i]); + if (box) { + mt->me.type = MENU_ENTRY_BOX; + mt->me.action = menutree_box; + mt->action = box; + getenv_bool(box, &mt->me.box_state); + menu_add_entry(menu, &mt->me); + continue; + } + + mt->me.type = MENU_ENTRY_NORMAL; + + mt->action = asprintf("%s/action", g.gl_pathv[i]); + + ret = stat(mt->action, &s); + if (ret) { + mt->me.action = menutree_action_subdir; + free(mt->action); + mt->action = xstrdup(g.gl_pathv[i]); + } else { + mt->me.action = menutree_action; + } + + menu_add_entry(menu, &mt->me); + } + + if (!toplevel) { + mt = xzalloc(sizeof(*mt)); + mt->me.display = xstrdup("back"); + mt->me.type = MENU_ENTRY_NORMAL; + mt->me.non_re_ent = 1; + mt->me.free = menutree_entry_free; + menu_add_entry(menu, &mt->me); + } + + menu_show(menu); + + ret = 0; +out: + menu_free(menu); + + globfree(&g); + + return ret; +} diff --git a/defaultenv/defaultenv-2-menu/menu/00-boot-default/action b/defaultenv/defaultenv-2-menu/menu/00-boot-default/action new file mode 100644 index 0000000000..3d72ff6523 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/00-boot-default/action @@ -0,0 +1,5 @@ +#!/bin/sh + +boot + +readline "Booting failed. Press any key to continue" ignore diff --git a/defaultenv/defaultenv-2-menu/menu/00-boot-default/title b/defaultenv/defaultenv-2-menu/menu/00-boot-default/title new file mode 100644 index 0000000000..ef8c3dd1af --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/00-boot-default/title @@ -0,0 +1 @@ +Boot default diff --git a/defaultenv/defaultenv-2-menu/menu/10-boot-all/action b/defaultenv/defaultenv-2-menu/menu/10-boot-all/action new file mode 100644 index 0000000000..a890ffe380 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/10-boot-all/action @@ -0,0 +1,3 @@ +#!/bin/sh + +boot -m diff --git a/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/action b/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/action new file mode 100644 index 0000000000..b31b0e409d --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/action @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "Boot from Network...." + +sleep 3 diff --git a/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/title b/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/title new file mode 100644 index 0000000000..79a6d8ffde --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/10-boot-all/net/title @@ -0,0 +1 @@ +Boot from network diff --git a/defaultenv/defaultenv-2-menu/menu/10-boot-all/title b/defaultenv/defaultenv-2-menu/menu/10-boot-all/title new file mode 100644 index 0000000000..0f05e98eab --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/10-boot-all/title @@ -0,0 +1 @@ +Detect bootsources diff --git a/defaultenv/defaultenv-2-menu/menu/20-settings/config/action b/defaultenv/defaultenv-2-menu/menu/20-settings/config/action new file mode 100644 index 0000000000..9a993af9de --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/20-settings/config/action @@ -0,0 +1,5 @@ +#!/bin/sh + +edit /env/config + +/env/config diff --git a/defaultenv/defaultenv-2-menu/menu/20-settings/config/title b/defaultenv/defaultenv-2-menu/menu/20-settings/config/title new file mode 100644 index 0000000000..a8955a90c3 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/20-settings/config/title @@ -0,0 +1 @@ +Config settings diff --git a/defaultenv/defaultenv-2-menu/menu/20-settings/network/action b/defaultenv/defaultenv-2-menu/menu/20-settings/network/action new file mode 100644 index 0000000000..d27a77f706 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/20-settings/network/action @@ -0,0 +1,3 @@ +#!/bin/sh + +edit /env/network/eth0 diff --git a/defaultenv/defaultenv-2-menu/menu/20-settings/network/title b/defaultenv/defaultenv-2-menu/menu/20-settings/network/title new file mode 100644 index 0000000000..4641d480ea --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/20-settings/network/title @@ -0,0 +1 @@ +Network settings diff --git a/defaultenv/defaultenv-2-menu/menu/20-settings/title b/defaultenv/defaultenv-2-menu/menu/20-settings/title new file mode 100644 index 0000000000..163d304af4 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/20-settings/title @@ -0,0 +1 @@ +Settings diff --git a/defaultenv/defaultenv-2-menu/menu/30-saveenv/action b/defaultenv/defaultenv-2-menu/menu/30-saveenv/action new file mode 100644 index 0000000000..c6aed70912 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/30-saveenv/action @@ -0,0 +1,8 @@ +#!/bin/sh + +saveenv +if [ $? != 0 ]; then + echo "saving environment failed" +fi + +sleep 2 diff --git a/defaultenv/defaultenv-2-menu/menu/30-saveenv/title b/defaultenv/defaultenv-2-menu/menu/30-saveenv/title new file mode 100644 index 0000000000..8ae292d6b5 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/30-saveenv/title @@ -0,0 +1 @@ +Save environment diff --git a/defaultenv/defaultenv-2-menu/menu/40-shell/action b/defaultenv/defaultenv-2-menu/menu/40-shell/action new file mode 100644 index 0000000000..fd5bc2b0c4 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/40-shell/action @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "Enter 'exit' to get back to the menu" + +sh diff --git a/defaultenv/defaultenv-2-menu/menu/40-shell/title b/defaultenv/defaultenv-2-menu/menu/40-shell/title new file mode 100644 index 0000000000..6567bb2d9e --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/40-shell/title @@ -0,0 +1 @@ +Shell diff --git a/defaultenv/defaultenv-2-menu/menu/50-reset/action b/defaultenv/defaultenv-2-menu/menu/50-reset/action new file mode 100644 index 0000000000..61d5c9a965 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/50-reset/action @@ -0,0 +1,3 @@ +#!/bin/sh + +reset diff --git a/defaultenv/defaultenv-2-menu/menu/50-reset/title b/defaultenv/defaultenv-2-menu/menu/50-reset/title new file mode 100644 index 0000000000..6d9fd4d6bf --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/50-reset/title @@ -0,0 +1 @@ +Reset diff --git a/defaultenv/defaultenv-2-menu/menu/boot-entries-collect b/defaultenv/defaultenv-2-menu/menu/boot-entries-collect deleted file mode 100644 index c066c930ab..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/boot-entries-collect +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -cd /env/boot - -./$global.boot.default menu - -for i in *; do - if [ "$i" != "$global.boot.default" ]; then - ./$i menu - fi -done - -cd / diff --git a/defaultenv/defaultenv-2-menu/menu/boot-entries-edit b/defaultenv/defaultenv-2-menu/menu/boot-entries-edit deleted file mode 100644 index c4e1c3d5fd..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/boot-entries-edit +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -export menu_exit=false - -while true; do - menu -a -m boot_entries_edit -d "\e[1;36mEdit boot entries\e[0m" - - boot-entries-collect - - menu -e -a -m boot_entries_edit -c "boot-menu-new-boot-entry" -d "Add a new entry" - menu -e -a -m boot_entries_edit -c "boot-entries-remove" -d "Remove an entry" - menu -e -a -m boot_entries_edit -c "menu_exit=true" -d "back" - - menu -s -m boot_entries_edit - menu -r -m boot_entries_edit - - if [ $menu_exit = true ]; then - exit - fi -done diff --git a/defaultenv/defaultenv-2-menu/menu/boot-entries-remove b/defaultenv/defaultenv-2-menu/menu/boot-entries-remove deleted file mode 100644 index 566be9dd6e..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/boot-entries-remove +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -export menu_exit=false - -while true; do - menu -a -m boot_entries_remove -d "\e[1;36mRemove Boot entry\e[0m" - - boot-entries-collect - - menu -e -a -m boot_entries_remove -c "menu_exit=true" -d "back" - - menu -s -m boot_entries_remove - menu -r -m boot_entries_remove - - if [ $menu_exit = true ]; then - exit - fi -done diff --git a/defaultenv/defaultenv-2-menu/menu/boot-menu-add-entry b/defaultenv/defaultenv-2-menu/menu/boot-menu-add-entry deleted file mode 100644 index f06c524034..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/boot-menu-add-entry +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -menu -e -a -m boot -c "boot -v $1; echo; readline \"press enter to continue\" a " -d "Boot: ${GREEN}$2${NC}" -menu -e -a -m boot_entries_edit -c "$global.editcmd /env/boot/$1" -d "${GREEN}$2${NC}" -menu -e -a -m boot_entries_remove -c "rm /env/boot/$1" -d "${GREEN}$2${NC}" diff --git a/defaultenv/defaultenv-2-menu/menu/boot-menu-new-boot-entry b/defaultenv/defaultenv-2-menu/menu/boot-menu-new-boot-entry deleted file mode 100644 index c5e982cdb2..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/boot-menu-new-boot-entry +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -name= - -readline "Name of the new entry: " name - -if [ -z "$name" ]; then - exit 1 -fi - -if [ -e "/env/boot/$name" ]; then - echo "entry $name already exists" - readline "<enter>" unused - exit 1 -fi - -cp /env/data/boot-template /env/boot/$name - -edit /env/boot/$name - -boot-menu-show rebuild diff --git a/defaultenv/defaultenv-2-menu/menu/init-entries-collect b/defaultenv/defaultenv-2-menu/menu/init-entries-collect deleted file mode 100644 index dbb775779a..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/init-entries-collect +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -cd /env/init - -for i in *; do - ./$i menu -done - -cd / diff --git a/defaultenv/defaultenv-2-menu/menu/init-entries-edit b/defaultenv/defaultenv-2-menu/menu/init-entries-edit deleted file mode 100644 index fc02b327d9..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/init-entries-edit +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -export menu_exit=false - -while true; do - menu -a -m init_entries_edit -d "\e[1;36mEdit init entries\e[0m" - - menu -e -a -m init_entries_edit -R -c "true" -d ">> Reset board to let changes here take effect <<" - - init-entries-collect - - menu -e -a -m init_entries_edit -c "menu_exit=true" -d "back" - - menu -s -m init_entries_edit - menu -r -m init_entries_edit - - if [ $menu_exit = true ]; then - exit - fi -done diff --git a/defaultenv/defaultenv-2-menu/menu/init-menu-add-entry b/defaultenv/defaultenv-2-menu/menu/init-menu-add-entry deleted file mode 100644 index 7cb5686402..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/init-menu-add-entry +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -menu -e -a -m init_entries_edit -c "$global.editcmd /env/init/$1" -d "\e[1;32m$2\e[0m" diff --git a/defaultenv/defaultenv-2-menu/menu/mainmenu b/defaultenv/defaultenv-2-menu/menu/mainmenu index f10f67a62f..98039472bd 100644 --- a/defaultenv/defaultenv-2-menu/menu/mainmenu +++ b/defaultenv/defaultenv-2-menu/menu/mainmenu @@ -1,23 +1,5 @@ #!/bin/sh -savepath=$PATH -export menupath=$PATH:/env/menu - . /env/data/ansi-colors -while true; do - export PATH=${menupath} - - echo $PATH - - menu -a -m boot -d "${CYAN}Welcome to Barebox${NC}" - - boot-entries-collect - - menu -e -a -m boot -c "settings" -d "Settings" - menu -e -a -m boot -c 'PATH=$savepath; echo "enter exit to return to menu"; sh' -d "${DARK_YELLOW}Shell${NC}" - menu -e -a -m boot -c reset -d "${RED}Reset${NC}" - - menu -s -m boot - menu -r -m boot -done +menutree diff --git a/defaultenv/defaultenv-2-menu/menu/settings b/defaultenv/defaultenv-2-menu/menu/settings deleted file mode 100644 index db619afa6f..0000000000 --- a/defaultenv/defaultenv-2-menu/menu/settings +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -export menu_exit=false - -while true; do - menu -a -m settings -d "${CYAN}Settings${NC}" - - menu -e -a -R -m settings -c "$global.editcmd /env/network/eth0" -d "Network settings" - menu -e -a -R -m settings -c "$global.editcmd /env/config" -d "Config settings" - menu -e -a -m settings -c "boot-entries-edit" -d "Edit boot entries" - menu -e -a -m settings -c "init-entries-edit" -d "Edit init entries" - menu -e -a -R -m settings -c "saveenv || echo \"failed to save environment\" && sleep 2" -d "Save settings" - menu -e -a -m settings -c "menu_exit=true" -d "back" - - menu -s -m settings - menu -r -m settings - - if [ $menu_exit = true ]; then - exit - fi -done diff --git a/defaultenv/defaultenv-2-menu/menu/title b/defaultenv/defaultenv-2-menu/menu/title new file mode 100644 index 0000000000..f3c47b5d12 --- /dev/null +++ b/defaultenv/defaultenv-2-menu/menu/title @@ -0,0 +1 @@ +${RED}Main menu${NC} diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f5c05920b1..0687b3cddd 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,8 +1,9 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o \ - clk-mux.o clk-gate.o clk-divider-table.o + clk-mux.o clk-gate.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_ARCH_MVEBU) += mvebu/ obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_CLK_SOCFPGA) += socfpga.o +obj-$(CONFIG_MACH_MIPS_ATH79) += clk-ar933x.o diff --git a/drivers/clk/clk-ar933x.c b/drivers/clk/clk-ar933x.c new file mode 100644 index 0000000000..d983387a93 --- /dev/null +++ b/drivers/clk/clk-ar933x.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2013 Lucas Stach <l.stach@pengutronix.de> + * + * Based on the Linux Tegra clock code + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <common.h> +#include <init.h> +#include <io.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/ath79.h> +#include <dt-bindings/clock/ar933x-clk.h> + +static struct clk *clks[AR933X_CLK_END]; +static struct clk_onecell_data clk_data; + +struct clk_ar933x { + struct clk clk; + void __iomem *base; + u32 div_shift; + u32 div_mask; + const char *parent; +}; + +static unsigned long clk_ar933x_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_ar933x *f = container_of(clk, struct clk_ar933x, clk); + unsigned long rate; + unsigned long freq; + u32 clock_ctrl; + u32 cpu_config; + u32 t; + + clock_ctrl = __raw_readl(f->base + AR933X_PLL_CLOCK_CTRL_REG); + + if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { + rate = parent_rate; + } else { + cpu_config = __raw_readl(f->base + AR933X_PLL_CPU_CONFIG_REG); + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & + AR933X_PLL_CPU_CONFIG_REFDIV_MASK; + freq = parent_rate / t; + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & + AR933X_PLL_CPU_CONFIG_NINT_MASK; + freq *= t; + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & + AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; + if (t == 0) + t = 1; + + freq >>= t; + + t = ((clock_ctrl >> f->div_shift) & f->div_mask) + 1; + rate = freq / t; + } + + return rate; +} + +struct clk_ops clk_ar933x_ops = { + .recalc_rate = clk_ar933x_recalc_rate, +}; + +static struct clk *clk_ar933x(const char *name, const char *parent, + void __iomem *base, u32 div_shift, u32 div_mask) +{ + struct clk_ar933x *f = xzalloc(sizeof(*f)); + + f->parent = parent; + f->base = base; + f->div_shift = div_shift; + f->div_mask = div_mask; + + f->clk.ops = &clk_ar933x_ops; + f->clk.name = name; + f->clk.parent_names = &f->parent; + f->clk.num_parents = 1; + + clk_register(&f->clk); + + return &f->clk; +} + +static void ar933x_ref_clk_init(void __iomem *base) +{ + u32 t; + unsigned long ref_rate; + + t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); + if (t & AR933X_BOOTSTRAP_REF_CLK_40) + ref_rate = (40 * 1000 * 1000); + else + ref_rate = (25 * 1000 * 1000); + + clks[AR933X_CLK_REF] = clk_fixed("ref", ref_rate); +} + +static void ar933x_pll_init(void __iomem *base) +{ + clks[AR933X_CLK_UART] = clk_fixed_factor("uart", "ref", 1, 1, + CLK_SET_RATE_PARENT); + + clks[AR933X_CLK_CPU] = clk_ar933x("cpu", "ref", base, + AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT, + AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK); + + clks[AR933X_CLK_DDR] = clk_ar933x("ddr", "ref", base, + AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT, + AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK); + + clks[AR933X_CLK_AHB] = clk_ar933x("ahb", "ref", base, + AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT, + AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK); + + clks[AR933X_CLK_WDT] = clk_fixed_factor("wdt", "ahb", 1, 1, + CLK_SET_RATE_PARENT); +} + +static int ar933x_clk_probe(struct device_d *dev) +{ + void __iomem *base; + + base = dev_request_mem_region(dev, 0); + if (!base) + return -EBUSY; + + ar933x_ref_clk_init(base); + ar933x_pll_init(base); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(dev->device_node, of_clk_src_onecell_get, + &clk_data); + + return 0; +} + +static __maybe_unused struct of_device_id ar933x_clk_dt_ids[] = { + { + .compatible = "qca,ar933x-clk", + }, { + /* sentinel */ + } +}; + +static struct driver_d ar933x_clk_driver = { + .probe = ar933x_clk_probe, + .name = "ar933x_clk", + .of_compatible = DRV_OF_COMPAT(ar933x_clk_dt_ids), +}; + +static int ar933x_clk_init(void) +{ + return platform_driver_register(&ar933x_clk_driver); +} +postcore_initcall(ar933x_clk_init); diff --git a/drivers/clk/clk-divider-table.c b/drivers/clk/clk-divider-table.c deleted file mode 100644 index fd2d3fc3c1..0000000000 --- a/drivers/clk/clk-divider-table.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * clk-divider-table.c - generic barebox clock support. Based on Linux clk support - * - * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * 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. - * - */ -#include <common.h> -#include <io.h> -#include <malloc.h> -#include <linux/clk.h> -#include <linux/err.h> - -struct clk_divider_table { - struct clk clk; - u8 shift; - u8 width; - void __iomem *reg; - const char *parent; - const struct clk_div_table *table; - int table_size; - int max_div_index; -}; - -static int clk_divider_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_divider_table *div = - container_of(clk, struct clk_divider_table, clk); - unsigned int val; - int i, div_index = -1; - unsigned long best = 0; - - if (rate > parent_rate) - rate = parent_rate; - if (rate < parent_rate / div->table[div->max_div_index].div) - rate = parent_rate / div->table[div->max_div_index].div; - - for (i = 0; i < div->table_size; i++) { - unsigned long now = parent_rate / div->table[i].div; - - if (now <= rate && now >= best) { - best = now; - div_index = i; - } - } - - val = readl(div->reg); - val &= ~(((1 << div->width) - 1) << div->shift); - val |= div_index << div->shift; - writel(val, div->reg); - - return 0; -} - -static unsigned long clk_divider_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_divider_table *div = - container_of(clk, struct clk_divider_table, clk); - unsigned int val; - - val = readl(div->reg) >> div->shift; - val &= (1 << div->width) - 1; - - if (val >= div->table_size) - return 0; - - return parent_rate / div->table[val].div; -} - -static struct clk_ops clk_divider_table_ops = { - .set_rate = clk_divider_set_rate, - .recalc_rate = clk_divider_recalc_rate, -}; - -struct clk *clk_divider_table(const char *name, - const char *parent, void __iomem *reg, u8 shift, u8 width, - const struct clk_div_table *table) -{ - struct clk_divider_table *div = xzalloc(sizeof(*div)); - const struct clk_div_table *clkt; - int ret, max_div = 0; - - div->shift = shift; - div->reg = reg; - div->width = width; - div->parent = parent; - div->clk.ops = &clk_divider_table_ops; - div->clk.name = name; - div->clk.parent_names = &div->parent; - div->clk.num_parents = 1; - div->table = table; - - for (clkt = div->table; clkt->div; clkt++) { - if (clkt->div > max_div) { - max_div = clkt->div; - div->max_div_index = div->table_size; - } - div->table_size++; - } - - ret = clk_register(&div->clk); - if (ret) { - free(div); - return ERR_PTR(ret); - } - - return &div->clk; -} diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 3bf8105a8b..67783daabb 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -20,65 +20,196 @@ #include <linux/clk.h> #include <linux/err.h> -static unsigned int clk_divider_maxdiv(struct clk_divider *div) +#define div_mask(d) ((1 << ((d)->width)) - 1) + +static unsigned int _get_maxdiv(struct clk_divider *divider) { - if (div->flags & CLK_DIVIDER_ONE_BASED) - return (1 << div->width) - 1; - return 1 << div->width; + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div_mask(divider); + return div_mask(divider) + 1; } -static int clk_divider_set_rate(struct clk *clk, unsigned long rate, +static unsigned int _get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int _get_div(struct clk_divider *divider, unsigned int val) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return val; + if (divider->table) + return _get_table_div(divider->table, val); + return val + 1; +} + +static unsigned int _get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned int _get_val(struct clk_divider *divider, unsigned int div) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div; + if (divider->table) + return _get_table_val(divider->table, div); + return div - 1; +} + +static unsigned long clk_divider_recalc_rate(struct clk *clk, unsigned long parent_rate) { - struct clk_divider *div = container_of(clk, struct clk_divider, clk); - unsigned int val, divval; + struct clk_divider *divider = container_of(clk, struct clk_divider, clk); + unsigned int div, val; + + val = readl(divider->reg) >> divider->shift; + val &= div_mask(divider); + + div = _get_div(divider, val); + + return parent_rate / div; +} + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +static bool _is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static bool _is_valid_div(struct clk_divider *divider, unsigned int div) +{ + if (divider->table) + return _is_valid_table_div(divider->table, div); + return true; +} + +static int clk_divider_bestdiv(struct clk *clk, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = container_of(clk, struct clk_divider, clk); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + unsigned long parent_rate_saved = *best_parent_rate; - if (rate > parent_rate) - rate = parent_rate; if (!rate) rate = 1; - divval = DIV_ROUND_UP(parent_rate, rate); - if (divval > clk_divider_maxdiv(div)) - divval = clk_divider_maxdiv(div); + maxdiv = _get_maxdiv(divider); - if (!(div->flags & CLK_DIVIDER_ONE_BASED)) - divval--; + if (!(clk->flags & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } - val = readl(div->reg); - val &= ~(((1 << div->width) - 1) << div->shift); - val |= divval << div->shift; - writel(val, div->reg); + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); - return 0; + for (i = 1; i <= maxdiv; i++) { + if (!_is_valid_div(divider, i)) + continue; + if (rate * i == parent_rate_saved) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return i; + } + parent_rate = clk_round_rate(clk_get_parent(clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = _get_maxdiv(divider); + *best_parent_rate = clk_round_rate(clk_get_parent(clk), 1); + } + + return bestdiv; } -static unsigned long clk_divider_recalc_rate(struct clk *clk, - unsigned long parent_rate) +static long clk_divider_round_rate(struct clk *clk, unsigned long rate, + unsigned long *parent_rate) { - struct clk_divider *div = container_of(clk, struct clk_divider, clk); - unsigned int val; + int div; - val = readl(div->reg) >> div->shift; - val &= (1 << div->width) - 1; + div = clk_divider_bestdiv(clk, rate, parent_rate); - if (div->flags & CLK_DIVIDER_ONE_BASED) { - if (!val) - val++; + return *parent_rate / div; +} + +static int clk_divider_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = container_of(clk, struct clk_divider, clk); + unsigned int div, value; + u32 val; + + if (clk->flags & CLK_SET_RATE_PARENT) { + unsigned long best_parent_rate = parent_rate; + div = clk_divider_bestdiv(clk, rate, &best_parent_rate); + clk_set_rate(clk_get_parent(clk), best_parent_rate); } else { - val++; + div = parent_rate / rate; } - return parent_rate / val; + value = _get_val(divider, div); + + if (value > div_mask(divider)) + value = div_mask(divider); + + val = readl(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + val |= value << divider->shift; + writel(val, divider->reg); + + return 0; } struct clk_ops clk_divider_ops = { .set_rate = clk_divider_set_rate, .recalc_rate = clk_divider_recalc_rate, + .round_rate = clk_divider_round_rate, }; struct clk *clk_divider(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width) + void __iomem *reg, u8 shift, u8 width, unsigned flags) { struct clk_divider *div = xzalloc(sizeof(*div)); int ret; @@ -89,6 +220,7 @@ struct clk *clk_divider(const char *name, const char *parent, div->parent = parent; div->clk.ops = &clk_divider_ops; div->clk.name = name; + div->clk.flags = flags; div->clk.parent_names = &div->parent; div->clk.num_parents = 1; @@ -102,12 +234,12 @@ struct clk *clk_divider(const char *name, const char *parent, } struct clk *clk_divider_one_based(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width) + void __iomem *reg, u8 shift, u8 width, unsigned flags) { struct clk_divider *div; struct clk *clk; - clk = clk_divider(name, parent, reg, shift, width); + clk = clk_divider(name, parent, reg, shift, width, flags); if (IS_ERR(clk)) return clk; @@ -116,3 +248,39 @@ struct clk *clk_divider_one_based(const char *name, const char *parent, return clk; } + +struct clk *clk_divider_table(const char *name, + const char *parent, void __iomem *reg, u8 shift, u8 width, + const struct clk_div_table *table, unsigned flags) +{ + struct clk_divider *div = xzalloc(sizeof(*div)); + const struct clk_div_table *clkt; + int ret, max_div = 0; + + div->shift = shift; + div->reg = reg; + div->width = width; + div->parent = parent; + div->clk.ops = &clk_divider_ops; + div->clk.name = name; + div->clk.flags = flags; + div->clk.parent_names = &div->parent; + div->clk.num_parents = 1; + div->table = table; + + for (clkt = div->table; clkt->div; clkt++) { + if (clkt->div > max_div) { + max_div = clkt->div; + div->max_div_index = div->table_size; + } + div->table_size++; + } + + ret = clk_register(&div->clk); + if (ret) { + free(div); + return ERR_PTR(ret); + } + + return &div->clk; +} diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index f0ecbd3e59..cb531b146b 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -35,12 +35,42 @@ static unsigned long clk_fixed_factor_recalc_rate(struct clk *clk, return (parent_rate / f->div) * f->mult; } +static long clk_factor_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + struct clk_fixed_factor *fix = container_of(clk, struct clk_fixed_factor, clk); + + if (clk->flags & CLK_SET_RATE_PARENT) { + unsigned long best_parent; + + best_parent = (rate / fix->mult) * fix->div; + *prate = clk_round_rate(clk_get_parent(clk), best_parent); + } + + return (*prate / fix->div) * fix->mult; +} + +static int clk_factor_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_fixed_factor *fix = container_of(clk, struct clk_fixed_factor, clk); + + if (clk->flags & CLK_SET_RATE_PARENT) { + printk("%s: %ld -> parent %ld\n", __func__, rate, rate * fix->div / fix->mult); + return clk_set_rate(clk_get_parent(clk), rate * fix->div / fix->mult); + } + + return 0; +} + static struct clk_ops clk_fixed_factor_ops = { + .set_rate = clk_factor_set_rate, + .round_rate = clk_factor_round_rate, .recalc_rate = clk_fixed_factor_recalc_rate, }; struct clk *clk_fixed_factor(const char *name, - const char *parent, unsigned int mult, unsigned int div) + const char *parent, unsigned int mult, unsigned int div, unsigned flags) { struct clk_fixed_factor *f = xzalloc(sizeof(*f)); int ret; @@ -50,6 +80,7 @@ struct clk *clk_fixed_factor(const char *name, f->parent = parent; f->clk.ops = &clk_fixed_factor_ops; f->clk.name = name; + f->clk.flags = flags; f->clk.parent_names = &f->parent; f->clk.num_parents = 1; diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index baec85598d..b298b193dc 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -77,13 +77,15 @@ static int clk_gate_is_enabled(struct clk *clk) } static struct clk_ops clk_gate_ops = { + .set_rate = clk_parent_set_rate, + .round_rate = clk_parent_round_rate, .enable = clk_gate_enable, .disable = clk_gate_disable, .is_enabled = clk_gate_is_enabled, }; struct clk *clk_gate_alloc(const char *name, const char *parent, - void __iomem *reg, u8 shift) + void __iomem *reg, u8 shift, unsigned flags) { struct clk_gate *g = xzalloc(sizeof(*g)); @@ -92,6 +94,7 @@ struct clk *clk_gate_alloc(const char *name, const char *parent, g->shift = shift; g->clk.ops = &clk_gate_ops; g->clk.name = name; + g->clk.flags = flags; g->clk.parent_names = &g->parent; g->clk.num_parents = 1; @@ -106,12 +109,12 @@ void clk_gate_free(struct clk *clk_gate) } struct clk *clk_gate(const char *name, const char *parent, void __iomem *reg, - u8 shift) + u8 shift, unsigned flags) { struct clk *g; int ret; - g = clk_gate_alloc(name , parent, reg, shift); + g = clk_gate_alloc(name , parent, reg, shift, flags); ret = clk_register(g); if (ret) { @@ -123,12 +126,12 @@ struct clk *clk_gate(const char *name, const char *parent, void __iomem *reg, } struct clk *clk_gate_inverted(const char *name, const char *parent, - void __iomem *reg, u8 shift) + void __iomem *reg, u8 shift, unsigned flags) { struct clk *clk; struct clk_gate *g; - clk = clk_gate(name, parent, reg, shift); + clk = clk_gate(name, parent, reg, shift, flags); if (IS_ERR(clk)) return clk; diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index b22bdd1ec7..4ce86f43d1 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -51,12 +51,15 @@ static int clk_mux_set_parent(struct clk *clk, u8 idx) } static struct clk_ops clk_mux_ops = { + .set_rate = clk_parent_set_rate, + .round_rate = clk_parent_round_rate, .get_parent = clk_mux_get_parent, .set_parent = clk_mux_set_parent, }; struct clk *clk_mux_alloc(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents) + u8 shift, u8 width, const char **parents, u8 num_parents, + unsigned flags) { struct clk_mux *m = xzalloc(sizeof(*m)); @@ -65,6 +68,7 @@ struct clk *clk_mux_alloc(const char *name, void __iomem *reg, m->width = width; m->clk.ops = &clk_mux_ops; m->clk.name = name; + m->clk.flags = flags; m->clk.parent_names = parents; m->clk.num_parents = num_parents; @@ -79,12 +83,12 @@ void clk_mux_free(struct clk *clk_mux) } struct clk *clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents) + u8 shift, u8 width, const char **parents, u8 num_parents, unsigned flags) { struct clk *m; int ret; - m = clk_mux_alloc(name, reg, shift, width, parents, num_parents); + m = clk_mux_alloc(name, reg, shift, width, parents, num_parents, flags); ret = clk_register(m); if (ret) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 31d73c028c..0d259413a9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -104,9 +104,19 @@ unsigned long clk_get_rate(struct clk *clk) long clk_round_rate(struct clk *clk, unsigned long rate) { + unsigned long parent_rate = 0; + struct clk *parent; + if (IS_ERR(clk)) return 0; + parent = clk_get_parent(clk); + if (parent) + parent_rate = clk_get_rate(parent); + + if (clk->ops->round_rate) + return clk->ops->round_rate(clk, rate, &parent_rate); + return clk_get_rate(clk); } @@ -249,11 +259,31 @@ int clk_is_enabled(struct clk *clk) return clk_is_enabled(clk); } +/* + * Generic struct clk_ops callbacks + */ int clk_is_enabled_always(struct clk *clk) { return 1; } +long clk_parent_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + if (!(clk->flags & CLK_SET_RATE_PARENT)) + return *prate; + + return clk_round_rate(clk_get_parent(clk), rate); +} + +int clk_parent_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + if (!(clk->flags & CLK_SET_RATE_PARENT)) + return 0; + return clk_set_rate(clk_get_parent(clk), rate); +} + #if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER) /** * struct of_clk_provider - Clock provider registration structure diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 37cc1568a3..658ce3e81a 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -87,7 +87,7 @@ int mvebu_coreclk_probe(struct device_d *dev) 2+n, &rclk_name); desc->get_clk_ratio(base, desc->ratios[n].id, &mult, &div); clk_data.clks[2+n] = clk_fixed_factor(rclk_name, cpuclk_name, - mult, div); + mult, div, 0); WARN_ON(IS_ERR(clk_data.clks[2+n])); }; @@ -188,7 +188,7 @@ int mvebu_clk_gating_probe(struct device_d *dev) (desc[n].parent) ? desc[n].parent : default_parent; gate->bit_idx = desc[n].bit_idx; gate->clk = clk_gate(desc[n].name, parent, - base, desc[n].bit_idx); + base, desc[n].bit_idx, 0); WARN_ON(IS_ERR(gate->clk)); } diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index 05b3c2a04d..934a1940fb 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -128,7 +128,7 @@ int __init mx28_clocks_init(void __iomem *regs) clks[fec] = mxs_clk_gate("fec", "fec_sleep", ENET, 30); clks[usb0_phy] = mxs_clk_gate("usb0_phy", "pll0", PLL0CTRL0, 18); clks[usb1_phy] = mxs_clk_gate("usb1_phy", "pll1", PLL1CTRL0, 18); - clks[enet_out] = clk_gate("enet_out", "pll2", ENET, 18); + clks[enet_out] = clk_gate("enet_out", "pll2", ENET, 18, 0); clks[lcdif_comp] = mxs_clk_lcdif("lcdif_comp", clks[ref_pix], clks[lcdif_div], clks[lcdif]); diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h index b4fcfa0090..7bab7b5e6e 100644 --- a/drivers/clk/mxs/clk.h +++ b/drivers/clk/mxs/clk.h @@ -34,19 +34,19 @@ static inline struct clk *mxs_clk_fixed(const char *name, int rate) static inline struct clk *mxs_clk_gate(const char *name, const char *parent_name, void __iomem *reg, u8 shift) { - return clk_gate_inverted(name, parent_name, reg, shift); + return clk_gate_inverted(name, parent_name, reg, shift, 0); } static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg, u8 shift, u8 width, const char **parent_names, int num_parents) { - return clk_mux(name, reg, shift, width, parent_names, num_parents); + return clk_mux(name, reg, shift, width, parent_names, num_parents, 0); } static inline struct clk *mxs_clk_fixed_factor(const char *name, const char *parent_name, unsigned int mult, unsigned int div) { - return clk_fixed_factor(name, parent_name, mult, div); + return clk_fixed_factor(name, parent_name, mult, div, 0); } #endif /* __MXS_CLK_H */ diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index e969495875..c970f63afa 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -140,12 +140,12 @@ struct clk *_tegra_clk_register_periph(const char *name, } periph->mux = clk_mux_alloc(NULL, clk_base + reg_offset, 30, 2, - parent_names, num_parents); + parent_names, num_parents, 0); if (!periph->mux) goto out_mux; periph->gate = clk_gate_alloc(NULL, NULL, clk_base + 0x10 + - ((id >> 3) & 0xc), id & 0x1f); + ((id >> 3) & 0xc), id & 0x1f, 0); if (!periph->gate) goto out_gate; diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index f68c811a8d..cfb719f431 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -62,7 +62,7 @@ static void tegra20_osc_clk_init(void) clks[clk_32k] = clk_fixed("clk_32k", 32768); clks[pll_ref] = clk_fixed_factor("pll_ref", "clk_m", 1, - get_pll_ref_div()); + get_pll_ref_div(), 0); } /* PLL frequency tables */ diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4ef25ec45b..43974f03c2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -14,6 +14,29 @@ config CLOCKSOURCE_CLPS711X bool depends on ARCH_CLPS711X +config CLOCKSOURCE_DUMMY + bool "Enable dummy software-only clocksource" + help + When porting barebox to a new SoC there might be a case + of broken or absent clocksource. This causes barebox serial + console to be non functional. + To solve the problem this software-only clocksource driver is used. + WARNING!!! This clocksource doesn't provide correct timing. + To adjust this clocksource please use CONFIG_CLOCKSOURCE_DUMMY_RATE. + The bigger rate valuest makes clocksource "faster". + It's possible to add this clocksource unconditionally. + This clocksource starts very early (pure_initcall) so + real clocksource will take over. + This can help if initialization order is wrong so that + the time functions are used before the real clocksource + was initialized. + +config CLOCKSOURCE_DUMMY_RATE + int + prompt "dummy clocksource rate" + depends on CLOCKSOURCE_DUMMY + default 1000 + config CLOCKSOURCE_MVEBU bool depends on ARCH_MVEBU diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 25b7f460da..834a15d1e9 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_AMBA_SP804) += amba-sp804.o obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o obj-$(CONFIG_CLOCKSOURCE_CLPS711X) += clps711x.o +obj-$(CONFIG_CLOCKSOURCE_DUMMY) += dummy.o obj-$(CONFIG_CLOCKSOURCE_MVEBU) += mvebu.o obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o obj-$(CONFIG_CLOCKSOURCE_ORION) += orion.o diff --git a/drivers/clocksource/dummy.c b/drivers/clocksource/dummy.c new file mode 100644 index 0000000000..154a8cd672 --- /dev/null +++ b/drivers/clocksource/dummy.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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 <common.h> +#include <init.h> +#include <clock.h> + +static uint64_t dummy_counter; + +static uint64_t dummy_cs_read(void) +{ + static int first; + + if (!first) { + pr_warn("Warning: Using dummy clocksource\n"); + first = 1; + } + + dummy_counter += CONFIG_CLOCKSOURCE_DUMMY_RATE; + + return dummy_counter; +} + +static struct clocksource dummy_cs = { + .read = dummy_cs_read, + .mask = CLOCKSOURCE_MASK(32), +}; + +static int clocksource_init(void) +{ + dummy_counter = 0; + + clocks_calc_mult_shift(&dummy_cs.mult, &dummy_cs.shift, + 100000000, NSEC_PER_SEC, 10); + + pr_debug("clocksource_init: mult=%08x, shift=%08x\n", + dummy_cs.mult, dummy_cs.shift); + init_clock(&dummy_cs); + + return 0; +} +pure_initcall(clocksource_init); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7c426563e7..7302955d87 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -20,6 +20,13 @@ config GPIO_CLPS711X 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 b7c536d21b..68a76a3745 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 0000000000..7d15b855f0 --- /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. <source@mvista.com> + * Copyright (c) 2014 Antony Pavlov <antonynpavlov@gmail.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. + */ + +#include <common.h> +#include <gpio.h> +#include <init.h> +#include <io.h> +#include <linux/err.h> + +#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/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f657c287f7..6b390478fa 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -587,4 +587,4 @@ static struct driver_d i2c_fsl_driver = { .name = DRIVER_NAME, .of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids), }; -device_platform_driver(i2c_fsl_driver); +coredevice_platform_driver(i2c_fsl_driver); diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index e289a3569b..9873957015 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -405,6 +405,17 @@ struct i2c_adapter *i2c_get_adapter(int busnum) return NULL; } +struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) +{ + struct i2c_adapter *adap; + + list_for_each_entry(adap, &adapter_list, list) + if (adap->dev.device_node == node) + return adap; + + return NULL; +} + /** * i2c_add_numbered_adapter - declare i2c adapter, use static bus number * @adapter: the adapter to register (with adap->nr initialized) diff --git a/drivers/input/gpio_keys.c b/drivers/input/gpio_keys.c index 9486b9a786..d017594662 100644 --- a/drivers/input/gpio_keys.c +++ b/drivers/input/gpio_keys.c @@ -121,7 +121,7 @@ static int gpio_keys_probe_dt(struct gpio_keys *gk, struct device_d *dev) struct device_node *npkey, *np = dev->device_node; int i = 0, ret; - if (!IS_ENABLED(CONFIG_OFDEVICE)) + if (!IS_ENABLED(CONFIG_OFDEVICE) || !IS_ENABLED(CONFIG_OF_GPIO)) return -ENODEV; gk->nbuttons = of_get_child_count(np); diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 36a363fa37..c97c8c1403 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -401,7 +401,7 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) mtd->cdev.mtd = mtd; if (IS_ENABLED(CONFIG_PARAMETER)) { - dev_add_param_int_ro(&mtd->class_dev, "size", mtd->size, "%u"); + dev_add_param_int_ro(&mtd->class_dev, "size", mtd->size, "%llu"); dev_add_param_int_ro(&mtd->class_dev, "erasesize", mtd->erasesize, "%u"); dev_add_param_int_ro(&mtd->class_dev, "writesize", mtd->oobsize, "%u"); dev_add_param_int_ro(&mtd->class_dev, "oobsize", mtd->oobsize, "%u"); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 56c69f35c0..50e04548e9 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -268,8 +268,9 @@ static int erase_sector(struct m25p *flash, u32 offset, u32 command) static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); - u32 addr, len; + u32 addr; uint32_t rem; + uint64_t len; dev_dbg(&flash->spi->dev, "%s at 0x%llx, len %lld\n", __func__, (long long)instr->addr, @@ -897,7 +898,7 @@ static int m25p_probe(struct device_d *dev) flash->mtd.type = MTD_NORFLASH; flash->mtd.writesize = 1; flash->mtd.flags = MTD_CAP_NORFLASH; - flash->mtd.size = info->sector_size * info->n_sectors; + flash->mtd.size = (uint64_t)info->sector_size * info->n_sectors; flash->mtd.erase = m25p80_erase; flash->mtd.read = m25p80_read; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index cdc0120c53..fa31b61464 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -625,7 +625,7 @@ add_dataflash_otp(struct spi_device *spi, char *name, device = &priv->mtd; device->name = (pdata && pdata->name) ? pdata->name : "dataflash"; - device->size = nr_pages * pagesize; + device->size = nr_pages * (uint64_t)pagesize; device->erasesize = pagesize; device->writesize = pagesize; device->type = MTD_DATAFLASH; diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c index b9cac2ae69..10d17e90d2 100644 --- a/drivers/mtd/mtdoob.c +++ b/drivers/mtd/mtdoob.c @@ -78,7 +78,7 @@ static int add_mtdoob_device(struct mtd_info *mtd, char *devname, void **priv) mtdoob = xzalloc(sizeof(*mtdoob)); mtdoob->cdev.ops = &mtd_ops_oob; - mtdoob->cdev.size = (mtd->size / mtd->writesize) * mtd->oobsize; + mtdoob->cdev.size = mtd_div_by_wb(mtd->size, mtd) * mtd->oobsize; mtdoob->cdev.name = asprintf("%s_oob%d", devname, mtd->class_dev.id); mtdoob->cdev.priv = mtdoob; mtdoob->cdev.dev = &mtd->class_dev; diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c index 006b28f9b2..c25e4062ee 100644 --- a/drivers/mtd/mtdraw.c +++ b/drivers/mtd/mtdraw.c @@ -293,7 +293,7 @@ static int add_mtdraw_device(struct mtd_info *mtd, char *devname, void **priv) mtdraw->mtd = mtd; mtdraw->cdev.ops = (struct file_operations *)&mtd_raw_fops; - mtdraw->cdev.size = mtd->size / mtd->writesize * + mtdraw->cdev.size = mtd_div_by_wb(mtd->size, mtd) * (mtd->writesize + mtd->oobsize); mtdraw->cdev.name = asprintf("%s.raw", mtd->cdev.name); mtdraw->cdev.priv = mtdraw; diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c index d1e4b5717d..b06b558b08 100644 --- a/drivers/mtd/nand/nand_mxs.c +++ b/drivers/mtd/nand/nand_mxs.c @@ -33,6 +33,7 @@ #include <dma/apbh-dma.h> #include <stmp-device.h> #include <asm/mmu.h> +#include <mach/generic.h> #define MX28_BLOCK_SFTRST (1 << 31) #define MX28_BLOCK_CLKGATE (1 << 30) @@ -233,18 +234,31 @@ static uint32_t mxs_nand_aux_status_offset(void) static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, uint32_t page_oob_size) { + int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(page_data_size); + int ecc_strength = 0; + int gf_len = 13; /* length of Galois Field for non-DDR nand */ + + /* + * Possibly this if-else calculation may be removed since + * ecc_strength calculated after it is taken from kernel driver + * and therefore should work for all cases. But it was tested only + * on devices with {data_size = 2046, oob_size = 64} and + * {data_size = 4096, oob_size = 224} configuration. + */ if (page_data_size == 2048) return 8; - - if (page_data_size == 4096) { + else if (page_data_size == 4096) { if (page_oob_size == 128) return 8; - if (page_oob_size == 218) return 16; } - return 0; + ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8) + / (gf_len * ecc_chunk_count); + + /* We need the minor even number. */ + return rounddown(ecc_strength, 2); } static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size, @@ -427,7 +441,13 @@ static int mxs_nand_device_ready(struct mtd_info *mtd) if (nand_info->version > GPMI_VERSION_TYPE_MX23) { tmp = readl(gpmi_regs + GPMI_STAT); - tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + nand_info->cur_chip); + /* i.MX6 has only one R/B actual pin, so if there are several + R/B signals they must be all connected to this pin */ + if (cpu_is_mx6()) + tmp >>= GPMI_STAT_READY_BUSY_OFFSET; + else + tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + + nand_info->cur_chip); } else { tmp = readl(gpmi_regs + GPMI_DEBUG); tmp >>= (GPMI_DEBUG_READY0_OFFSET + nand_info->cur_chip); @@ -1304,7 +1324,7 @@ static int mxs_nand_probe(struct device_d *dev) nand->ecc.strength = 8; /* first scan to find the device and get the page size */ - err = nand_scan_ident(mtd, 1, NULL); + err = nand_scan_ident(mtd, 4, NULL); if (err) goto err2; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 3053a8e891..59712b8119 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -940,7 +940,7 @@ static int gpmc_nand_probe(struct device_d *pdev) switch (pdata->device_width) { case 0: - printk("probe buswidth\n"); + dev_dbg(pdev, "probing buswidth\n"); nand->options |= NAND_BUSWIDTH_AUTO; break; case 8: diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index 351c5831b0..720c2adab3 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -75,8 +75,8 @@ static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) return res; } -struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, - unsigned long flags, const char *name) +struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, + uint64_t size, unsigned long flags, const char *name) { struct mtd_info *part; int start = 0, end = 0, i; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index da21f69e7e..b908fcda0b 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -104,6 +104,8 @@ struct ubi_device *ubi_get_device(int ubi_num) struct ubi_device *ubi; ubi = ubi_devices[ubi_num]; + if (!ubi) + return NULL; ubi->ref_count++; diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 4b8eb4c5cf..dcd138f553 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -222,7 +222,7 @@ static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) break; case UBI_IOCMKVOL: if (!req->bytes) - req->bytes = ubi->avail_pebs * ubi->leb_size; + req->bytes = (__s64)ubi->avail_pebs * ubi->leb_size; return ubi_create_volume(ubi, req); }; diff --git a/drivers/net/ar231x.c b/drivers/net/ar231x.c index 5c091140ac..515de17b10 100644 --- a/drivers/net/ar231x.c +++ b/drivers/net/ar231x.c @@ -419,15 +419,9 @@ static int ar231x_eth_probe(struct device_d *dev) return 0; } -static void ar231x_eth_remove(struct device_d *dev) -{ - -} - static struct driver_d ar231x_eth_driver = { .name = "ar231x_eth", .probe = ar231x_eth_probe, - .remove = ar231x_eth_remove, }; static int ar231x_eth_driver_init(void) diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c index 25924cf7e2..bf2f957a36 100644 --- a/drivers/net/at91_ether.c +++ b/drivers/net/at91_ether.c @@ -357,13 +357,8 @@ static int at91_ether_probe(struct device_d *dev) return 0; } -static void at91_ether_remove(struct device_d *dev) -{ -} - static struct driver_d at91_ether_driver = { .name = "at91_ether", .probe = at91_ether_probe, - .remove = at91_ether_remove, }; device_platform_driver(at91_ether_driver); diff --git a/drivers/net/designware.c b/drivers/net/designware.c index ecb4656e9d..e706f54b31 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -477,10 +477,6 @@ static int dwc_ether_probe(struct device_d *dev) return 0; } -static void dwc_ether_remove(struct device_d *dev) -{ -} - static __maybe_unused struct of_device_id dwc_ether_compatible[] = { { .compatible = "snps,dwmac-3.70a", @@ -493,7 +489,6 @@ static __maybe_unused struct of_device_id dwc_ether_compatible[] = { static struct driver_d dwc_ether_driver = { .name = "designware_eth", .probe = dwc_ether_probe, - .remove = dwc_ether_remove, .of_compatible = DRV_OF_COMPAT(dwc_ether_compatible), }; device_platform_driver(dwc_ether_driver); diff --git a/drivers/of/base.c b/drivers/of/base.c index 104b6daeaf..c440a69e6c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1841,8 +1841,11 @@ int of_device_is_stdout_path(struct device_d *dev) struct device_node *dn; const char *name; - name = of_get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) + name = of_get_property(of_chosen, "stdout-path", NULL); + if (!name) + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + + if (!name) return 0; dn = of_find_node_by_path(name); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 11fc155074..f51c6e6b02 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -14,6 +14,13 @@ config SERIAL_AMBA_PL011 If unsure, say N. +config DRIVER_SERIAL_AR933X + bool "AR933X serial driver" + depends on MACH_MIPS_ATH79 + help + If you have an Atheros AR933X SOC based board and want to use the + built-in UART of the SoC, say Y to this option. + config DRIVER_SERIAL_IMX depends on ARCH_IMX default y diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 93790b5349..e1865f725a 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_DRIVER_SERIAL_ARM_DCC) += arm_dcc.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o +obj-$(CONFIG_DRIVER_SERIAL_AR933X) += serial_ar933x.o obj-$(CONFIG_DRIVER_SERIAL_IMX) += serial_imx.o obj-$(CONFIG_DRIVER_SERIAL_STM378X) += stm-serial.o obj-$(CONFIG_DRIVER_SERIAL_ATMEL) += atmel.o diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c new file mode 100644 index 0000000000..27cccba119 --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,204 @@ +/* + * based on linux.git/drivers/tty/serial/serial_ar933x.c + * + * 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. + * + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <malloc.h> +#include <io.h> +#include <asm-generic/div64.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include "serial_ar933x.h" + +#define AR933X_UART_MAX_SCALE 0xff +#define AR933X_UART_MAX_STEP 0xffff + +struct ar933x_uart_priv { + void __iomem *base; + struct clk *clk; +}; + +static inline void ar933x_serial_writel(struct console_device *cdev, + u32 b, int offset) +{ + struct ar933x_uart_priv *priv = cdev->dev->priv; + + cpu_writel(b, priv->base + offset); +} + +static inline u32 ar933x_serial_readl(struct console_device *cdev, + int offset) +{ + struct ar933x_uart_priv *priv = cdev->dev->priv; + + return cpu_readl(priv->base + offset); +} + +/* + * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) + * take from linux. + */ +static unsigned long ar933x_uart_get_baud(unsigned int clk, + unsigned int scale, + unsigned int step) +{ + u64 t; + u32 div; + + div = (2 << 16) * (scale + 1); + t = clk; + t *= step; + t += (div / 2); + do_div(t, div); + + return t; +} + +static void ar933x_uart_get_scale_step(unsigned int clk, + unsigned int baud, + unsigned int *scale, + unsigned int *step) +{ + unsigned int tscale; + long min_diff; + + *scale = 0; + *step = 0; + + min_diff = baud; + for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { + u64 tstep; + int diff; + + tstep = baud * (tscale + 1); + tstep *= (2 << 16); + do_div(tstep, clk); + + if (tstep > AR933X_UART_MAX_STEP) + break; + + diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); + if (diff < min_diff) { + min_diff = diff; + *scale = tscale; + *step = tstep; + } + } +} + +static int ar933x_serial_setbaudrate(struct console_device *cdev, int baudrate) +{ + struct ar933x_uart_priv *priv = cdev->dev->priv; + unsigned int scale, step; + + ar933x_uart_get_scale_step(clk_get_rate(priv->clk), baudrate, &scale, + &step); + ar933x_serial_writel(cdev, (scale << AR933X_UART_CLOCK_SCALE_S) | step, + AR933X_UART_CLOCK_REG); + + return 0; +} + +static void ar933x_serial_putc(struct console_device *cdev, char ch) +{ + u32 data; + + /* wait transmitter ready */ + data = ar933x_serial_readl(cdev, AR933X_UART_DATA_REG); + while (!(data & AR933X_UART_DATA_TX_CSR)) + data = ar933x_serial_readl(cdev, AR933X_UART_DATA_REG); + + data = (ch & AR933X_UART_DATA_TX_RX_MASK) | AR933X_UART_DATA_TX_CSR; + ar933x_serial_writel(cdev, data, AR933X_UART_DATA_REG); +} + +static int ar933x_serial_tstc(struct console_device *cdev) +{ + u32 rdata; + + rdata = ar933x_serial_readl(cdev, AR933X_UART_DATA_REG); + + return rdata & AR933X_UART_DATA_RX_CSR; +} + +static int ar933x_serial_getc(struct console_device *cdev) +{ + u32 rdata; + + while (!ar933x_serial_tstc(cdev)) + ; + + rdata = ar933x_serial_readl(cdev, AR933X_UART_DATA_REG); + + /* remove the character from the FIFO */ + ar933x_serial_writel(cdev, AR933X_UART_DATA_RX_CSR, + AR933X_UART_DATA_REG); + + return rdata & AR933X_UART_DATA_TX_RX_MASK; +} + +static int ar933x_serial_probe(struct device_d *dev) +{ + struct console_device *cdev; + struct ar933x_uart_priv *priv; + u32 uart_cs; + + cdev = xzalloc(sizeof(struct console_device)); + priv = xzalloc(sizeof(struct ar933x_uart_priv)); + priv->base = dev_request_mem_region(dev, 0); + dev->priv = priv; + + cdev->dev = dev; + cdev->tstc = ar933x_serial_tstc; + cdev->putc = ar933x_serial_putc; + cdev->getc = ar933x_serial_getc; + cdev->setbrg = ar933x_serial_setbaudrate; + + priv->clk = clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "unable to get UART clock\n"); + return PTR_ERR(priv->clk); + } + + uart_cs = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) + | AR933X_UART_CS_TX_READY_ORIDE + | AR933X_UART_CS_RX_READY_ORIDE; + ar933x_serial_writel(cdev, uart_cs, AR933X_UART_CS_REG); + /* FIXME: need ar933x_serial_init_port(cdev); */ + + console_register(cdev); + + return 0; +} + +static struct of_device_id ar933x_serial_dt_ids[] = { + { + .compatible = "qca,ar9330-uart", + }, { + /* sentinel */ + }, +}; + +static struct driver_d ar933x_serial_driver = { + .name = "ar933x_serial", + .probe = ar933x_serial_probe, + .of_compatible = DRV_OF_COMPAT(ar933x_serial_dt_ids), +}; +console_platform_driver(ar933x_serial_driver); diff --git a/drivers/serial/serial_ar933x.h b/drivers/serial/serial_ar933x.h new file mode 100644 index 0000000000..f55f0fa3d7 --- /dev/null +++ b/drivers/serial/serial_ar933x.h @@ -0,0 +1,69 @@ +/* + * Atheros AR933X UART defines + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * 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. + */ + +#ifndef __AR933X_UART_H +#define __AR933X_UART_H + +#include <linux/bitops.h> + +#define AR933X_UART_REGS_SIZE 20 +#define AR933X_UART_FIFO_SIZE 16 + +#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLOCK_REG 0x08 +#define AR933X_UART_INT_REG 0x0c +#define AR933X_UART_INT_EN_REG 0x10 + +#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) + +#define AR933X_UART_CS_PARITY_S 0 +#define AR933X_UART_CS_PARITY_M 0x3 +#define AR933X_UART_CS_PARITY_NONE 0 +#define AR933X_UART_CS_PARITY_ODD 1 +#define AR933X_UART_CS_PARITY_EVEN 2 +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_NONE 0 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_FLOW_CTRL_S 4 +#define AR933X_UART_CS_FLOW_CTRL_M 0x3 +#define AR933X_UART_CS_DMA_EN BIT(6) +#define AR933X_UART_CS_TX_READY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_READY_ORIDE BIT(8) +#define AR933X_UART_CS_TX_READY BIT(9) +#define AR933X_UART_CS_RX_BREAK BIT(10) +#define AR933X_UART_CS_TX_BREAK BIT(11) +#define AR933X_UART_CS_HOST_INT BIT(12) +#define AR933X_UART_CS_HOST_INT_EN BIT(13) +#define AR933X_UART_CS_TX_BUSY BIT(14) +#define AR933X_UART_CS_RX_BUSY BIT(15) + +#define AR933X_UART_CLOCK_STEP_M 0xffff +#define AR933X_UART_CLOCK_SCALE_M 0xfff +#define AR933X_UART_CLOCK_SCALE_S 16 +#define AR933X_UART_CLOCK_STEP_M 0xffff + +#define AR933X_UART_INT_RX_VALID BIT(0) +#define AR933X_UART_INT_TX_READY BIT(1) +#define AR933X_UART_INT_RX_FRAMING_ERR BIT(2) +#define AR933X_UART_INT_RX_OFLOW_ERR BIT(3) +#define AR933X_UART_INT_TX_OFLOW_ERR BIT(4) +#define AR933X_UART_INT_RX_PARITY_ERR BIT(5) +#define AR933X_UART_INT_RX_BREAK_ON BIT(6) +#define AR933X_UART_INT_RX_BREAK_OFF BIT(7) +#define AR933X_UART_INT_RX_FULL BIT(8) +#define AR933X_UART_INT_TX_EMPTY BIT(9) +#define AR933X_UART_INT_ALLINTS 0x3ff + +#endif /* __AR933X_UART_H */ diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index f1da44b7f7..0c00eb182c 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -48,6 +48,7 @@ struct ns16550_priv { struct NS16550_plat plat; int access_width; struct clk *clk; + uint32_t fcrval; }; static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev) @@ -157,18 +158,13 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate) { unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate); struct ns16550_priv *priv = to_ns16550_priv(cdev); - struct NS16550_plat *plat = &priv->plat; ns16550_write(cdev, LCR_BKSE, lcr); ns16550_write(cdev, baud_divisor & 0xff, dll); ns16550_write(cdev, (baud_divisor >> 8) & 0xff, dlm); ns16550_write(cdev, LCRVAL, lcr); ns16550_write(cdev, MCRVAL, mcr); - - if (plat->flags & NS16650_FLAG_DISABLE_FIFO) - ns16550_write(cdev, FCRVAL & ~FCR_FIFO_EN, fcr); - else - ns16550_write(cdev, FCRVAL, fcr); + ns16550_write(cdev, priv->fcrval, fcr); return 0; } @@ -185,6 +181,15 @@ static void ns16550_serial_init_port(struct console_device *cdev) ns16550_write(cdev, 0x00, ier); } +static void ns16450_serial_init_port(struct console_device *cdev) +{ + struct ns16550_priv *priv = to_ns16550_priv(cdev); + + priv->fcrval &= ~FCR_FIFO_EN; + + ns16550_serial_init_port(cdev); +} + #define omap_mdr1 8 static void ns16550_omap_init_port(struct console_device *cdev) @@ -192,7 +197,17 @@ static void ns16550_omap_init_port(struct console_device *cdev) ns16550_serial_init_port(cdev); ns16550_write(cdev, 0x07, omap_mdr1); /* Disable */ - ns16550_write(cdev, 0x00, omap_mdr1); + ns16550_write(cdev, 0x00, omap_mdr1); +} + +#define JZ_FCR_UME 0x10 /* Uart Module Enable */ + +static void ns16550_jz_init_port(struct console_device *cdev) +{ + struct ns16550_priv *priv = to_ns16550_priv(cdev); + + priv->fcrval |= JZ_FCR_UME; + ns16550_serial_init_port(cdev); } /*********** Exposed Functions **********************************/ @@ -246,6 +261,10 @@ static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) of_property_read_u32(np, "reg-shift", &priv->plat.shift); } +static struct ns16550_drvdata ns16450_drvdata = { + .init_port = ns16450_serial_init_port, +}; + static struct ns16550_drvdata ns16550_drvdata = { .init_port = ns16550_serial_init_port, }; @@ -255,6 +274,10 @@ static __maybe_unused struct ns16550_drvdata omap_drvdata = { .linux_console_name = "ttyO", }; +static __maybe_unused struct ns16550_drvdata jz_drvdata = { + .init_port = ns16550_jz_init_port, +}; + /** * @brief Probe entry point -called on the first match for device * @@ -316,6 +339,11 @@ static int ns16550_probe(struct device_d *dev) cdev->setbrg = ns16550_setbaudrate; cdev->linux_console_name = devtype->linux_console_name; + if (plat && (plat->flags & NS16650_FLAG_DISABLE_FIFO)) + priv->fcrval = FCRVAL & ~FCR_FIFO_EN; + else + priv->fcrval = FCRVAL; + devtype->init_port(cdev); return console_register(cdev); @@ -328,6 +356,9 @@ err: static struct of_device_id ns16550_serial_dt_ids[] = { { + .compatible = "ns16450", + .data = (unsigned long)&ns16450_drvdata, + }, { .compatible = "ns16550a", .data = (unsigned long)&ns16550_drvdata, }, { @@ -346,6 +377,12 @@ static struct of_device_id ns16550_serial_dt_ids[] = { .data = (unsigned long)&omap_drvdata, }, #endif +#if IS_ENABLED(CONFIG_MACH_MIPS_XBURST) + { + .compatible = "ingenic,jz4740-uart", + .data = (unsigned long)&jz_drvdata, + }, +#endif { /* sentinel */ }, diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 11b6c186e3..71d0ecf39c 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -994,6 +994,8 @@ static struct usb_gadget_driver composite_driver = { */ int usb_composite_register(struct usb_composite_driver *driver) { + int ret; + if (!driver || !driver->dev || !driver->bind || composite) return -EINVAL; @@ -1002,7 +1004,12 @@ int usb_composite_register(struct usb_composite_driver *driver) composite_driver.function = (char *) driver->name; composite = driver; - return usb_gadget_register_driver(&composite_driver); + ret = usb_gadget_register_driver(&composite_driver); + + if (ret) + composite = NULL; + + return ret; } /** diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index 76b5def33c..d0f2155e49 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -703,7 +703,9 @@ int usb_dfu_register(struct usb_dfu_pdata *pdata) strings_dev[STRING_MANUFACTURER_IDX].s = pdata->manufacturer; strings_dev[STRING_PRODUCT_IDX].s = pdata->productname; - usb_composite_register(&dfu_driver); + ret = usb_composite_register(&dfu_driver); + if (ret) + return ret; while (1) { ret = usb_gadget_poll(); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5539266226..34177b3f08 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -77,6 +77,8 @@ config DRIVER_VIDEO_BCM2835 help Add support for the BCM2835/VideoCore frame buffer device. +source drivers/video/imx-ipu-v3/Kconfig + config DRIVER_VIDEO_SIMPLEFB bool "Simple framebuffer support" depends on OFTREE @@ -84,4 +86,10 @@ config DRIVER_VIDEO_SIMPLEFB Add support for setting up the kernel's simple framebuffer driver based on the active barebox framebuffer. +config DRIVER_VIDEO_EDID + bool "Add EDID support" + help + This enabled support for reading and parsing EDID data from an attached + monitor. + endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 31edfca2b0..ae9f6e545e 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -1,4 +1,6 @@ obj-$(CONFIG_VIDEO) += fb.o +obj-$(CONFIG_DRIVER_VIDEO_EDID) += edid.o +obj-$(CONFIG_OFDEVICE) += of_display_timing.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o @@ -11,3 +13,4 @@ obj-$(CONFIG_DRIVER_VIDEO_SDL) += sdl.o obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o obj-$(CONFIG_DRIVER_VIDEO_BCM2835) += bcm2835.o obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c index bed540da9f..d03922b2b6 100644 --- a/drivers/video/atmel_lcdfb_core.c +++ b/drivers/video/atmel_lcdfb_core.c @@ -269,9 +269,9 @@ int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data) info = &sinfo->info; info->priv = sinfo; info->fbops = &atmel_lcdc_ops; - info->mode_list = pdata->mode_list; - info->num_modes = pdata->num_modes; - info->mode = &info->mode_list[0]; + info->modes.modes = pdata->mode_list; + info->modes.num_modes = pdata->num_modes; + info->mode = &info->modes.modes[0]; info->xres = info->mode->xres; info->yres = info->mode->yres; info->bits_per_pixel = pdata->default_bpp; diff --git a/drivers/video/edid.c b/drivers/video/edid.c new file mode 100644 index 0000000000..828c3610ac --- /dev/null +++ b/drivers/video/edid.c @@ -0,0 +1,909 @@ +/* + * drivers/video/edid.c + * + * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> + * + * Credits: + * + * The EDID Parser is a conglomeration from the following sources: + * + * 1. SciTech SNAP Graphics Architecture + * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. + * + * 2. XFree86 4.3.0, interpret_edid.c + * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + * + * 3. John Fremlin <vii@users.sourceforge.net> and + * Ani Joshi <ajoshi@unixbox.com> + * + * Generalized Timing Formula is derived from: + * + * GTF Spreadsheet by Andy Morrish (1/5/97) + * available at http://www.vesa.org + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + +#define pr_fmt(fmt) "EDID: " fmt + +#include <common.h> +#include <fb.h> +#include <malloc.h> +#include <i2c/i2c.h> + +#include "edid.h" + +#define FBMON_FIX_HEADER 1 +#define FBMON_FIX_INPUT 2 +#define FBMON_FIX_TIMINGS 3 + +struct broken_edid { + u8 manufacturer[4]; + u32 model; + u32 fix; +}; + +static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00 +}; + +static int edid_is_serial_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xff) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_ascii_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfe) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_limits_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfd) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_monitor_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfc) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] != 0x00) || (block[1] != 0x00) || + (block[2] != 0x00) || (block[4] != 0x00)) + return 1; + else + return 0; +} + +static int check_edid(unsigned char *edid) +{ + unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; + unsigned char *b; + u32 model; + int i, fix = 0, ret = 0; + + manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; + manufacturer[1] = ((block[0] & 0x03) << 3) + + ((block[1] & 0xe0) >> 5) + '@'; + manufacturer[2] = (block[1] & 0x1f) + '@'; + manufacturer[3] = 0; + model = block[2] + (block[3] << 8); + + switch (fix) { + case FBMON_FIX_HEADER: + for (i = 0; i < 8; i++) { + if (edid[i] != edid_v1_header[i]) { + ret = fix; + break; + } + } + break; + case FBMON_FIX_INPUT: + b = edid + EDID_STRUCT_DISPLAY; + /* Only if display is GTF capable will + the input type be reset to analog */ + if (b[4] & 0x01 && b[0] & 0x80) + ret = fix; + break; + case FBMON_FIX_TIMINGS: + b = edid + DETAILED_TIMING_DESCRIPTIONS_START; + ret = fix; + + for (i = 0; i < 4; i++) { + if (edid_is_limits_block(b)) { + ret = 0; + break; + } + + b += DETAILED_TIMING_DESCRIPTION_SIZE; + } + + break; + } + + if (ret) + printk("fbmon: The EDID Block of " + "Manufacturer: %s Model: 0x%x is known to " + "be broken,\n", manufacturer, model); + + return ret; +} + +static void fix_edid(unsigned char *edid, int fix) +{ + int i; + unsigned char *b, csum = 0; + + switch (fix) { + case FBMON_FIX_HEADER: + printk("fbmon: trying a header reconstruct\n"); + memcpy(edid, edid_v1_header, 8); + break; + case FBMON_FIX_INPUT: + printk("fbmon: trying to fix input type\n"); + b = edid + EDID_STRUCT_DISPLAY; + b[0] &= ~0x80; + edid[127] += 0x80; + break; + case FBMON_FIX_TIMINGS: + printk("fbmon: trying to fix monitor timings\n"); + b = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++) { + if (!(edid_is_serial_block(b) || + edid_is_ascii_block(b) || + edid_is_monitor_block(b) || + edid_is_timing_block(b))) { + b[0] = 0x00; + b[1] = 0x00; + b[2] = 0x00; + b[3] = 0xfd; + b[4] = 0x00; + b[5] = 60; /* vfmin */ + b[6] = 60; /* vfmax */ + b[7] = 30; /* hfmin */ + b[8] = 75; /* hfmax */ + b[9] = 17; /* pixclock - 170 MHz*/ + b[10] = 0; /* GTF */ + break; + } + + b += DETAILED_TIMING_DESCRIPTION_SIZE; + } + + for (i = 0; i < EDID_LENGTH - 1; i++) + csum += edid[i]; + + edid[127] = 256 - csum; + break; + } +} + +static int edid_checksum(unsigned char *edid) +{ + unsigned char csum = 0, all_null = 0; + int i, err = 0, fix = check_edid(edid); + + if (fix) + fix_edid(edid, fix); + + for (i = 0; i < EDID_LENGTH; i++) { + csum += edid[i]; + all_null |= edid[i]; + } + + if (csum == 0x00 && all_null) { + /* checksum passed, everything's good */ + err = 1; + } + + return err; +} + +static int edid_check_header(unsigned char *edid) +{ + int i, err = 1, fix = check_edid(edid); + + if (fix) + fix_edid(edid, fix); + + for (i = 0; i < 8; i++) { + if (edid[i] != edid_v1_header[i]) + err = 0; + } + + return err; +} + +/* + * VESA Generalized Timing Formula (GTF) + */ + +#define FLYBACK 550 +#define V_FRONTPORCH 1 +#define H_OFFSET 40 +#define H_SCALEFACTOR 20 +#define H_BLANKSCALE 128 +#define H_GRADIENT 600 +#define C_VAL 30 +#define M_VAL 300 + +struct __fb_timings { + u32 dclk; + u32 hfreq; + u32 vfreq; + u32 hactive; + u32 vactive; + u32 hblank; + u32 vblank; + u32 htotal; + u32 vtotal; +}; + +/** + * fb_get_vblank - get vertical blank time + * @hfreq: horizontal freq + * + * DESCRIPTION: + * vblank = right_margin + vsync_len + left_margin + * + * given: right_margin = 1 (V_FRONTPORCH) + * vsync_len = 3 + * flyback = 550 + * + * flyback * hfreq + * left_margin = --------------- - vsync_len + * 1000000 + */ +static u32 fb_get_vblank(u32 hfreq) +{ + u32 vblank; + + vblank = (hfreq * FLYBACK)/1000; + vblank = (vblank + 500)/1000; + return (vblank + V_FRONTPORCH); +} + +/** + * fb_get_hblank_by_freq - get horizontal blank time given hfreq + * @hfreq: horizontal freq + * @xres: horizontal resolution in pixels + * + * DESCRIPTION: + * + * xres * duty_cycle + * hblank = ------------------ + * 100 - duty_cycle + * + * duty cycle = percent of htotal assigned to inactive display + * duty cycle = C - (M/Hfreq) + * + * where: C = ((offset - scale factor) * blank_scale) + * -------------------------------------- + scale factor + * 256 + * M = blank_scale * gradient + * + */ +static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) +{ + u32 c_val, m_val, duty_cycle, hblank; + + c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + + H_SCALEFACTOR) * 1000; + m_val = (H_BLANKSCALE * H_GRADIENT)/256; + m_val = (m_val * 1000000)/hfreq; + duty_cycle = c_val - m_val; + hblank = (xres * duty_cycle)/(100000 - duty_cycle); + return (hblank); +} + +/** + * int_sqrt - rough approximation to sqrt + * @x: integer of which to calculate the sqrt + * + * A very rough approximation to the sqrt() function. + */ +unsigned long int_sqrt(unsigned long x) +{ + unsigned long b, m, y = 0; + + if (x <= 1) + return x; + + m = 1UL << (BITS_PER_LONG - 2); + while (m != 0) { + b = y + m; + y >>= 1; + + if (x >= b) { + x -= b; + y += m; + } + m >>= 2; + } + + return y; +} +EXPORT_SYMBOL(int_sqrt); + +/** + * fb_get_hfreq - estimate hsync + * @vfreq: vertical refresh rate + * @yres: vertical resolution + * + * DESCRIPTION: + * + * (yres + front_port) * vfreq * 1000000 + * hfreq = ------------------------------------- + * (1000000 - (vfreq * FLYBACK) + * + */ + +static u32 fb_get_hfreq(u32 vfreq, u32 yres) +{ + u32 divisor, hfreq; + + divisor = (1000000 - (vfreq * FLYBACK))/1000; + hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; + return (hfreq/divisor); +} + +static void fb_timings_vfreq(struct __fb_timings *timings) +{ + timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); + timings->vblank = fb_get_vblank(timings->hfreq); + timings->vtotal = timings->vactive + timings->vblank; + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hactive); + timings->htotal = timings->hactive + timings->hblank; + timings->dclk = timings->htotal * timings->hfreq; +} + +/* + * fb_get_mode - calculates video mode using VESA GTF + * @flags: if: 0 - maximize vertical refresh rate + * 1 - vrefresh-driven calculation; + * 2 - hscan-driven calculation; + * 3 - pixelclock-driven calculation; + * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock + * @var: pointer to fb_var_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * Calculates video mode based on monitor specs using VESA GTF. + * The GTF is best for VESA GTF compliant monitors but is + * specifically formulated to work for older monitors as well. + * + * If @flag==0, the function will attempt to maximize the + * refresh rate. Otherwise, it will calculate timings based on + * the flag and accompanying value. + * + * If FB_IGNOREMON bit is set in @flags, monitor specs will be + * ignored and @var will be filled with the calculated timings. + * + * All calculations are based on the VESA GTF Spreadsheet + * available at VESA's public ftp (http://www.vesa.org). + * + * NOTES: + * The timings generated by the GTF will be different from VESA + * DMT. It might be a good idea to keep a table of standard + * VESA modes as well. The GTF may also not work for some displays, + * such as, and especially, analog TV. + * + * REQUIRES: + * A valid info->monspecs, otherwise 'safe numbers' will be used. + */ +int fb_get_mode(int flags, u32 val, struct fb_videomode *var) +{ + struct __fb_timings *timings; + u32 interlace = 1, dscan = 1; + u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0; + + timings = xzalloc(sizeof(struct __fb_timings)); + + /* + * If monspecs are invalid, use values that are enough + * for 640x480@60 + */ + hfmin = 29000; hfmax = 30000; + vfmin = 60; vfmax = 60; + dclkmin = 0; dclkmax = 25000000; + + timings->hactive = var->xres; + timings->vactive = var->yres; + if (var->vmode & FB_VMODE_INTERLACED) { + timings->vactive /= 2; + interlace = 2; + } + if (var->vmode & FB_VMODE_DOUBLE) { + timings->vactive *= 2; + dscan = 2; + } + + /* vrefresh driven */ + timings->vfreq = val; + fb_timings_vfreq(timings); + + if (timings->dclk) + var->pixclock = KHZ2PICOS(timings->dclk / 1000); + var->hsync_len = (timings->htotal * 8) / 100; + var->right_margin = (timings->hblank / 2) - var->hsync_len; + var->left_margin = timings->hblank - var->right_margin - + var->hsync_len; + var->vsync_len = (3 * interlace) / dscan; + var->lower_margin = (1 * interlace) / dscan; + var->upper_margin = (timings->vblank * interlace) / dscan - + (var->vsync_len + var->lower_margin); + + free(timings); + return err; +} + +static void calc_mode_timings(int xres, int yres, int refresh, + struct fb_videomode *mode) +{ + mode->xres = xres; + mode->yres = yres; + mode->refresh = refresh; + fb_get_mode(0, refresh, mode); + mode->name = asprintf("%dx%d@%d-calc", mode->xres, mode->yres, mode->refresh); + pr_debug(" %s\n", mode->name); +} + +const struct fb_videomode vesa_modes[] = { + /* 0 640x350-85 VESA */ + { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, 0}, + /* 1 640x400-85 VESA */ + { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 2 720x400-85 VESA */ + { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 3 640x480-60 VESA */ + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 4 640x480-72 VESA */ + { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 5 640x480-75 VESA */ + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 6 640x480-85 VESA */ + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 7 800x600-56 VESA */ + { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 8 800x600-60 VESA */ + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 9 800x600-72 VESA */ + { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 10 800x600-75 VESA */ + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 11 800x600-85 VESA */ + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 12 1024x768i-43 VESA */ + { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, 0 }, + /* 13 1024x768-60 VESA */ + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 14 1024x768-70 VESA */ + { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, 0 }, + /* 15 1024x768-75 VESA */ + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 16 1024x768-85 VESA */ + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 17 1152x864-75 VESA */ + { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 18 1280x960-60 VESA */ + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 19 1280x960-85 VESA */ + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 20 1280x1024-60 VESA */ + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 21 1280x1024-75 VESA */ + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 22 1280x1024-85 VESA */ + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 23 1600x1200-60 VESA */ + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 24 1600x1200-65 VESA */ + { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 25 1600x1200-70 VESA */ + { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 26 1600x1200-75 VESA */ + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 27 1600x1200-85 VESA */ + { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 }, + /* 28 1792x1344-60 VESA */ + { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 29 1792x1344-75 VESA */ + { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 30 1856x1392-60 VESA */ + { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 31 1856x1392-75 VESA */ + { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 32 1920x1440-60 VESA */ + { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, + /* 33 1920x1440-75 VESA */ + { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 }, +}; + +#define VESA_MODEDB_SIZE ARRAY_SIZE(vesa_modes) + +static void add_vesa_mode(struct fb_videomode *mode, int num) +{ + *mode = vesa_modes[num]; + mode->name = asprintf("%dx%d@%d-vesa", mode->xres, mode->yres, mode->refresh); + pr_debug(" %s\n", mode->name); +} + +static int get_est_timing(unsigned char *block, struct fb_videomode *mode) +{ + int num = 0; + unsigned char c; + + c = block[0]; + if (c & 0x80) + calc_mode_timings(720, 400, 70, &mode[num++]); + if (c & 0x40) + calc_mode_timings(720, 400, 88, &mode[num++]); + if (c & 0x20) + add_vesa_mode(&mode[num++], 3); + if (c & 0x10) + calc_mode_timings(640, 480, 67, &mode[num++]); + if (c & 0x08) + add_vesa_mode(&mode[num++], 4); + if (c & 0x04) + add_vesa_mode(&mode[num++], 5); + if (c & 0x02) + add_vesa_mode(&mode[num++], 7); + if (c & 0x01) + add_vesa_mode(&mode[num++], 8); + + c = block[1]; + if (c & 0x80) + add_vesa_mode(&mode[num++], 9); + if (c & 0x40) + add_vesa_mode(&mode[num++], 10); + if (c & 0x20) + calc_mode_timings(832, 624, 75, &mode[num++]); + if (c & 0x10) + add_vesa_mode(&mode[num++], 12); + if (c & 0x08) + add_vesa_mode(&mode[num++], 13); + if (c & 0x04) + add_vesa_mode(&mode[num++], 14); + if (c & 0x02) + add_vesa_mode(&mode[num++], 15); + if (c & 0x01) + add_vesa_mode(&mode[num++], 21); + c = block[2]; + + if (c & 0x80) + add_vesa_mode(&mode[num++], 17); + + pr_debug(" Manufacturer's mask: %x\n",c & 0x7F); + return num; +} + +static int get_std_timing(unsigned char *block, struct fb_videomode *mode, + int ver, int rev) +{ + int xres, yres = 0, refresh, ratio, i; + + xres = (block[0] + 31) * 8; + if (xres <= 256) + return 0; + + ratio = (block[1] & 0xc0) >> 6; + switch (ratio) { + case 0: + /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */ + if (ver < 1 || (ver == 1 && rev < 3)) + yres = xres; + else + yres = (xres * 10) / 16; + break; + case 1: + yres = (xres * 3) / 4; + break; + case 2: + yres = (xres * 4) / 5; + break; + case 3: + yres = (xres * 9) / 16; + break; + } + refresh = (block[1] & 0x3f) + 60; + + for (i = 0; i < VESA_MODEDB_SIZE; i++) { + if (vesa_modes[i].xres == xres && + vesa_modes[i].yres == yres && + vesa_modes[i].refresh == refresh) { + add_vesa_mode(mode, i); + return 1; + } + } + + calc_mode_timings(xres, yres, refresh, mode); + + return 1; +} + +static int get_dst_timing(unsigned char *block, + struct fb_videomode *mode, int ver, int rev) +{ + int j, num = 0; + + for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) + num += get_std_timing(block, &mode[num], ver, rev); + + return num; +} + +static void get_detailed_timing(unsigned char *block, + struct fb_videomode *mode) +{ + mode->xres = H_ACTIVE; + mode->yres = V_ACTIVE; + mode->pixclock = PIXEL_CLOCK; + mode->pixclock /= 1000; + mode->pixclock = KHZ2PICOS(mode->pixclock); + mode->right_margin = H_SYNC_OFFSET; + mode->left_margin = (H_ACTIVE + H_BLANKING) - + (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); + mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - + V_SYNC_WIDTH; + mode->lower_margin = V_SYNC_OFFSET; + mode->hsync_len = H_SYNC_WIDTH; + mode->vsync_len = V_SYNC_WIDTH; + if (HSYNC_POSITIVE) + mode->sync |= FB_SYNC_HOR_HIGH_ACT; + if (VSYNC_POSITIVE) + mode->sync |= FB_SYNC_VERT_HIGH_ACT; + mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * + (V_ACTIVE + V_BLANKING)); + if (INTERLACED) { + mode->yres *= 2; + mode->upper_margin *= 2; + mode->lower_margin *= 2; + mode->vsync_len *= 2; + mode->vmode |= FB_VMODE_INTERLACED; + } + + pr_debug(" %d MHz ", PIXEL_CLOCK/1000000); + pr_debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, + H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); + pr_debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, + V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); + pr_debug("%sHSync %sVSync\n", (HSYNC_POSITIVE) ? "+" : "-", + (VSYNC_POSITIVE) ? "+" : "-"); + + mode->name = asprintf("%dx%d@%d", mode->xres, mode->yres, mode->refresh); +} + +/** + * edid_to_display_timings - create video mode database + * @edid: EDID data + * @dbsize: database size + * + * RETURNS: struct fb_videomode, @dbsize contains length of database + * + * DESCRIPTION: + * This function builds a mode database using the contents of the EDID + * data + */ +int edid_to_display_timings(struct display_timings *timings, unsigned char *edid) +{ + struct fb_videomode *mode; + unsigned char *block; + int num = 0, i, first = 1; + int ver, rev, ret; + + ver = edid[EDID_STRUCT_VERSION]; + rev = edid[EDID_STRUCT_REVISION]; + + mode = xzalloc(50 * sizeof(struct fb_videomode)); + + if (!edid_checksum(edid) || + !edid_check_header(edid)) { + ret = -EINVAL; + goto out; + } + + pr_debug(" Detailed Timings\n"); + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + if (!(block[0] == 0x00 && block[1] == 0x00)) { + get_detailed_timing(block, &mode[num]); + if (first) { + first = 0; + } + num++; + } + } + + pr_debug(" Supported VESA Modes\n"); + block = edid + ESTABLISHED_TIMING_1; + num += get_est_timing(block, &mode[num]); + + pr_debug(" Standard Timings\n"); + block = edid + STD_TIMING_DESCRIPTIONS_START; + for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) + num += get_std_timing(block, &mode[num], ver, rev); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) + num += get_dst_timing(block + 5, &mode[num], ver, rev); + } + + /* Yikes, EDID data is totally useless */ + if (!num) { + free(mode); + return -EINVAL; + } + + timings->num_modes = num; + timings->modes = mode; + + return 0; +out: + free(timings); + free(mode); + return ret; +} + +#define DDC_ADDR 0x50 +#define DDC_SEGMENT_ADDR 0x30 + +/** + * Get EDID information via I2C. + * + * \param adapter : i2c device adaptor + * \param buf : EDID data buffer to be filled + * \param len : EDID data buffer length + * \return 0 on success or -1 on failure. + * + * Try to fetch EDID information by calling i2c driver function. + */ +static int +edid_do_read_i2c(struct i2c_adapter *adapter, unsigned char *buf, + int block, int len) +{ + unsigned char start = block * EDID_LENGTH; + unsigned char segment = block >> 1; + unsigned char xfers = segment ? 3 : 2; + int ret, retries = 5; + + /* The core i2c driver will automatically retry the transfer if the + * adapter reports EAGAIN. However, we find that bit-banging transfers + * are susceptible to errors under a heavily loaded machine and + * generate spurious NAKs and timeouts. Retrying the transfer + * of the individual block a few times seems to overcome this. + */ + do { + struct i2c_msg msgs[] = { + { + .addr = DDC_SEGMENT_ADDR, + .flags = 0, + .len = 1, + .buf = &segment, + }, { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + } + }; + + /* + * Avoid sending the segment addr to not upset non-compliant ddc + * monitors. + */ + ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers); + } while (ret != xfers && --retries); + + return ret == xfers ? 0 : -1; +} + +void *edid_read_i2c(struct i2c_adapter *adapter) +{ + u8 *block; + + block = xmalloc(EDID_LENGTH); + + if (edid_do_read_i2c(adapter, block, 0, EDID_LENGTH)) + goto out; + + return block; +out: + free(block); + + return NULL; +} + +void fb_edid_add_modes(struct fb_info *info) +{ + if (info->edid_i2c_adapter) + info->edid_data = edid_read_i2c(info->edid_i2c_adapter); + + if (!info->edid_data) + return; + + edid_to_display_timings(&info->edid_modes, info->edid_data); +} diff --git a/drivers/video/edid.h b/drivers/video/edid.h new file mode 100644 index 0000000000..006d9f2834 --- /dev/null +++ b/drivers/video/edid.h @@ -0,0 +1,138 @@ +/* + * drivers/video/edid.h - EDID/DDC Header + * + * Based on: + * 1. XFree86 4.3.0, edid.h + * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + * + * 2. John Fremlin <vii@users.sourceforge.net> and + * Ani Joshi <ajoshi@unixbox.com> + * + * DDC is a Trademark of VESA (Video Electronics Standard Association). + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. +*/ + +#ifndef __EDID_H__ +#define __EDID_H__ + +#define EDID_LENGTH 0x80 +#define EDID_HEADER 0x00 +#define EDID_HEADER_END 0x07 + +#define ID_MANUFACTURER_NAME 0x08 +#define ID_MANUFACTURER_NAME_END 0x09 +#define ID_MODEL 0x0a + +#define ID_SERIAL_NUMBER 0x0c + +#define MANUFACTURE_WEEK 0x10 +#define MANUFACTURE_YEAR 0x11 + +#define EDID_STRUCT_VERSION 0x12 +#define EDID_STRUCT_REVISION 0x13 + +#define EDID_STRUCT_DISPLAY 0x14 + +#define DPMS_FLAGS 0x18 +#define ESTABLISHED_TIMING_1 0x23 +#define ESTABLISHED_TIMING_2 0x24 +#define MANUFACTURERS_TIMINGS 0x25 + +/* standard timings supported */ +#define STD_TIMING 8 +#define STD_TIMING_DESCRIPTION_SIZE 2 +#define STD_TIMING_DESCRIPTIONS_START 0x26 + +#define DETAILED_TIMING_DESCRIPTIONS_START 0x36 +#define DETAILED_TIMING_DESCRIPTION_SIZE 18 +#define NO_DETAILED_TIMING_DESCRIPTIONS 4 + +#define DETAILED_TIMING_DESCRIPTION_1 0x36 +#define DETAILED_TIMING_DESCRIPTION_2 0x48 +#define DETAILED_TIMING_DESCRIPTION_3 0x5a +#define DETAILED_TIMING_DESCRIPTION_4 0x6c + +#define DESCRIPTOR_DATA 5 + +#define UPPER_NIBBLE( x ) \ + (((128|64|32|16) & (x)) >> 4) + +#define LOWER_NIBBLE( x ) \ + ((1|2|4|8) & (x)) + +#define COMBINE_HI_8LO( hi, lo ) \ + ( (((unsigned)hi) << 8) | (unsigned)lo ) + +#define COMBINE_HI_4LO( hi, lo ) \ + ( (((unsigned)hi) << 4) | (unsigned)lo ) + +#define PIXEL_CLOCK_LO (unsigned)block[ 0 ] +#define PIXEL_CLOCK_HI (unsigned)block[ 1 ] +#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000) +#define H_ACTIVE_LO (unsigned)block[ 2 ] +#define H_BLANKING_LO (unsigned)block[ 3 ] +#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO ) +#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO ) + +#define V_ACTIVE_LO (unsigned)block[ 5 ] +#define V_BLANKING_LO (unsigned)block[ 6 ] +#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO ) +#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO ) + +#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ] +#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ] + +#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] ) +#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] ) + +#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2)) +#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2) + +#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4) +#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6) + +#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) +#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) + +#define H_SYNC_WIDTH COMBINE_HI_8LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) +#define H_SYNC_OFFSET COMBINE_HI_8LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) + +#define H_SIZE_LO (unsigned)block[ 12 ] +#define V_SIZE_LO (unsigned)block[ 13 ] + +#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] ) +#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] ) + +#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO ) +#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO ) + +#define H_BORDER (unsigned)block[ 15 ] +#define V_BORDER (unsigned)block[ 16 ] + +#define FLAGS (unsigned)block[ 17 ] + +#define INTERLACED (FLAGS&128) +#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */ +#define SYNC_SEPARATE (3<<3) +#define HSYNC_POSITIVE (FLAGS & 4) +#define VSYNC_POSITIVE (FLAGS & 2) + +#define V_MIN_RATE block[ 5 ] +#define V_MAX_RATE block[ 6 ] +#define H_MIN_RATE block[ 7 ] +#define H_MAX_RATE block[ 8 ] +#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10) +#define GTF_SUPPORT block[10] + +#define DPMS_ACTIVE_OFF (1 << 5) +#define DPMS_SUSPEND (1 << 6) +#define DPMS_STANDBY (1 << 7) + +#endif /* __EDID_H__ */ diff --git a/drivers/video/fb.c b/drivers/video/fb.c index c36b9adcea..2c8b8eb25e 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -49,32 +49,45 @@ static int fb_enable_set(struct param_d *param, void *priv) return 0; } -static int fb_setup_mode(struct device_d *dev, struct param_d *param, - const char *val) +static struct fb_videomode *fb_num_to_mode(struct fb_info *info, int num) { - struct fb_info *info = dev->priv; - int mode, ret; + int num_modes; + + num_modes = info->modes.num_modes + info->edid_modes.num_modes; + + if (num >= num_modes) + return NULL; + + if (num >= info->modes.num_modes) + return &info->edid_modes.modes[num - info->modes.num_modes]; + + return &info->modes.modes[num]; +} + +static int fb_setup_mode(struct fb_info *info) +{ + struct device_d *dev = &info->dev; + int ret; + struct fb_videomode *mode; if (info->enabled != 0) return -EPERM; - if (!val) - return dev_param_set_generic(dev, param, NULL); - - for (mode = 0; mode < info->num_modes; mode++) { - if (!strcmp(info->mode_list[mode].name, val)) - break; - } - if (mode >= info->num_modes) + mode = fb_num_to_mode(info, info->current_mode); + if (!mode) return -EINVAL; - info->mode = &info->mode_list[mode]; + info->mode = mode; info->xres = info->mode->xres; info->yres = info->mode->yres; info->line_length = 0; - ret = info->fbops->fb_activate_var(info); + if (info->fbops->fb_activate_var) { + ret = info->fbops->fb_activate_var(info); + if (ret) + return ret; + } if (!info->line_length) info->line_length = info->xres * (info->bits_per_pixel >> 3); @@ -85,13 +98,24 @@ static int fb_setup_mode(struct device_d *dev, struct param_d *param, dev->resource[0].start = (resource_size_t)info->screen_base; info->cdev.size = info->line_length * info->yres; dev->resource[0].end = dev->resource[0].start + info->cdev.size - 1; - dev_param_set_generic(dev, param, val); } else info->cdev.size = 0; return ret; } +static int fb_set_modename(struct param_d *param, void *priv) +{ + struct fb_info *info = priv; + int ret; + + ret = fb_setup_mode(info); + if (ret) + return ret; + + return 0; +} + static struct file_operations fb_ops = { .read = mem_read, .write = mem_write, @@ -100,22 +124,28 @@ static struct file_operations fb_ops = { .ioctl = fb_ioctl, }; -static void fb_info(struct device_d *dev) +static void fb_print_mode(struct fb_videomode *mode) +{ + printf("%-20s %dx%d@%d\n", mode->name, + mode->xres, mode->yres, mode->refresh); +} + +static void fb_print_modes(struct display_timings *modes) { - struct fb_info *info = dev->priv; int i; - if (!info->num_modes) - return; + for (i = 0; i < modes->num_modes; i++) + fb_print_mode(&modes->modes[i]); +} + +static void fb_info(struct device_d *dev) +{ + struct fb_info *info = dev->priv; printf("available modes:\n"); - for (i = 0; i < info->num_modes; i++) { - struct fb_videomode *mode = &info->mode_list[i]; - - printf("%-10s %dx%d@%d\n", mode->name, - mode->xres, mode->yres, mode->refresh); - } + fb_print_modes(&info->modes); + fb_print_modes(&info->edid_modes); printf("\n"); } @@ -124,10 +154,20 @@ int register_framebuffer(struct fb_info *info) { int id = get_free_deviceid("fb"); struct device_d *dev; - int ret; + int ret, num_modes, i; + const char **names; dev = &info->dev; + /* + * If info->mode is set at this point it's the only mode + * the fb supports. move it over to the modes list. + */ + if (info->mode) { + info->modes.modes = info->mode; + info->modes.num_modes = 1; + } + if (!info->line_length) info->line_length = info->xres * (info->bits_per_pixel >> 3); @@ -155,11 +195,22 @@ int register_framebuffer(struct fb_info *info) dev_add_param_bool(dev, "enable", fb_enable_set, NULL, &info->p_enable, info); - if (info->num_modes && (info->mode_list != NULL) && - (info->fbops->fb_activate_var != NULL)) { - dev_add_param(dev, "mode_name", fb_setup_mode, NULL, 0); - dev_set_param(dev, "mode_name", info->mode_list[0].name); - } + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_EDID)) + fb_edid_add_modes(info); + + num_modes = info->modes.num_modes + info->edid_modes.num_modes; + + names = xzalloc(sizeof(char *) * num_modes); + + for (i = 0; i < info->modes.num_modes; i++) + names[i] = info->modes.modes[i].name; + for (i = 0; i < info->edid_modes.num_modes; i++) + names[i + info->modes.num_modes] = info->edid_modes.modes[i].name; + dev_add_param_enum(dev, "mode_name", fb_set_modename, NULL, &info->current_mode, names, num_modes, info); + + info->mode = fb_num_to_mode(info, 0); + + fb_setup_mode(info); ret = devfs_create(&info->cdev); if (ret) diff --git a/drivers/video/imx-ipu-fb.c b/drivers/video/imx-ipu-fb.c index 7276647382..abac812cb6 100644 --- a/drivers/video/imx-ipu-fb.c +++ b/drivers/video/imx-ipu-fb.c @@ -1007,8 +1007,8 @@ static int imxfb_probe(struct device_d *dev) fbi->disable_fractional_divider = pdata->disable_fractional_divider; info->priv = fbi; info->fbops = &imxfb_ops; - info->num_modes = pdata->num_modes; - info->mode_list = pdata->mode; + info->modes.modes = pdata->mode; + info->modes.num_modes = pdata->num_modes; imxfb_init_info(info, pdata->mode, pdata->bpp); @@ -1047,14 +1047,9 @@ static int imxfb_probe(struct device_d *dev) return ret; } -static void imxfb_remove(struct device_d *dev) -{ -} - static struct driver_d imx3fb_driver = { .name = "imx-ipu-fb", .probe = imxfb_probe, - .remove = imxfb_remove, }; device_platform_driver(imx3fb_driver); diff --git a/drivers/video/imx-ipu-v3/Kconfig b/drivers/video/imx-ipu-v3/Kconfig new file mode 100644 index 0000000000..3d656e5193 --- /dev/null +++ b/drivers/video/imx-ipu-v3/Kconfig @@ -0,0 +1,14 @@ +config DRIVER_VIDEO_IMX_IPUV3 + bool "i.MX IPUv3 driver" + help + Support the IPUv3 found on Freescale i.MX51/53/6 SoCs + +if DRIVER_VIDEO_IMX_IPUV3 + +config DRIVER_VIDEO_IMX_IPUV3_LVDS + bool "IPUv3 LVDS support" + +config DRIVER_VIDEO_IMX_IPUV3_HDMI + bool "IPUv3 HDMI support" + +endif diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile new file mode 100644 index 0000000000..2bc0aec5ae --- /dev/null +++ b/drivers/video/imx-ipu-v3/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-common.o ipu-dmfc.o ipu-di.o +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-dp.o ipuv3-plane.o ipufb.o +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += ipu-dc.o +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3_LVDS) += imx-ldb.o +obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3_HDMI) += imx-hdmi.o diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.c b/drivers/video/imx-ipu-v3/imx-hdmi.c new file mode 100644 index 0000000000..4f462889a8 --- /dev/null +++ b/drivers/video/imx-ipu-v3/imx-hdmi.c @@ -0,0 +1,1297 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * 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. + * + * SH-Mobile High-Definition Multimedia Interface (HDMI) driver + * for SLISHDMI13T and SLIPHDMIT IP cores + * + * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + */ +#include <common.h> +#include <fb.h> +#include <io.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <init.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <asm-generic/div64.h> +#include <linux/clk.h> +#include <i2c/i2c.h> +#include <mach/imx6-regs.h> +#include <mach/imx53-regs.h> + +#include "imx-ipu-v3.h" +#include "ipuv3-plane.h" +#include "imx-hdmi.h" + +#define HDMI_EDID_LEN 512 + +#define RGB 0 +#define YCBCR444 1 +#define YCBCR422_16BITS 2 +#define YCBCR422_8BITS 3 +#define XVYCC444 4 + +enum hdmi_colorimetry { + HDMI_COLORIMETRY_NONE, + HDMI_COLORIMETRY_ITU_601, + HDMI_COLORIMETRY_ITU_709, + HDMI_COLORIMETRY_EXTENDED, +}; + +enum hdmi_datamap { + RGB444_8B = 0x01, + RGB444_10B = 0x03, + RGB444_12B = 0x05, + RGB444_16B = 0x07, + YCbCr444_8B = 0x09, + YCbCr444_10B = 0x0B, + YCbCr444_12B = 0x0D, + YCbCr444_16B = 0x0F, + YCbCr422_8B = 0x16, + YCbCr422_10B = 0x14, + YCbCr422_12B = 0x12, +}; + +enum imx_hdmi_devtype { + IMX6Q_HDMI, + IMX6DL_HDMI, +}; + +static const u16 csc_coeff_default[3][4] = { + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 } +}; + +static const u16 csc_coeff_rgb_out_eitu601[3][4] = { + { 0x2000, 0x6926, 0x74fd, 0x010e }, + { 0x2000, 0x2cdd, 0x0000, 0x7e9a }, + { 0x2000, 0x0000, 0x38b4, 0x7e3b } +}; + +static const u16 csc_coeff_rgb_out_eitu709[3][4] = { + { 0x2000, 0x7106, 0x7a02, 0x00a7 }, + { 0x2000, 0x3264, 0x0000, 0x7e6d }, + { 0x2000, 0x0000, 0x3b61, 0x7e25 } +}; + +static const u16 csc_coeff_rgb_in_eitu601[3][4] = { + { 0x2591, 0x1322, 0x074b, 0x0000 }, + { 0x6535, 0x2000, 0x7acc, 0x0200 }, + { 0x6acd, 0x7534, 0x2000, 0x0200 } +}; + +static const u16 csc_coeff_rgb_in_eitu709[3][4] = { + { 0x2dc5, 0x0d9b, 0x049e, 0x0000 }, + { 0x62f0, 0x2000, 0x7d11, 0x0200 }, + { 0x6756, 0x78ab, 0x2000, 0x0200 } +}; + +struct hdmi_vmode { + bool mdvi; + bool mhsyncpolarity; + bool mvsyncpolarity; + bool minterlaced; + bool mdataenablepolarity; + + unsigned int mpixelclock; + unsigned int mpixelrepetitioninput; + unsigned int mpixelrepetitionoutput; +}; + +struct hdmi_data_info { + unsigned int enc_in_format; + unsigned int enc_out_format; + unsigned int enc_color_depth; + unsigned int colorimetry; + unsigned int pix_repet_factor; + unsigned int hdcp_enable; + struct hdmi_vmode video_mode; +}; + +struct imx_hdmi { + enum imx_hdmi_devtype dev_type; + struct device_d *dev; + struct clk *isfr_clk; + struct clk *iahb_clk; + + bool connected; + + struct hdmi_data_info hdmi_data; + int vic; + + u8 edid[HDMI_EDID_LEN]; + bool cable_plugin; + + bool phy_enabled; + + struct regmap *regmap; + struct i2c_adapter *ddc; + void __iomem *regs; + + unsigned int sample_rate; + int ratio; + + struct ipu_output output; +}; + +static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di) +{ + void __iomem *gpr3 = (void *)MX6_IOMUXC_BASE_ADDR + 0xc; + uint32_t val; + + dev_info(hdmi->dev, "setup hdmi mux to %d\n", ipu_di); + + val = readl(gpr3); + val &= ~(3 << 2); + val |= ipu_di << 2; + writel(val, gpr3); +} + +static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) +{ + writeb(val, hdmi->regs + offset); +} + +static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset) +{ + return readb(hdmi->regs + offset); +} + +static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) +{ + u8 val = hdmi_readb(hdmi, reg) & ~mask; + val |= data & mask; + hdmi_writeb(hdmi, val, reg); +} + +static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, + u8 shift, u8 mask) +{ + hdmi_modb(hdmi, data << shift, mask, reg); +} + +static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, + unsigned int value) +{ + hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); + hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); + hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); + + /* nshift factor = 0 */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); +} + +static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) +{ + /* Must be set/cleared first */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); + + hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); + hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); + hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | + HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); +} + +static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, + unsigned int ratio) +{ + unsigned int n = (128 * freq) / 1000; + + switch (freq) { + case 32000: + if (pixel_clk == 25170000) + n = (ratio == 150) ? 9152 : 4576; + else if (pixel_clk == 27020000) + n = (ratio == 150) ? 8192 : 4096; + else if (pixel_clk == 74170000 || pixel_clk == 148350000) + n = 11648; + else + n = 4096; + break; + + case 44100: + if (pixel_clk == 25170000) + n = 7007; + else if (pixel_clk == 74170000) + n = 17836; + else if (pixel_clk == 148350000) + n = (ratio == 150) ? 17836 : 8918; + else + n = 6272; + break; + + case 48000: + if (pixel_clk == 25170000) + n = (ratio == 150) ? 9152 : 6864; + else if (pixel_clk == 27020000) + n = (ratio == 150) ? 8192 : 6144; + else if (pixel_clk == 74170000) + n = 11648; + else if (pixel_clk == 148350000) + n = (ratio == 150) ? 11648 : 5824; + else + n = 6144; + break; + + case 88200: + n = hdmi_compute_n(44100, pixel_clk, ratio) * 2; + break; + + case 96000: + n = hdmi_compute_n(48000, pixel_clk, ratio) * 2; + break; + + case 176400: + n = hdmi_compute_n(44100, pixel_clk, ratio) * 4; + break; + + case 192000: + n = hdmi_compute_n(48000, pixel_clk, ratio) * 4; + break; + + default: + break; + } + + return n; +} + +static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, + unsigned int ratio) +{ + unsigned int cts = 0; + + pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq, + pixel_clk, ratio); + + switch (freq) { + case 32000: + if (pixel_clk == 297000000) { + cts = 222750; + break; + } + case 48000: + case 96000: + case 192000: + switch (pixel_clk) { + case 25200000: + case 27000000: + case 54000000: + case 74250000: + case 148500000: + cts = pixel_clk / 1000; + break; + case 297000000: + cts = 247500; + break; + /* + * All other TMDS clocks are not supported by + * DWC_hdmi_tx. The TMDS clocks divided or + * multiplied by 1,001 coefficients are not + * supported. + */ + default: + break; + } + break; + case 44100: + case 88200: + case 176400: + switch (pixel_clk) { + case 25200000: + cts = 28000; + break; + case 27000000: + cts = 30000; + break; + case 54000000: + cts = 60000; + break; + case 74250000: + cts = 82500; + break; + case 148500000: + cts = 165000; + break; + case 297000000: + cts = 247500; + break; + default: + break; + } + break; + default: + break; + } + if (ratio == 100) + return cts; + else + return (cts * ratio) / 100; +} + +static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, + unsigned long pixel_clk) +{ + unsigned int clk_n, clk_cts; + + clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk, + hdmi->ratio); + clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk, + hdmi->ratio); + + if (!clk_cts) { + dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", + __func__, pixel_clk); + return; + } + + dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", + __func__, hdmi->sample_rate, hdmi->ratio, + pixel_clk, clk_n, clk_cts); + + hdmi_set_clock_regenerator_n(hdmi, clk_n); + hdmi_regenerate_cts(hdmi, clk_cts); +} + +static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi) +{ + hdmi_set_clk_regenerator(hdmi, 74250000); +} + +/* + * this submodule is responsible for the video data synchronization. + * for example, for RGB 4:4:4 input, the data map is defined as + * pin{47~40} <==> R[7:0] + * pin{31~24} <==> G[7:0] + * pin{15~8} <==> B[7:0] + */ +static void hdmi_video_sample(struct imx_hdmi *hdmi) +{ + int color_format = 0; + u8 val; + + if (hdmi->hdmi_data.enc_in_format == RGB) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x01; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x03; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x05; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_format = 0x07; + else + return; + } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x09; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x0B; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x0D; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_format = 0x0F; + else + return; + } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x16; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x14; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x12; + else + return; + } + + val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | + ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) & + HDMI_TX_INVID0_VIDEO_MAPPING_MASK); + hdmi_writeb(hdmi, val, HDMI_TX_INVID0); + + /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */ + val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; + hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING); + hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1); + hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1); + hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1); +} + +static int is_color_space_conversion(struct imx_hdmi *hdmi) +{ + return (hdmi->hdmi_data.enc_in_format != + hdmi->hdmi_data.enc_out_format); +} + +static int is_color_space_decimation(struct imx_hdmi *hdmi) +{ + return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) && + (hdmi->hdmi_data.enc_in_format == RGB || + hdmi->hdmi_data.enc_in_format == YCBCR444)); +} + +static int is_color_space_interpolation(struct imx_hdmi *hdmi) +{ + return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) && + (hdmi->hdmi_data.enc_out_format == RGB || + hdmi->hdmi_data.enc_out_format == YCBCR444)); +} + +static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) +{ + const u16 (*csc_coeff)[3][4] = &csc_coeff_default; + unsigned i; + u32 csc_scale = 1; + + if (is_color_space_conversion(hdmi)) { + if (hdmi->hdmi_data.enc_out_format == RGB) { + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) + csc_coeff = &csc_coeff_rgb_out_eitu601; + else + csc_coeff = &csc_coeff_rgb_out_eitu709; + } else if (hdmi->hdmi_data.enc_in_format == RGB) { + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) + csc_coeff = &csc_coeff_rgb_in_eitu601; + else + csc_coeff = &csc_coeff_rgb_in_eitu709; + csc_scale = 0; + } + } + + /* The CSC registers are sequential, alternating MSB then LSB */ + for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) { + u16 coeff_a = (*csc_coeff)[0][i]; + u16 coeff_b = (*csc_coeff)[1][i]; + u16 coeff_c = (*csc_coeff)[2][i]; + + hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); + } + + hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK, + HDMI_CSC_SCALE); +} + +static void hdmi_video_csc(struct imx_hdmi *hdmi) +{ + int color_depth = 0; + int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; + int decimation = 0; + + /* YCC422 interpolation to 444 mode */ + if (is_color_space_interpolation(hdmi)) + interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1; + else if (is_color_space_decimation(hdmi)) + decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3; + + if (hdmi->hdmi_data.enc_color_depth == 8) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP; + else + return; + + /* Configure the CSC registers */ + hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); + hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, + HDMI_CSC_SCALE); + + imx_hdmi_update_csc_coeffs(hdmi); +} + +/* + * HDMI video packetizer is used to packetize the data. + * for example, if input is YCC422 mode or repeater is used, + * data should be repacked this module can be bypassed. + */ +static void hdmi_video_packetize(struct imx_hdmi *hdmi) +{ + unsigned int color_depth = 0; + unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; + unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; + struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; + u8 val, vp_conf; + + if (hdmi_data->enc_out_format == RGB + || hdmi_data->enc_out_format == YCBCR444) { + if (!hdmi_data->enc_color_depth) + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; + else if (hdmi_data->enc_color_depth == 8) { + color_depth = 4; + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; + } else if (hdmi_data->enc_color_depth == 10) + color_depth = 5; + else if (hdmi_data->enc_color_depth == 12) + color_depth = 6; + else if (hdmi_data->enc_color_depth == 16) + color_depth = 7; + else + return; + } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { + if (!hdmi_data->enc_color_depth || + hdmi_data->enc_color_depth == 8) + remap_size = HDMI_VP_REMAP_YCC422_16bit; + else if (hdmi_data->enc_color_depth == 10) + remap_size = HDMI_VP_REMAP_YCC422_20bit; + else if (hdmi_data->enc_color_depth == 12) + remap_size = HDMI_VP_REMAP_YCC422_24bit; + else + return; + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; + } else + return; + + /* set the packetizer registers */ + val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & + HDMI_VP_PR_CD_COLOR_DEPTH_MASK) | + ((hdmi_data->pix_repet_factor << + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) & + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); + hdmi_writeb(hdmi, val, HDMI_VP_PR_CD); + + hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF); + + /* Data from pixel repeater block */ + if (hdmi_data->pix_repet_factor > 1) { + vp_conf = HDMI_VP_CONF_PR_EN_ENABLE | + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; + } else { /* data from packetizer block */ + vp_conf = HDMI_VP_CONF_PR_EN_DISABLE | + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; + } + + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_PR_EN_MASK | + HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF); + + hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET, + HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); + + hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); + + if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_ENABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; + } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_ENABLE; + } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { + vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; + } else { + return; + } + + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF); + + hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PP_STUFFING_MASK | + HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF); + + hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, + HDMI_VP_CONF); +} + +static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, + HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, + HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, + HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); +} + +static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); +} + +static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) +{ + unsigned char val = 0; + val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; + while (!val) { + udelay(1000); + if (msec-- == 0) + return false; + val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; + } + return true; +} + +static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, + unsigned char addr) +{ + hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); + hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); + hdmi_writeb(hdmi, (unsigned char)(data >> 8), + HDMI_PHY_I2CM_DATAO_1_ADDR); + hdmi_writeb(hdmi, (unsigned char)(data >> 0), + HDMI_PHY_I2CM_DATAO_0_ADDR); + hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, + HDMI_PHY_I2CM_OPERATION_ADDR); + hdmi_phy_wait_i2c_done(hdmi, 1000); +} + +static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, + unsigned char addr) +{ + __hdmi_phy_i2c_write(hdmi, data, addr); + return 0; +} + +static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_PDZ_OFFSET, + HDMI_PHY_CONF0_PDZ_MASK); +} + +static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_ENTMDS_OFFSET, + HDMI_PHY_CONF0_ENTMDS_MASK); +} + +static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET, + HDMI_PHY_CONF0_GEN2_PDDQ_MASK); +} + +static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET, + HDMI_PHY_CONF0_GEN2_TXPWRON_MASK); +} + +static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_SELDATAENPOL_OFFSET, + HDMI_PHY_CONF0_SELDATAENPOL_MASK); +} + +static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_SELDIPIF_OFFSET, + HDMI_PHY_CONF0_SELDIPIF_MASK); +} + +enum { + RES_8, + RES_10, + RES_12, + RES_MAX, +}; + +struct mpll_config { + unsigned long mpixelclock; + struct { + u16 cpce; + u16 gmp; + } res[RES_MAX]; +}; + +static const struct mpll_config mpll_config[] = { + { + 45250000, { + { 0x01e0, 0x0000 }, + { 0x21e1, 0x0000 }, + { 0x41e2, 0x0000 } + }, + }, { + 92500000, { + { 0x0140, 0x0005 }, + { 0x2141, 0x0005 }, + { 0x4142, 0x0005 }, + }, + }, { + 148500000, { + { 0x00a0, 0x000a }, + { 0x20a1, 0x000a }, + { 0x40a2, 0x000a }, + }, + }, { + ~0UL, { + { 0x00a0, 0x000a }, + { 0x2001, 0x000f }, + { 0x4002, 0x000f }, + }, + } +}; + +struct curr_ctrl { + unsigned long mpixelclock; + u16 curr[RES_MAX]; +}; + +static const struct curr_ctrl curr_ctrl[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { + 54000000, { 0x091c, 0x091c, 0x06dc }, + }, { + 58400000, { 0x091c, 0x06dc, 0x06dc }, + }, { + 72000000, { 0x06dc, 0x06dc, 0x091c }, + }, { + 74250000, { 0x06dc, 0x0b5c, 0x091c }, + }, { + 118800000, { 0x091c, 0x091c, 0x06dc }, + }, { + 216000000, { 0x06dc, 0x0b5c, 0x091c }, + } +}; + +static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, + unsigned char res, int cscon) +{ + unsigned res_idx, i; + u8 val, msec; + + if (prep) + return -EINVAL; + + switch (res) { + case 0: /* color resolution 0 is 8 bit colour depth */ + case 8: + res_idx = RES_8; + break; + case 10: + res_idx = RES_10; + break; + case 12: + res_idx = RES_12; + break; + default: + return -EINVAL; + } + + /* Enable csc path */ + if (cscon) + val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH; + else + val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS; + + hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); + + /* gen2 tx power off */ + imx_hdmi_phy_gen2_txpwron(hdmi, 0); + + /* gen2 pddq */ + imx_hdmi_phy_gen2_pddq(hdmi, 1); + + /* PHY reset */ + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ); + + hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST); + + hdmi_phy_test_clear(hdmi, 1); + hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, + HDMI_PHY_I2CM_SLAVE_ADDR); + hdmi_phy_test_clear(hdmi, 0); + + /* PLL/MPLL Cfg - always match on final entry */ + for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + mpll_config[i].mpixelclock) + break; + + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); + + for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + curr_ctrl[i].mpixelclock) + break; + + if (i >= ARRAY_SIZE(curr_ctrl)) { + dev_err(hdmi->dev, + "Pixel clock %d - unsupported by HDMI\n", + hdmi->hdmi_data.video_mode.mpixelclock); + return -EINVAL; + } + + /* CURRCTRL */ + hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); + + hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ + hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); + /* RESISTANCE TERM 133Ohm Cfg */ + hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */ + /* PREEMP Cgf 0.00 */ + hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */ + /* TX/CK LVL 10 */ + hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ + /* REMOVE CLK TERM */ + hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ + + imx_hdmi_phy_enable_power(hdmi, 1); + + /* toggle TMDS enable */ + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_tmds(hdmi, 1); + + /* gen2 tx power on */ + imx_hdmi_phy_gen2_txpwron(hdmi, 1); + imx_hdmi_phy_gen2_pddq(hdmi, 0); + + /*Wait for PHY PLL lock */ + msec = 5; + do { + val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; + if (!val) + break; + + if (msec == 0) { + dev_err(hdmi->dev, "PHY PLL not locked\n"); + return -ETIMEDOUT; + } + + udelay(1000); + msec--; + } while (1); + + return 0; +} + +static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) +{ + int i, ret; + bool cscon = false; + + /*check csc whether needed activated in HDMI mode */ + cscon = (is_color_space_conversion(hdmi) && + !hdmi->hdmi_data.video_mode.mdvi); + + /* HDMI Phy spec says to do the phy initialization sequence twice */ + for (i = 0; i < 2; i++) { + imx_hdmi_phy_sel_data_en_pol(hdmi, 1); + imx_hdmi_phy_sel_interface_control(hdmi, 0); + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_power(hdmi, 0); + + /* Enable CSC */ + ret = hdmi_phy_configure(hdmi, 0, 8, cscon); + if (ret) + return ret; + } + + hdmi->phy_enabled = true; + return 0; +} + +static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) +{ + u8 de; + + if (hdmi->hdmi_data.video_mode.mdataenablepolarity) + de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; + else + de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; + + /* disable rx detect */ + hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE, + HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0); + + hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG); + + hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); +} + +static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi) +{ + if (!hdmi->phy_enabled) + return; + + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_power(hdmi, 0); + + hdmi->phy_enabled = false; +} + +/* HDMI Initialization Step B.4 */ +static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) +{ + u8 clkdis; + + /* control period minimum duration */ + hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); + hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); + hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC); + + /* Set to fill TMDS data channels */ + hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM); + hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM); + hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); + + /* Enable pixel clock and tmds data path */ + clkdis = 0x7F; + clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + + clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + + /* Enable csc path */ + if (is_color_space_conversion(hdmi)) { + clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + } +} + +/* Workaround to clear the overflow condition */ +static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi) +{ + int count; + u8 val; + + /* TMDS software reset */ + hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ); + + val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF); + if (hdmi->dev_type == IMX6DL_HDMI) { + hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); + return; + } + + for (count = 0; count < 4; count++) + hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); +} + +static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct fb_videomode *mode) +{ + int ret; + + hdmi->vic = 0; + + dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n"); + hdmi->hdmi_data.video_mode.mdvi = true; + + hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; + hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; + + /* TODO: Get input format from IPU (via FB driver interface) */ + hdmi->hdmi_data.enc_in_format = RGB; + + hdmi->hdmi_data.enc_out_format = RGB; + + hdmi->hdmi_data.enc_color_depth = 8; + hdmi->hdmi_data.pix_repet_factor = 0; + hdmi->hdmi_data.hdcp_enable = 0; + hdmi->hdmi_data.video_mode.mdataenablepolarity = true; + + /* HDMI Initializateion Step B.2 */ + ret = imx_hdmi_phy_init(hdmi); + if (ret) + return ret; + + /* HDMI Initialization Step B.3 */ + imx_hdmi_enable_video_path(hdmi); + + /* not for DVI mode */ + dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); + + hdmi_video_packetize(hdmi); + hdmi_video_csc(hdmi); + hdmi_video_sample(hdmi); + hdmi_tx_hdcp_config(hdmi); + + imx_hdmi_clear_overflow(hdmi); + + return 0; +} + +static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi) +{ + u8 ih_mute; + + /* + * Boot up defaults are: + * HDMI_IH_MUTE = 0x03 (disabled) + * HDMI_IH_MUTE_* = 0x00 (enabled) + * + * Disable top level interrupt bits in HDMI block + */ + ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) | + HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; + + hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); + + /* by default mask all interrupts */ + hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK); + hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT); + hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT); + + /* Disable interrupts in the IH_MUTE_* registers */ + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + /* Enable top level interrupt bits in HDMI block */ + ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT); + hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); +} + +struct imx_hdmi_data { + unsigned ipu_mask; + enum imx_hdmi_devtype devtype; +}; + +static struct imx_hdmi_data imx6q_hdmi_data = { + .ipu_mask = 0xf, + .devtype = IMX6Q_HDMI, +}; + +static struct imx_hdmi_data imx6dl_hdmi_data = { + .ipu_mask = 0x3, + .devtype = IMX6DL_HDMI, +}; + +static struct of_device_id imx_hdmi_dt_ids[] = { + { + .compatible = "fsl,imx6q-hdmi", + .data = (unsigned long)&imx6q_hdmi_data, + }, { + .compatible = "fsl,imx6dl-hdmi", + .data = (unsigned long)&imx6dl_hdmi_data, + }, { + /* sentinel */ + } +}; + +static int imx_hdmi_prepare(struct ipu_output *output, struct fb_videomode *mode, int di) +{ + struct imx_hdmi *hdmi = container_of(output, struct imx_hdmi, output); + + imx_hdmi_set_ipu_di_mux(hdmi, di); + + return 0; +} + +static int imx_hdmi_commit(struct ipu_output *output, struct fb_videomode *mode, int di) +{ + struct imx_hdmi *hdmi = container_of(output, struct imx_hdmi, output); + + imx_hdmi_setup(hdmi, mode); + + return 0; +} + +static int imx_hdmi_disable(struct ipu_output *output) +{ + struct imx_hdmi *hdmi = container_of(output, struct imx_hdmi, output); + + imx_hdmi_phy_disable(hdmi); + + return 0; +} + +static struct ipu_output_ops imx_hdmi_ops = { + .prepare = imx_hdmi_prepare, + .enable = imx_hdmi_commit, + .disable = imx_hdmi_disable, +}; + +static int imx_hdmi_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct device_node *ddc_node; + struct imx_hdmi *hdmi; + int ret; + const struct imx_hdmi_data *devtype; + + ret = dev_get_drvdata(dev, (unsigned long *)&devtype); + if (ret) + return ret; + + hdmi = xzalloc(sizeof(*hdmi)); + + hdmi->dev = dev; + hdmi->connected = 0; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; + + ret = dev_get_drvdata(dev, (unsigned long *)&hdmi->dev_type); + if (ret) + return ret; + + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); + if (ddc_node) { + hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); + if (!hdmi->ddc) + dev_dbg(hdmi->dev, "failed to read ddc node\n"); + } else { + dev_dbg(hdmi->dev, "no ddc property found\n"); + } + + ddc_node = NULL; + + hdmi->regs = dev_request_mem_region(dev, 0); + if (!hdmi->regs) + return -EBUSY; + + hdmi->isfr_clk = clk_get(hdmi->dev, "isfr"); + if (IS_ERR(hdmi->isfr_clk)) { + ret = PTR_ERR(hdmi->isfr_clk); + dev_err(dev, + "Unable to get HDMI isfr clk: %d\n", ret); + return ret; + } + + ret = clk_enable(hdmi->isfr_clk); + if (ret) + return ret; + + hdmi->iahb_clk = clk_get(hdmi->dev, "iahb"); + if (IS_ERR(hdmi->iahb_clk)) { + ret = PTR_ERR(hdmi->iahb_clk); + dev_err(dev, + "Unable to get HDMI iahb clk: %d\n", ret); + goto err_isfr; + } + + ret = clk_enable(hdmi->iahb_clk); + if (ret) + goto err_isfr; + + /* Product and revision IDs */ + dev_info(dev, + "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", + hdmi_readb(hdmi, HDMI_DESIGN_ID), + hdmi_readb(hdmi, HDMI_REVISION_ID), + hdmi_readb(hdmi, HDMI_PRODUCT_ID0), + hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); + + initialize_hdmi_ih_mutes(hdmi); + + /* + * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator + * N and cts values before enabling phy + */ + hdmi_init_clk_regenerator(hdmi); + + /* + * Configure registers related to HDMI interrupt + * generation before registering IRQ. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0); + + /* Clear Hotplug interrupts */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + + hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, + HDMI_PHY_I2CM_INT_ADDR); + + hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, + HDMI_PHY_I2CM_CTLINT_ADDR); + + /* enable cable hot plug irq */ + hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0); + + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); + + hdmi->output.ops = &imx_hdmi_ops; + hdmi->output.di_clkflags = IPU_DI_CLKMODE_EXT | IPU_DI_CLKMODE_SYNC; + hdmi->output.out_pixel_fmt = V4L2_PIX_FMT_RGB24; + hdmi->output.name = asprintf("hdmi-0"); + hdmi->output.ipu_mask = devtype->ipu_mask; + hdmi->output.edid_i2c_adapter = hdmi->ddc; + hdmi->output.modes = of_get_display_timings(np); + + ipu_register_output(&hdmi->output); + + return 0; + +err_isfr: + clk_disable(hdmi->isfr_clk); + + return ret; +} + +static struct driver_d imx_hdmi_driver = { + .probe = imx_hdmi_probe, + .of_compatible = imx_hdmi_dt_ids, + .name = "imx-hdmi", +}; +device_platform_driver(imx_hdmi_driver); + +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.h b/drivers/video/imx-ipu-v3/imx-hdmi.h new file mode 100644 index 0000000000..39b677689d --- /dev/null +++ b/drivers/video/imx-ipu-v3/imx-hdmi.h @@ -0,0 +1,1032 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef __IMX_HDMI_H__ +#define __IMX_HDMI_H__ + +/* Identification Registers */ +#define HDMI_DESIGN_ID 0x0000 +#define HDMI_REVISION_ID 0x0001 +#define HDMI_PRODUCT_ID0 0x0002 +#define HDMI_PRODUCT_ID1 0x0003 +#define HDMI_CONFIG0_ID 0x0004 +#define HDMI_CONFIG1_ID 0x0005 +#define HDMI_CONFIG2_ID 0x0006 +#define HDMI_CONFIG3_ID 0x0007 + +/* Interrupt Registers */ +#define HDMI_IH_FC_STAT0 0x0100 +#define HDMI_IH_FC_STAT1 0x0101 +#define HDMI_IH_FC_STAT2 0x0102 +#define HDMI_IH_AS_STAT0 0x0103 +#define HDMI_IH_PHY_STAT0 0x0104 +#define HDMI_IH_I2CM_STAT0 0x0105 +#define HDMI_IH_CEC_STAT0 0x0106 +#define HDMI_IH_VP_STAT0 0x0107 +#define HDMI_IH_I2CMPHY_STAT0 0x0108 +#define HDMI_IH_AHBDMAAUD_STAT0 0x0109 + +#define HDMI_IH_MUTE_FC_STAT0 0x0180 +#define HDMI_IH_MUTE_FC_STAT1 0x0181 +#define HDMI_IH_MUTE_FC_STAT2 0x0182 +#define HDMI_IH_MUTE_AS_STAT0 0x0183 +#define HDMI_IH_MUTE_PHY_STAT0 0x0184 +#define HDMI_IH_MUTE_I2CM_STAT0 0x0185 +#define HDMI_IH_MUTE_CEC_STAT0 0x0186 +#define HDMI_IH_MUTE_VP_STAT0 0x0187 +#define HDMI_IH_MUTE_I2CMPHY_STAT0 0x0188 +#define HDMI_IH_MUTE_AHBDMAAUD_STAT0 0x0189 +#define HDMI_IH_MUTE 0x01FF + +/* Video Sample Registers */ +#define HDMI_TX_INVID0 0x0200 +#define HDMI_TX_INSTUFFING 0x0201 +#define HDMI_TX_GYDATA0 0x0202 +#define HDMI_TX_GYDATA1 0x0203 +#define HDMI_TX_RCRDATA0 0x0204 +#define HDMI_TX_RCRDATA1 0x0205 +#define HDMI_TX_BCBDATA0 0x0206 +#define HDMI_TX_BCBDATA1 0x0207 + +/* Video Packetizer Registers */ +#define HDMI_VP_STATUS 0x0800 +#define HDMI_VP_PR_CD 0x0801 +#define HDMI_VP_STUFF 0x0802 +#define HDMI_VP_REMAP 0x0803 +#define HDMI_VP_CONF 0x0804 +#define HDMI_VP_STAT 0x0805 +#define HDMI_VP_INT 0x0806 +#define HDMI_VP_MASK 0x0807 +#define HDMI_VP_POL 0x0808 + +/* Frame Composer Registers */ +#define HDMI_FC_INVIDCONF 0x1000 +#define HDMI_FC_INHACTV0 0x1001 +#define HDMI_FC_INHACTV1 0x1002 +#define HDMI_FC_INHBLANK0 0x1003 +#define HDMI_FC_INHBLANK1 0x1004 +#define HDMI_FC_INVACTV0 0x1005 +#define HDMI_FC_INVACTV1 0x1006 +#define HDMI_FC_INVBLANK 0x1007 +#define HDMI_FC_HSYNCINDELAY0 0x1008 +#define HDMI_FC_HSYNCINDELAY1 0x1009 +#define HDMI_FC_HSYNCINWIDTH0 0x100A +#define HDMI_FC_HSYNCINWIDTH1 0x100B +#define HDMI_FC_VSYNCINDELAY 0x100C +#define HDMI_FC_VSYNCINWIDTH 0x100D +#define HDMI_FC_INFREQ0 0x100E +#define HDMI_FC_INFREQ1 0x100F +#define HDMI_FC_INFREQ2 0x1010 +#define HDMI_FC_CTRLDUR 0x1011 +#define HDMI_FC_EXCTRLDUR 0x1012 +#define HDMI_FC_EXCTRLSPAC 0x1013 +#define HDMI_FC_CH0PREAM 0x1014 +#define HDMI_FC_CH1PREAM 0x1015 +#define HDMI_FC_CH2PREAM 0x1016 +#define HDMI_FC_AVICONF3 0x1017 +#define HDMI_FC_GCP 0x1018 +#define HDMI_FC_AVICONF0 0x1019 +#define HDMI_FC_AVICONF1 0x101A +#define HDMI_FC_AVICONF2 0x101B +#define HDMI_FC_AVIVID 0x101C +#define HDMI_FC_AVIETB0 0x101D +#define HDMI_FC_AVIETB1 0x101E +#define HDMI_FC_AVISBB0 0x101F +#define HDMI_FC_AVISBB1 0x1020 +#define HDMI_FC_AVIELB0 0x1021 +#define HDMI_FC_AVIELB1 0x1022 +#define HDMI_FC_AVISRB0 0x1023 +#define HDMI_FC_AVISRB1 0x1024 +#define HDMI_FC_AUDICONF0 0x1025 +#define HDMI_FC_AUDICONF1 0x1026 +#define HDMI_FC_AUDICONF2 0x1027 +#define HDMI_FC_AUDICONF3 0x1028 +#define HDMI_FC_VSDIEEEID0 0x1029 +#define HDMI_FC_VSDSIZE 0x102A +#define HDMI_FC_VSDIEEEID1 0x1030 +#define HDMI_FC_VSDIEEEID2 0x1031 +#define HDMI_FC_VSDPAYLOAD0 0x1032 +#define HDMI_FC_VSDPAYLOAD1 0x1033 +#define HDMI_FC_VSDPAYLOAD2 0x1034 +#define HDMI_FC_VSDPAYLOAD3 0x1035 +#define HDMI_FC_VSDPAYLOAD4 0x1036 +#define HDMI_FC_VSDPAYLOAD5 0x1037 +#define HDMI_FC_VSDPAYLOAD6 0x1038 +#define HDMI_FC_VSDPAYLOAD7 0x1039 +#define HDMI_FC_VSDPAYLOAD8 0x103A +#define HDMI_FC_VSDPAYLOAD9 0x103B +#define HDMI_FC_VSDPAYLOAD10 0x103C +#define HDMI_FC_VSDPAYLOAD11 0x103D +#define HDMI_FC_VSDPAYLOAD12 0x103E +#define HDMI_FC_VSDPAYLOAD13 0x103F +#define HDMI_FC_VSDPAYLOAD14 0x1040 +#define HDMI_FC_VSDPAYLOAD15 0x1041 +#define HDMI_FC_VSDPAYLOAD16 0x1042 +#define HDMI_FC_VSDPAYLOAD17 0x1043 +#define HDMI_FC_VSDPAYLOAD18 0x1044 +#define HDMI_FC_VSDPAYLOAD19 0x1045 +#define HDMI_FC_VSDPAYLOAD20 0x1046 +#define HDMI_FC_VSDPAYLOAD21 0x1047 +#define HDMI_FC_VSDPAYLOAD22 0x1048 +#define HDMI_FC_VSDPAYLOAD23 0x1049 +#define HDMI_FC_SPDVENDORNAME0 0x104A +#define HDMI_FC_SPDVENDORNAME1 0x104B +#define HDMI_FC_SPDVENDORNAME2 0x104C +#define HDMI_FC_SPDVENDORNAME3 0x104D +#define HDMI_FC_SPDVENDORNAME4 0x104E +#define HDMI_FC_SPDVENDORNAME5 0x104F +#define HDMI_FC_SPDVENDORNAME6 0x1050 +#define HDMI_FC_SPDVENDORNAME7 0x1051 +#define HDMI_FC_SDPPRODUCTNAME0 0x1052 +#define HDMI_FC_SDPPRODUCTNAME1 0x1053 +#define HDMI_FC_SDPPRODUCTNAME2 0x1054 +#define HDMI_FC_SDPPRODUCTNAME3 0x1055 +#define HDMI_FC_SDPPRODUCTNAME4 0x1056 +#define HDMI_FC_SDPPRODUCTNAME5 0x1057 +#define HDMI_FC_SDPPRODUCTNAME6 0x1058 +#define HDMI_FC_SDPPRODUCTNAME7 0x1059 +#define HDMI_FC_SDPPRODUCTNAME8 0x105A +#define HDMI_FC_SDPPRODUCTNAME9 0x105B +#define HDMI_FC_SDPPRODUCTNAME10 0x105C +#define HDMI_FC_SDPPRODUCTNAME11 0x105D +#define HDMI_FC_SDPPRODUCTNAME12 0x105E +#define HDMI_FC_SDPPRODUCTNAME13 0x105F +#define HDMI_FC_SDPPRODUCTNAME14 0x1060 +#define HDMI_FC_SPDPRODUCTNAME15 0x1061 +#define HDMI_FC_SPDDEVICEINF 0x1062 +#define HDMI_FC_AUDSCONF 0x1063 +#define HDMI_FC_AUDSSTAT 0x1064 +#define HDMI_FC_DATACH0FILL 0x1070 +#define HDMI_FC_DATACH1FILL 0x1071 +#define HDMI_FC_DATACH2FILL 0x1072 +#define HDMI_FC_CTRLQHIGH 0x1073 +#define HDMI_FC_CTRLQLOW 0x1074 +#define HDMI_FC_ACP0 0x1075 +#define HDMI_FC_ACP28 0x1076 +#define HDMI_FC_ACP27 0x1077 +#define HDMI_FC_ACP26 0x1078 +#define HDMI_FC_ACP25 0x1079 +#define HDMI_FC_ACP24 0x107A +#define HDMI_FC_ACP23 0x107B +#define HDMI_FC_ACP22 0x107C +#define HDMI_FC_ACP21 0x107D +#define HDMI_FC_ACP20 0x107E +#define HDMI_FC_ACP19 0x107F +#define HDMI_FC_ACP18 0x1080 +#define HDMI_FC_ACP17 0x1081 +#define HDMI_FC_ACP16 0x1082 +#define HDMI_FC_ACP15 0x1083 +#define HDMI_FC_ACP14 0x1084 +#define HDMI_FC_ACP13 0x1085 +#define HDMI_FC_ACP12 0x1086 +#define HDMI_FC_ACP11 0x1087 +#define HDMI_FC_ACP10 0x1088 +#define HDMI_FC_ACP9 0x1089 +#define HDMI_FC_ACP8 0x108A +#define HDMI_FC_ACP7 0x108B +#define HDMI_FC_ACP6 0x108C +#define HDMI_FC_ACP5 0x108D +#define HDMI_FC_ACP4 0x108E +#define HDMI_FC_ACP3 0x108F +#define HDMI_FC_ACP2 0x1090 +#define HDMI_FC_ACP1 0x1091 +#define HDMI_FC_ISCR1_0 0x1092 +#define HDMI_FC_ISCR1_16 0x1093 +#define HDMI_FC_ISCR1_15 0x1094 +#define HDMI_FC_ISCR1_14 0x1095 +#define HDMI_FC_ISCR1_13 0x1096 +#define HDMI_FC_ISCR1_12 0x1097 +#define HDMI_FC_ISCR1_11 0x1098 +#define HDMI_FC_ISCR1_10 0x1099 +#define HDMI_FC_ISCR1_9 0x109A +#define HDMI_FC_ISCR1_8 0x109B +#define HDMI_FC_ISCR1_7 0x109C +#define HDMI_FC_ISCR1_6 0x109D +#define HDMI_FC_ISCR1_5 0x109E +#define HDMI_FC_ISCR1_4 0x109F +#define HDMI_FC_ISCR1_3 0x10A0 +#define HDMI_FC_ISCR1_2 0x10A1 +#define HDMI_FC_ISCR1_1 0x10A2 +#define HDMI_FC_ISCR2_15 0x10A3 +#define HDMI_FC_ISCR2_14 0x10A4 +#define HDMI_FC_ISCR2_13 0x10A5 +#define HDMI_FC_ISCR2_12 0x10A6 +#define HDMI_FC_ISCR2_11 0x10A7 +#define HDMI_FC_ISCR2_10 0x10A8 +#define HDMI_FC_ISCR2_9 0x10A9 +#define HDMI_FC_ISCR2_8 0x10AA +#define HDMI_FC_ISCR2_7 0x10AB +#define HDMI_FC_ISCR2_6 0x10AC +#define HDMI_FC_ISCR2_5 0x10AD +#define HDMI_FC_ISCR2_4 0x10AE +#define HDMI_FC_ISCR2_3 0x10AF +#define HDMI_FC_ISCR2_2 0x10B0 +#define HDMI_FC_ISCR2_1 0x10B1 +#define HDMI_FC_ISCR2_0 0x10B2 +#define HDMI_FC_DATAUTO0 0x10B3 +#define HDMI_FC_DATAUTO1 0x10B4 +#define HDMI_FC_DATAUTO2 0x10B5 +#define HDMI_FC_DATMAN 0x10B6 +#define HDMI_FC_DATAUTO3 0x10B7 +#define HDMI_FC_RDRB0 0x10B8 +#define HDMI_FC_RDRB1 0x10B9 +#define HDMI_FC_RDRB2 0x10BA +#define HDMI_FC_RDRB3 0x10BB +#define HDMI_FC_RDRB4 0x10BC +#define HDMI_FC_RDRB5 0x10BD +#define HDMI_FC_RDRB6 0x10BE +#define HDMI_FC_RDRB7 0x10BF +#define HDMI_FC_STAT0 0x10D0 +#define HDMI_FC_INT0 0x10D1 +#define HDMI_FC_MASK0 0x10D2 +#define HDMI_FC_POL0 0x10D3 +#define HDMI_FC_STAT1 0x10D4 +#define HDMI_FC_INT1 0x10D5 +#define HDMI_FC_MASK1 0x10D6 +#define HDMI_FC_POL1 0x10D7 +#define HDMI_FC_STAT2 0x10D8 +#define HDMI_FC_INT2 0x10D9 +#define HDMI_FC_MASK2 0x10DA +#define HDMI_FC_POL2 0x10DB +#define HDMI_FC_PRCONF 0x10E0 + +#define HDMI_FC_GMD_STAT 0x1100 +#define HDMI_FC_GMD_EN 0x1101 +#define HDMI_FC_GMD_UP 0x1102 +#define HDMI_FC_GMD_CONF 0x1103 +#define HDMI_FC_GMD_HB 0x1104 +#define HDMI_FC_GMD_PB0 0x1105 +#define HDMI_FC_GMD_PB1 0x1106 +#define HDMI_FC_GMD_PB2 0x1107 +#define HDMI_FC_GMD_PB3 0x1108 +#define HDMI_FC_GMD_PB4 0x1109 +#define HDMI_FC_GMD_PB5 0x110A +#define HDMI_FC_GMD_PB6 0x110B +#define HDMI_FC_GMD_PB7 0x110C +#define HDMI_FC_GMD_PB8 0x110D +#define HDMI_FC_GMD_PB9 0x110E +#define HDMI_FC_GMD_PB10 0x110F +#define HDMI_FC_GMD_PB11 0x1110 +#define HDMI_FC_GMD_PB12 0x1111 +#define HDMI_FC_GMD_PB13 0x1112 +#define HDMI_FC_GMD_PB14 0x1113 +#define HDMI_FC_GMD_PB15 0x1114 +#define HDMI_FC_GMD_PB16 0x1115 +#define HDMI_FC_GMD_PB17 0x1116 +#define HDMI_FC_GMD_PB18 0x1117 +#define HDMI_FC_GMD_PB19 0x1118 +#define HDMI_FC_GMD_PB20 0x1119 +#define HDMI_FC_GMD_PB21 0x111A +#define HDMI_FC_GMD_PB22 0x111B +#define HDMI_FC_GMD_PB23 0x111C +#define HDMI_FC_GMD_PB24 0x111D +#define HDMI_FC_GMD_PB25 0x111E +#define HDMI_FC_GMD_PB26 0x111F +#define HDMI_FC_GMD_PB27 0x1120 + +#define HDMI_FC_DBGFORCE 0x1200 +#define HDMI_FC_DBGAUD0CH0 0x1201 +#define HDMI_FC_DBGAUD1CH0 0x1202 +#define HDMI_FC_DBGAUD2CH0 0x1203 +#define HDMI_FC_DBGAUD0CH1 0x1204 +#define HDMI_FC_DBGAUD1CH1 0x1205 +#define HDMI_FC_DBGAUD2CH1 0x1206 +#define HDMI_FC_DBGAUD0CH2 0x1207 +#define HDMI_FC_DBGAUD1CH2 0x1208 +#define HDMI_FC_DBGAUD2CH2 0x1209 +#define HDMI_FC_DBGAUD0CH3 0x120A +#define HDMI_FC_DBGAUD1CH3 0x120B +#define HDMI_FC_DBGAUD2CH3 0x120C +#define HDMI_FC_DBGAUD0CH4 0x120D +#define HDMI_FC_DBGAUD1CH4 0x120E +#define HDMI_FC_DBGAUD2CH4 0x120F +#define HDMI_FC_DBGAUD0CH5 0x1210 +#define HDMI_FC_DBGAUD1CH5 0x1211 +#define HDMI_FC_DBGAUD2CH5 0x1212 +#define HDMI_FC_DBGAUD0CH6 0x1213 +#define HDMI_FC_DBGAUD1CH6 0x1214 +#define HDMI_FC_DBGAUD2CH6 0x1215 +#define HDMI_FC_DBGAUD0CH7 0x1216 +#define HDMI_FC_DBGAUD1CH7 0x1217 +#define HDMI_FC_DBGAUD2CH7 0x1218 +#define HDMI_FC_DBGTMDS0 0x1219 +#define HDMI_FC_DBGTMDS1 0x121A +#define HDMI_FC_DBGTMDS2 0x121B + +/* HDMI Source PHY Registers */ +#define HDMI_PHY_CONF0 0x3000 +#define HDMI_PHY_TST0 0x3001 +#define HDMI_PHY_TST1 0x3002 +#define HDMI_PHY_TST2 0x3003 +#define HDMI_PHY_STAT0 0x3004 +#define HDMI_PHY_INT0 0x3005 +#define HDMI_PHY_MASK0 0x3006 +#define HDMI_PHY_POL0 0x3007 + +/* HDMI Master PHY Registers */ +#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020 +#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021 +#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022 +#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023 +#define HDMI_PHY_I2CM_DATAI_1_ADDR 0x3024 +#define HDMI_PHY_I2CM_DATAI_0_ADDR 0x3025 +#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026 +#define HDMI_PHY_I2CM_INT_ADDR 0x3027 +#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028 +#define HDMI_PHY_I2CM_DIV_ADDR 0x3029 +#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR 0x302a +#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR 0x302b +#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR 0x302c +#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR 0x302d +#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR 0x302e +#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR 0x302f +#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR 0x3030 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR 0x3031 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR 0x3032 + +/* Audio Sampler Registers */ +#define HDMI_AUD_CONF0 0x3100 +#define HDMI_AUD_CONF1 0x3101 +#define HDMI_AUD_INT 0x3102 +#define HDMI_AUD_CONF2 0x3103 +#define HDMI_AUD_N1 0x3200 +#define HDMI_AUD_N2 0x3201 +#define HDMI_AUD_N3 0x3202 +#define HDMI_AUD_CTS1 0x3203 +#define HDMI_AUD_CTS2 0x3204 +#define HDMI_AUD_CTS3 0x3205 +#define HDMI_AUD_INPUTCLKFS 0x3206 +#define HDMI_AUD_SPDIFINT 0x3302 +#define HDMI_AUD_CONF0_HBR 0x3400 +#define HDMI_AUD_HBR_STATUS 0x3401 +#define HDMI_AUD_HBR_INT 0x3402 +#define HDMI_AUD_HBR_POL 0x3403 +#define HDMI_AUD_HBR_MASK 0x3404 + +/* + * Generic Parallel Audio Interface Registers + * Not used as GPAUD interface is not enabled in hw + */ +#define HDMI_GP_CONF0 0x3500 +#define HDMI_GP_CONF1 0x3501 +#define HDMI_GP_CONF2 0x3502 +#define HDMI_GP_STAT 0x3503 +#define HDMI_GP_INT 0x3504 +#define HDMI_GP_MASK 0x3505 +#define HDMI_GP_POL 0x3506 + +/* Audio DMA Registers */ +#define HDMI_AHB_DMA_CONF0 0x3600 +#define HDMI_AHB_DMA_START 0x3601 +#define HDMI_AHB_DMA_STOP 0x3602 +#define HDMI_AHB_DMA_THRSLD 0x3603 +#define HDMI_AHB_DMA_STRADDR0 0x3604 +#define HDMI_AHB_DMA_STRADDR1 0x3605 +#define HDMI_AHB_DMA_STRADDR2 0x3606 +#define HDMI_AHB_DMA_STRADDR3 0x3607 +#define HDMI_AHB_DMA_STPADDR0 0x3608 +#define HDMI_AHB_DMA_STPADDR1 0x3609 +#define HDMI_AHB_DMA_STPADDR2 0x360a +#define HDMI_AHB_DMA_STPADDR3 0x360b +#define HDMI_AHB_DMA_BSTADDR0 0x360c +#define HDMI_AHB_DMA_BSTADDR1 0x360d +#define HDMI_AHB_DMA_BSTADDR2 0x360e +#define HDMI_AHB_DMA_BSTADDR3 0x360f +#define HDMI_AHB_DMA_MBLENGTH0 0x3610 +#define HDMI_AHB_DMA_MBLENGTH1 0x3611 +#define HDMI_AHB_DMA_STAT 0x3612 +#define HDMI_AHB_DMA_INT 0x3613 +#define HDMI_AHB_DMA_MASK 0x3614 +#define HDMI_AHB_DMA_POL 0x3615 +#define HDMI_AHB_DMA_CONF1 0x3616 +#define HDMI_AHB_DMA_BUFFSTAT 0x3617 +#define HDMI_AHB_DMA_BUFFINT 0x3618 +#define HDMI_AHB_DMA_BUFFMASK 0x3619 +#define HDMI_AHB_DMA_BUFFPOL 0x361a + +/* Main Controller Registers */ +#define HDMI_MC_SFRDIV 0x4000 +#define HDMI_MC_CLKDIS 0x4001 +#define HDMI_MC_SWRSTZ 0x4002 +#define HDMI_MC_OPCTRL 0x4003 +#define HDMI_MC_FLOWCTRL 0x4004 +#define HDMI_MC_PHYRSTZ 0x4005 +#define HDMI_MC_LOCKONCLOCK 0x4006 +#define HDMI_MC_HEACPHY_RST 0x4007 + +/* Color Space Converter Registers */ +#define HDMI_CSC_CFG 0x4100 +#define HDMI_CSC_SCALE 0x4101 +#define HDMI_CSC_COEF_A1_MSB 0x4102 +#define HDMI_CSC_COEF_A1_LSB 0x4103 +#define HDMI_CSC_COEF_A2_MSB 0x4104 +#define HDMI_CSC_COEF_A2_LSB 0x4105 +#define HDMI_CSC_COEF_A3_MSB 0x4106 +#define HDMI_CSC_COEF_A3_LSB 0x4107 +#define HDMI_CSC_COEF_A4_MSB 0x4108 +#define HDMI_CSC_COEF_A4_LSB 0x4109 +#define HDMI_CSC_COEF_B1_MSB 0x410A +#define HDMI_CSC_COEF_B1_LSB 0x410B +#define HDMI_CSC_COEF_B2_MSB 0x410C +#define HDMI_CSC_COEF_B2_LSB 0x410D +#define HDMI_CSC_COEF_B3_MSB 0x410E +#define HDMI_CSC_COEF_B3_LSB 0x410F +#define HDMI_CSC_COEF_B4_MSB 0x4110 +#define HDMI_CSC_COEF_B4_LSB 0x4111 +#define HDMI_CSC_COEF_C1_MSB 0x4112 +#define HDMI_CSC_COEF_C1_LSB 0x4113 +#define HDMI_CSC_COEF_C2_MSB 0x4114 +#define HDMI_CSC_COEF_C2_LSB 0x4115 +#define HDMI_CSC_COEF_C3_MSB 0x4116 +#define HDMI_CSC_COEF_C3_LSB 0x4117 +#define HDMI_CSC_COEF_C4_MSB 0x4118 +#define HDMI_CSC_COEF_C4_LSB 0x4119 + +/* HDCP Encryption Engine Registers */ +#define HDMI_A_HDCPCFG0 0x5000 +#define HDMI_A_HDCPCFG1 0x5001 +#define HDMI_A_HDCPOBS0 0x5002 +#define HDMI_A_HDCPOBS1 0x5003 +#define HDMI_A_HDCPOBS2 0x5004 +#define HDMI_A_HDCPOBS3 0x5005 +#define HDMI_A_APIINTCLR 0x5006 +#define HDMI_A_APIINTSTAT 0x5007 +#define HDMI_A_APIINTMSK 0x5008 +#define HDMI_A_VIDPOLCFG 0x5009 +#define HDMI_A_OESSWCFG 0x500A +#define HDMI_A_TIMER1SETUP0 0x500B +#define HDMI_A_TIMER1SETUP1 0x500C +#define HDMI_A_TIMER2SETUP0 0x500D +#define HDMI_A_TIMER2SETUP1 0x500E +#define HDMI_A_100MSCFG 0x500F +#define HDMI_A_2SCFG0 0x5010 +#define HDMI_A_2SCFG1 0x5011 +#define HDMI_A_5SCFG0 0x5012 +#define HDMI_A_5SCFG1 0x5013 +#define HDMI_A_SRMVERLSB 0x5014 +#define HDMI_A_SRMVERMSB 0x5015 +#define HDMI_A_SRMCTRL 0x5016 +#define HDMI_A_SFRSETUP 0x5017 +#define HDMI_A_I2CHSETUP 0x5018 +#define HDMI_A_INTSETUP 0x5019 +#define HDMI_A_PRESETUP 0x501A +#define HDMI_A_SRM_BASE 0x5020 + +/* CEC Engine Registers */ +#define HDMI_CEC_CTRL 0x7D00 +#define HDMI_CEC_STAT 0x7D01 +#define HDMI_CEC_MASK 0x7D02 +#define HDMI_CEC_POLARITY 0x7D03 +#define HDMI_CEC_INT 0x7D04 +#define HDMI_CEC_ADDR_L 0x7D05 +#define HDMI_CEC_ADDR_H 0x7D06 +#define HDMI_CEC_TX_CNT 0x7D07 +#define HDMI_CEC_RX_CNT 0x7D08 +#define HDMI_CEC_TX_DATA0 0x7D10 +#define HDMI_CEC_TX_DATA1 0x7D11 +#define HDMI_CEC_TX_DATA2 0x7D12 +#define HDMI_CEC_TX_DATA3 0x7D13 +#define HDMI_CEC_TX_DATA4 0x7D14 +#define HDMI_CEC_TX_DATA5 0x7D15 +#define HDMI_CEC_TX_DATA6 0x7D16 +#define HDMI_CEC_TX_DATA7 0x7D17 +#define HDMI_CEC_TX_DATA8 0x7D18 +#define HDMI_CEC_TX_DATA9 0x7D19 +#define HDMI_CEC_TX_DATA10 0x7D1a +#define HDMI_CEC_TX_DATA11 0x7D1b +#define HDMI_CEC_TX_DATA12 0x7D1c +#define HDMI_CEC_TX_DATA13 0x7D1d +#define HDMI_CEC_TX_DATA14 0x7D1e +#define HDMI_CEC_TX_DATA15 0x7D1f +#define HDMI_CEC_RX_DATA0 0x7D20 +#define HDMI_CEC_RX_DATA1 0x7D21 +#define HDMI_CEC_RX_DATA2 0x7D22 +#define HDMI_CEC_RX_DATA3 0x7D23 +#define HDMI_CEC_RX_DATA4 0x7D24 +#define HDMI_CEC_RX_DATA5 0x7D25 +#define HDMI_CEC_RX_DATA6 0x7D26 +#define HDMI_CEC_RX_DATA7 0x7D27 +#define HDMI_CEC_RX_DATA8 0x7D28 +#define HDMI_CEC_RX_DATA9 0x7D29 +#define HDMI_CEC_RX_DATA10 0x7D2a +#define HDMI_CEC_RX_DATA11 0x7D2b +#define HDMI_CEC_RX_DATA12 0x7D2c +#define HDMI_CEC_RX_DATA13 0x7D2d +#define HDMI_CEC_RX_DATA14 0x7D2e +#define HDMI_CEC_RX_DATA15 0x7D2f +#define HDMI_CEC_LOCK 0x7D30 +#define HDMI_CEC_WKUPCTRL 0x7D31 + +/* I2C Master Registers (E-DDC) */ +#define HDMI_I2CM_SLAVE 0x7E00 +#define HDMI_I2CMESS 0x7E01 +#define HDMI_I2CM_DATAO 0x7E02 +#define HDMI_I2CM_DATAI 0x7E03 +#define HDMI_I2CM_OPERATION 0x7E04 +#define HDMI_I2CM_INT 0x7E05 +#define HDMI_I2CM_CTLINT 0x7E06 +#define HDMI_I2CM_DIV 0x7E07 +#define HDMI_I2CM_SEGADDR 0x7E08 +#define HDMI_I2CM_SOFTRSTZ 0x7E09 +#define HDMI_I2CM_SEGPTR 0x7E0A +#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B +#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C +#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D +#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E +#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F +#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10 +#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11 +#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 + +enum { +/* IH_FC_INT2 field values */ + HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03, + HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_FC_STAT2 field values */ + HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_PHY_STAT0 field values */ + HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20, + HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10, + HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8, + HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4, + HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2, + HDMI_IH_PHY_STAT0_HPD = 0x1, + +/* IH_MUTE_I2CMPHY_STAT0 field values */ + HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2, + HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1, + +/* IH_AHBDMAAUD_STAT0 field values */ + HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20, + HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10, + HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08, + HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04, + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02, + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01, + +/* IH_MUTE_FC_STAT2 field values */ + HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_MUTE_AHBDMAAUD_STAT0 field values */ + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01, + +/* IH_MUTE field values */ + HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2, + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1, + +/* TX_INVID0 field values */ + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80, + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80, + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00, + HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F, + HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0, + +/* TX_INSTUFFING field values */ + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4, + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4, + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0, + +/* VP_PR_CD field values */ + HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0, + HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4, + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F, + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0, + +/* VP_STUFF field values */ + HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20, + HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5, + HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10, + HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4, + HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8, + HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3, + HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4, + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4, + HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0, + HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2, + HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2, + HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0, + HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1, + HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1, + HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0, + +/* VP_CONF field values */ + HDMI_VP_CONF_BYPASS_EN_MASK = 0x40, + HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40, + HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00, + HDMI_VP_CONF_PP_EN_ENMASK = 0x20, + HDMI_VP_CONF_PP_EN_ENABLE = 0x20, + HDMI_VP_CONF_PP_EN_DISABLE = 0x00, + HDMI_VP_CONF_PR_EN_MASK = 0x10, + HDMI_VP_CONF_PR_EN_ENABLE = 0x10, + HDMI_VP_CONF_PR_EN_DISABLE = 0x00, + HDMI_VP_CONF_YCC422_EN_MASK = 0x8, + HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8, + HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0, + HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4, + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4, + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0, + HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3, + HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3, + HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1, + HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0, + +/* VP_REMAP field values */ + HDMI_VP_REMAP_MASK = 0x3, + HDMI_VP_REMAP_YCC422_24bit = 0x2, + HDMI_VP_REMAP_YCC422_20bit = 0x1, + HDMI_VP_REMAP_YCC422_16bit = 0x0, + +/* FC_INVIDCONF field values */ + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80, + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80, + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8, + HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8, + HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0, + HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1, + HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1, + HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0, + +/* FC_AUDICONF0 field values */ + HDMI_FC_AUDICONF0_CC_OFFSET = 4, + HDMI_FC_AUDICONF0_CC_MASK = 0x70, + HDMI_FC_AUDICONF0_CT_OFFSET = 0, + HDMI_FC_AUDICONF0_CT_MASK = 0xF, + +/* FC_AUDICONF1 field values */ + HDMI_FC_AUDICONF1_SS_OFFSET = 3, + HDMI_FC_AUDICONF1_SS_MASK = 0x18, + HDMI_FC_AUDICONF1_SF_OFFSET = 0, + HDMI_FC_AUDICONF1_SF_MASK = 0x7, + +/* FC_AUDICONF3 field values */ + HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5, + HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60, + HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4, + HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10, + HDMI_FC_AUDICONF3_LSV_OFFSET = 0, + HDMI_FC_AUDICONF3_LSV_MASK = 0xF, + +/* FC_AUDSCHNLS0 field values */ + HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4, + HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30, + HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0, + HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01, + +/* FC_AUDSCHNLS3-6 field values */ + HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0, + HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f, + HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4, + HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0, + HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0, + HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f, + HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4, + HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0, + + HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0, + HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f, + HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4, + HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0, + HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0, + HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f, + HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4, + HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0, + +/* HDMI_FC_AUDSCHNLS7 field values */ + HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4, + HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30, + +/* HDMI_FC_AUDSCHNLS8 field values */ + HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0, + HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4, + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f, + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0, + +/* FC_AUDSCONF field values */ + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0, + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0, + +/* FC_STAT2 field values */ + HDMI_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_INT2 field values */ + HDMI_FC_INT2_OVERFLOW_MASK = 0x03, + HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_MASK2 field values */ + HDMI_FC_MASK2_OVERFLOW_MASK = 0x03, + HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_PRCONF field values */ + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0, + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4, + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F, + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0, + +/* FC_AVICONF0-FC_AVICONF3 field values */ + HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03, + HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00, + HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01, + HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02, + HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40, + HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40, + HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00, + HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C, + HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00, + HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04, + HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08, + HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C, + HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30, + HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10, + HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20, + HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00, + + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20, + HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0, + HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00, + HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40, + HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80, + HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0, + + HDMI_FC_AVICONF2_SCALING_MASK = 0x03, + HDMI_FC_AVICONF2_SCALING_NONE = 0x00, + HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01, + HDMI_FC_AVICONF2_SCALING_VERT = 0x02, + HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03, + HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C, + HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00, + HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04, + HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40, + HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80, + HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00, + HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80, + + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03, + HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C, + HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00, + HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04, + +/* FC_DBGFORCE field values */ + HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, + HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, + +/* PHY_CONF0 field values */ + HDMI_PHY_CONF0_PDZ_MASK = 0x80, + HDMI_PHY_CONF0_PDZ_OFFSET = 7, + HDMI_PHY_CONF0_ENTMDS_MASK = 0x40, + HDMI_PHY_CONF0_ENTMDS_OFFSET = 6, + HDMI_PHY_CONF0_SPARECTRL = 0x20, + HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10, + HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4, + HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8, + HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3, + HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4, + HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2, + HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2, + HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1, + HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1, + HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0, + +/* PHY_TST0 field values */ + HDMI_PHY_TST0_TSTCLR_MASK = 0x20, + HDMI_PHY_TST0_TSTCLR_OFFSET = 5, + HDMI_PHY_TST0_TSTEN_MASK = 0x10, + HDMI_PHY_TST0_TSTEN_OFFSET = 4, + HDMI_PHY_TST0_TSTCLK_MASK = 0x1, + HDMI_PHY_TST0_TSTCLK_OFFSET = 0, + +/* PHY_STAT0 field values */ + HDMI_PHY_RX_SENSE3 = 0x80, + HDMI_PHY_RX_SENSE2 = 0x40, + HDMI_PHY_RX_SENSE1 = 0x20, + HDMI_PHY_RX_SENSE0 = 0x10, + HDMI_PHY_HPD = 0x02, + HDMI_PHY_TX_PHY_LOCK = 0x01, + +/* PHY_I2CM_SLAVE_ADDR field values */ + HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69, + HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49, + +/* PHY_I2CM_OPERATION_ADDR field values */ + HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10, + HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1, + +/* HDMI_PHY_I2CM_INT_ADDR */ + HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08, + HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04, + +/* HDMI_PHY_I2CM_CTLINT_ADDR */ + HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80, + HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40, + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08, + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04, + +/* AUD_CTS3 field values */ + HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5, + HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0, + HDMI_AUD_CTS3_N_SHIFT_1 = 0, + HDMI_AUD_CTS3_N_SHIFT_16 = 0x20, + HDMI_AUD_CTS3_N_SHIFT_32 = 0x40, + HDMI_AUD_CTS3_N_SHIFT_64 = 0x60, + HDMI_AUD_CTS3_N_SHIFT_128 = 0x80, + HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0, + /* note that the CTS3 MANUAL bit has been removed + from our part. Can't set it, will read as 0. */ + HDMI_AUD_CTS3_CTS_MANUAL = 0x10, + HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f, + +/* AHB_DMA_CONF0 field values */ + HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7, + HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80, + HDMI_AHB_DMA_CONF0_HBR = 0x10, + HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3, + HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08, + HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1, + HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06, + HDMI_AHB_DMA_CONF0_INCR4 = 0x0, + HDMI_AHB_DMA_CONF0_INCR8 = 0x2, + HDMI_AHB_DMA_CONF0_INCR16 = 0x4, + HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1, + +/* HDMI_AHB_DMA_START field values */ + HDMI_AHB_DMA_START_START_OFFSET = 0, + HDMI_AHB_DMA_START_START_MASK = 0x01, + +/* HDMI_AHB_DMA_STOP field values */ + HDMI_AHB_DMA_STOP_STOP_OFFSET = 0, + HDMI_AHB_DMA_STOP_STOP_MASK = 0x01, + +/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */ + HDMI_AHB_DMA_DONE = 0x80, + HDMI_AHB_DMA_RETRY_SPLIT = 0x40, + HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20, + HDMI_AHB_DMA_ERROR = 0x10, + HDMI_AHB_DMA_FIFO_THREMPTY = 0x04, + HDMI_AHB_DMA_FIFO_FULL = 0x02, + HDMI_AHB_DMA_FIFO_EMPTY = 0x01, + +/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */ + HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02, + HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01, + +/* MC_CLKDIS field values */ + HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40, + HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20, + HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10, + HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8, + HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4, + HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2, + HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, + +/* MC_SWRSTZ field values */ + HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, + +/* MC_FLOWCTRL field values */ + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1, + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1, + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0, + +/* MC_PHYRSTZ field values */ + HDMI_MC_PHYRSTZ_ASSERT = 0x0, + HDMI_MC_PHYRSTZ_DEASSERT = 0x1, + +/* MC_HEACPHY_RST field values */ + HDMI_MC_HEACPHY_RST_ASSERT = 0x1, + HDMI_MC_HEACPHY_RST_DEASSERT = 0x0, + +/* CSC_CFG field values */ + HDMI_CSC_CFG_INTMODE_MASK = 0x30, + HDMI_CSC_CFG_INTMODE_OFFSET = 4, + HDMI_CSC_CFG_INTMODE_DISABLE = 0x00, + HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10, + HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20, + HDMI_CSC_CFG_DECMODE_MASK = 0x3, + HDMI_CSC_CFG_DECMODE_OFFSET = 0, + HDMI_CSC_CFG_DECMODE_DISABLE = 0x0, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3, + +/* CSC_SCALE field values */ + HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70, + HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03, + +/* A_HDCPCFG0 field values */ + HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80, + HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80, + HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00, + HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40, + HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40, + HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00, + HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20, + HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20, + HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00, + HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10, + HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10, + HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00, + HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8, + HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8, + HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0, + HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4, + HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4, + HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0, + HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2, + HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2, + HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0, + HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1, + HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1, + HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0, + +/* A_HDCPCFG1 field values */ + HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8, + HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8, + HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0, + HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1, + HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0, + +/* A_VIDPOLCFG field values */ + HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60, + HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5, + HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10, + HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10, + HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0, + HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8, + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8, + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0, + HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2, + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, +}; +#endif /* __IMX_HDMI_H__ */ diff --git a/drivers/video/imx-ipu-v3/imx-ipu-v3.h b/drivers/video/imx-ipu-v3/imx-ipu-v3.h new file mode 100644 index 0000000000..7c48a7ce38 --- /dev/null +++ b/drivers/video/imx-ipu-v3/imx-ipu-v3.h @@ -0,0 +1,344 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU Lesser General + * Public License. You may obtain a copy of the GNU Lesser General + * Public License Version 2.1 or later at the following locations: + * + * http://www.opensource.org/licenses/lgpl-license.html + * http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef __DRM_IPU_H__ +#define __DRM_IPU_H__ + +#include <io.h> +#include <fb.h> +#include <video/fourcc.h> + +struct ipu_soc; + +enum ipuv3_type { + IPUV3EX, + IPUV3M, + IPUV3H, +}; + +void ipuwritel(const char *unit, uint32_t value, void __iomem *reg); +uint32_t ipureadl(void __iomem *reg); + +/* + * Bitfield of Display Interface signal polarities. + */ +struct ipu_di_signal_cfg { + unsigned datamask_en:1; + unsigned interlaced:1; + unsigned odd_field_first:1; + unsigned clksel_en:1; + unsigned clkidle_en:1; + unsigned data_pol:1; /* true = inverted */ + unsigned clk_pol:1; /* true = rising edge */ + unsigned enable_pol:1; + unsigned Hsync_pol:1; /* true = active high */ + unsigned Vsync_pol:1; + + u16 width; + u16 height; + u32 pixel_fmt; + u16 h_start_width; + u16 h_sync_width; + u16 h_end_width; + u16 v_start_width; + u16 v_sync_width; + u16 v_end_width; + u32 v_to_h_sync; + unsigned long pixelclock; +#define IPU_DI_CLKMODE_SYNC (1 << 0) +#define IPU_DI_CLKMODE_EXT (1 << 1) +#define IPU_DI_CLKMODE_NON_FRACTIONAL (1 << 2) + unsigned long clkflags; + + u8 hsync_pin; + u8 vsync_pin; +}; + +enum ipu_color_space { + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_YUV, + IPUV3_COLORSPACE_UNKNOWN, +}; + +struct ipuv3_channel; + +enum ipu_channel_irq { + IPU_IRQ_EOF = 0, + IPU_IRQ_NFACK = 64, + IPU_IRQ_NFB4EOF = 128, + IPU_IRQ_EOS = 192, +}; + +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, + enum ipu_channel_irq irq); + +#define IPU_IRQ_DP_SF_START (448 + 2) +#define IPU_IRQ_DP_SF_END (448 + 3) +#define IPU_IRQ_BG_SF_END IPU_IRQ_DP_SF_END, +#define IPU_IRQ_DC_FC_0 (448 + 8) +#define IPU_IRQ_DC_FC_1 (448 + 9) +#define IPU_IRQ_DC_FC_2 (448 + 10) +#define IPU_IRQ_DC_FC_3 (448 + 11) +#define IPU_IRQ_DC_FC_4 (448 + 12) +#define IPU_IRQ_DC_FC_6 (448 + 13) +#define IPU_IRQ_VSYNC_PRE_0 (448 + 14) +#define IPU_IRQ_VSYNC_PRE_1 (448 + 15) + +/* + * IPU Image DMA Controller (idmac) functions + */ +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel); +void ipu_idmac_put(struct ipuv3_channel *); + +int ipu_idmac_enable_channel(struct ipuv3_channel *channel); +int ipu_idmac_disable_channel(struct ipuv3_channel *channel); +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms); + +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, + bool doublebuffer); +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num); + +/* + * IPU Display Controller (dc) functions + */ +struct ipu_dc; +struct ipu_di; +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel); +void ipu_dc_put(struct ipu_dc *dc); +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + u32 pixel_fmt, u32 width); +void ipu_dc_enable_channel(struct ipu_dc *dc); +void ipu_dc_disable_channel(struct ipu_dc *dc); + +/* + * IPU Display Interface (di) functions + */ +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp); +void ipu_di_put(struct ipu_di *); +int ipu_di_disable(struct ipu_di *); +int ipu_di_enable(struct ipu_di *); +int ipu_di_get_num(struct ipu_di *); +int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig); + +/* + * IPU Display Multi FIFO Controller (dmfc) functions + */ +struct dmfc_channel; +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc); +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc); +int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, + unsigned long bandwidth_mbs, int burstsize); +void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc); +int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width); +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel); +void ipu_dmfc_put(struct dmfc_channel *dmfc); + +/* + * IPU Display Processor (dp) functions + */ +#define IPU_DP_FLOW_SYNC_BG 0 +#define IPU_DP_FLOW_SYNC_FG 1 +#define IPU_DP_FLOW_ASYNC0_BG 2 +#define IPU_DP_FLOW_ASYNC0_FG 3 +#define IPU_DP_FLOW_ASYNC1_BG 4 +#define IPU_DP_FLOW_ASYNC1_FG 5 + +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow); +void ipu_dp_put(struct ipu_dp *); +int ipu_dp_enable_channel(struct ipu_dp *dp); +void ipu_dp_disable_channel(struct ipu_dp *dp); +int ipu_dp_setup_channel(struct ipu_dp *dp, + enum ipu_color_space in, enum ipu_color_space out); +int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, + bool bg_chan); + +#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) + +#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) +#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) +#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) +#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) +#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) +#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) + +#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) +#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) +#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) +#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) +#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) +#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) +#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) +#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) +#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) +#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) +#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) +#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) +#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) +#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) +#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) +#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) +#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) +#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) +#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) +#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) +#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) +#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) +#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) +#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) +#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) +#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) +#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) +#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) +#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) +#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) +#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) +#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) +#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) +#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) +#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) +#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) +#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) +#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) +#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) +#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) +#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) +#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) +#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) +#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) +#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) +#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) +#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) +#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) +#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) + +struct ipu_cpmem_word { + u32 data[5]; + u32 res[3]; +}; + +struct ipu_ch_param { + struct ipu_cpmem_word word[2]; +}; + +void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v); +u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs); +struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel); +void ipu_ch_param_dump(struct ipu_ch_param __iomem *p); + +static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p) +{ + int i; + void __iomem *base = p; + + for (i = 0; i < sizeof(*p) / sizeof(u32); i++) + ipuwritel("chp", 0, base + i * sizeof(u32)); +} + +static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p, + int bufnum, dma_addr_t buf) +{ + if (bufnum) + ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3); + else + ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3); +} + +static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p, + int xres, int yres) +{ + ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1); + ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1); +} + +static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p, + int stride) +{ + ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1); +} + +void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel); + +struct ipu_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + int bits_per_pixel; +}; + +struct ipu_rgb *drm_fourcc_to_rgb(u32 drm_fourcc); + +int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, + int width); + +int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *, + const struct ipu_rgb *rgb); + +static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p, + int stride) +{ + ipu_ch_param_write_field(p, IPU_FIELD_SO, 1); + ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8); + ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1); +}; + +void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, + int stride, int height); +void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, + u32 pixel_format); +void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, + u32 pixel_format, int stride, int u_offset, int v_offset); +int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat); + +enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); +enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); + +static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p, + int burstsize) +{ + ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1); +}; + +struct ipu_client_platformdata { + int di; + int dc; + int dp; + int dmfc; + int dma[2]; + struct device_node *device_node; +}; + +struct ipu_output; + +struct ipu_output_ops { + int (*prepare)(struct ipu_output *ipu_video_output, struct fb_videomode *mode, int di); + int (*enable)(struct ipu_output *ipu_video_output, struct fb_videomode *mode, int di); + int (*disable)(struct ipu_output *ipu_video_output); + int (*unprepare)(struct ipu_output *ipu_video_output); +}; + +struct ipu_output { + struct ipu_output_ops *ops; + struct list_head list; + unsigned int di_clkflags; + uint32_t out_pixel_fmt; + struct i2c_adapter *edid_i2c_adapter; + struct display_timings *modes; + char *name; + int ipu_mask; +}; + +int ipu_register_output(struct ipu_output *ouput); + +#endif /* __DRM_IPU_H__ */ diff --git a/drivers/video/imx-ipu-v3/imx-ldb.c b/drivers/video/imx-ipu-v3/imx-ldb.c new file mode 100644 index 0000000000..7367fbea71 --- /dev/null +++ b/drivers/video/imx-ipu-v3/imx-ldb.c @@ -0,0 +1,310 @@ +/* + * i.MX drm driver - parallel display implementation + * + * Copyright (C) 2012 Sascha Hauer, Pengutronix + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <fb.h> +#include <io.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <init.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <asm-generic/div64.h> +#include <linux/clk.h> +#include <mach/imx6-regs.h> +#include <mach/imx53-regs.h> + +#include "imx-ipu-v3.h" +#include "ipuv3-plane.h" + +#define LDB_CH0_MODE_EN_TO_DI0 (1 << 0) +#define LDB_CH0_MODE_EN_TO_DI1 (3 << 0) +#define LDB_CH0_MODE_EN_MASK (3 << 0) +#define LDB_CH1_MODE_EN_TO_DI0 (1 << 2) +#define LDB_CH1_MODE_EN_TO_DI1 (3 << 2) +#define LDB_CH1_MODE_EN_MASK (3 << 2) +#define LDB_SPLIT_MODE_EN (1 << 4) +#define LDB_DATA_WIDTH_CH0_24 (1 << 5) +#define LDB_BIT_MAP_CH0_JEIDA (1 << 6) +#define LDB_DATA_WIDTH_CH1_24 (1 << 7) +#define LDB_BIT_MAP_CH1_JEIDA (1 << 8) +#define LDB_DI0_VS_POL_ACT_LOW (1 << 9) +#define LDB_DI1_VS_POL_ACT_LOW (1 << 10) +#define LDB_BGREF_RMODE_INT (1 << 15) + +struct imx_ldb; + +struct imx_ldb_channel { + struct imx_ldb *ldb; + int chno; + int mode_valid; + struct display_timings *modes; + struct ipu_output output; +}; + +struct imx_ldb_data { + void __iomem *base; + int (*prepare)(struct imx_ldb_channel *imx_ldb_ch, int di); + unsigned ipu_mask; +}; + +struct imx_ldb { + struct device_d *dev; + u32 interface_pix_fmt; + int mode_valid; + struct imx_ldb_channel channel[2]; + u32 ldb_ctrl; + void __iomem *base; + const struct imx_ldb_data *soc_data; +}; + +enum { + LVDS_BIT_MAP_SPWG, + LVDS_BIT_MAP_JEIDA +}; + +static const char * const imx_ldb_bit_mappings[] = { + [LVDS_BIT_MAP_SPWG] = "spwg", + [LVDS_BIT_MAP_JEIDA] = "jeida", +}; + +static const int of_get_data_mapping(struct device_node *np) +{ + const char *bm; + int ret, i; + + ret = of_property_read_string(np, "fsl,data-mapping", &bm); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) + if (!strcasecmp(bm, imx_ldb_bit_mappings[i])) + return i; + + return -EINVAL; +} + +static int imx_ldb_prepare(struct ipu_output *output, struct fb_videomode *mode, int di) +{ + struct imx_ldb_channel *imx_ldb_ch = container_of(output, struct imx_ldb_channel, output); + struct imx_ldb *ldb = imx_ldb_ch->ldb; + + if (PICOS2KHZ(mode->pixclock) > 85000) { + dev_warn(ldb->dev, + "%s: mode exceeds 85 MHz pixel clock\n", __func__); + } + + ldb->soc_data->prepare(imx_ldb_ch, di); + + /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ + if (imx_ldb_ch == &ldb->channel[0]) { + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; + else + ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW; + } + + if (imx_ldb_ch == &ldb->channel[1]) { + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; + else + ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW; + } + + if (imx_ldb_ch == &ldb->channel[0]) { + ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; + ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0; + } + + if (imx_ldb_ch == &ldb->channel[1]) { + ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; + ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1; + } + + writel(ldb->ldb_ctrl, ldb->base); + + return 0; +} + +static int imx6q_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, int di) +{ + struct clk *diclk, *ldbclk; + struct imx_ldb *ldb = imx_ldb_ch->ldb; + int ret, ipuno, dino; + char *clkname; + void __iomem *gpr3 = (void *)MX6_IOMUXC_BASE_ADDR + 0xc; + uint32_t val; + int shift; + + ipuno = ((di >> 1) & 1) + 1; + dino = di & 0x1; + + clkname = asprintf("ipu%d_di%d_sel", ipuno, dino); + diclk = clk_lookup(clkname); + free(clkname); + if (IS_ERR(diclk)) { + dev_err(ldb->dev, "failed to get di clk: %s\n", strerror(PTR_ERR(diclk))); + return PTR_ERR(diclk); + } + + clkname = asprintf("ldb_di%d_podf", imx_ldb_ch->chno); + ldbclk = clk_lookup(clkname); + free(clkname); + if (IS_ERR(ldbclk)) { + dev_err(ldb->dev, "failed to get ldb clk: %s\n", strerror(PTR_ERR(ldbclk))); + return PTR_ERR(ldbclk); + } + + ret = clk_set_parent(diclk, ldbclk); + if (ret) { + dev_err(ldb->dev, "failed to set display clock parent: %s\n", strerror(-ret)); + return ret; + } +printk("%s: %d\n", __func__, di); + val = readl(gpr3); + shift = (imx_ldb_ch->chno == 0) ? 6 : 8; + val &= ~(3 << shift); + val |= di << shift; + writel(val, gpr3); + + return 0; +} + +static int imx53_ldb_prepare(struct imx_ldb_channel *imx_ldb_ch, int di) +{ + return -ENOSYS; +} + +static struct imx_ldb_data imx_ldb_data_imx6q = { + .base = (void *)MX6_IOMUXC_BASE_ADDR + 0x8, + .prepare = imx6q_ldb_prepare, + .ipu_mask = 0xf, +}; + +static struct imx_ldb_data imx_ldb_data_imx53 = { + .base = (void *)MX53_IOMUXC_BASE_ADDR + 0x8, + .prepare = imx53_ldb_prepare, + .ipu_mask = 0x3, +}; + +static struct ipu_output_ops imx_ldb_ops = { + .prepare = imx_ldb_prepare, +}; + +static int imx_ldb_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct device_node *child; + struct imx_ldb *imx_ldb; + int ret, i; + int dual = 0; + int datawidth; + int mapping; + const struct imx_ldb_data *devtype; + + ret = dev_get_drvdata(dev, (unsigned long *)&devtype); + if (ret) + return ret; + + imx_ldb = xzalloc(sizeof(*imx_ldb)); + imx_ldb->base = devtype->base; + imx_ldb->soc_data = devtype; + + for_each_child_of_node(np, child) { + struct imx_ldb_channel *channel; + + ret = of_property_read_u32(child, "reg", &i); + if (ret || i < 0 || i > 1) + return -EINVAL; + + if (dual && i > 0) { + dev_warn(dev, "dual-channel mode, ignoring second output\n"); + continue; + } + + if (!of_device_is_available(child)) + continue; + + channel = &imx_ldb->channel[i]; + channel->ldb = imx_ldb; + channel->chno = i; + + ret = of_property_read_u32(child, "fsl,data-width", &datawidth); + if (ret) + datawidth = 0; + else if (datawidth != 18 && datawidth != 24) + return -EINVAL; + + mapping = of_get_data_mapping(child); + switch (mapping) { + case LVDS_BIT_MAP_SPWG: + if (datawidth == 24) { + if (i == 0 || dual) + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; + if (i == 1 || dual) + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; + } + break; + case LVDS_BIT_MAP_JEIDA: + if (datawidth == 18) { + dev_err(dev, "JEIDA standard only supported in 24 bit\n"); + return -EINVAL; + } + if (i == 0 || dual) + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA; + if (i == 1 || dual) + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA; + break; + default: + dev_err(dev, "data mapping not specified or invalid\n"); + return -EINVAL; + } + + channel->output.ops = &imx_ldb_ops; + channel->output.di_clkflags = IPU_DI_CLKMODE_EXT | IPU_DI_CLKMODE_SYNC; + channel->output.out_pixel_fmt = (datawidth == 24) ? + V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; + channel->output.modes = of_get_display_timings(child); + channel->output.name = asprintf("ldb-%d", i); + channel->output.ipu_mask = devtype->ipu_mask; + + ipu_register_output(&channel->output); + } + + return 0; +} + +static struct of_device_id imx_ldb_dt_ids[] = { + { .compatible = "fsl,imx6q-ldb", (unsigned long)&imx_ldb_data_imx6q}, + { .compatible = "fsl,imx53-ldb", (unsigned long)&imx_ldb_data_imx53}, + { /* sentinel */ } +}; + +static struct driver_d imx_ldb_driver = { + .probe = imx_ldb_probe, + .of_compatible = imx_ldb_dt_ids, + .name = "imx-ldb", +}; +device_platform_driver(imx_ldb_driver); + +MODULE_DESCRIPTION("i.MX LVDS display driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c new file mode 100644 index 0000000000..ffd6ec18a9 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-common.c @@ -0,0 +1,836 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <clock.h> +#include <driver.h> +#include <init.h> +#include <asm/mmu.h> +#include <mach/generic.h> +#include <mach/imx6-regs.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +void ipuwritel(const char *unit, uint32_t value, void __iomem *reg) +{ + pr_debug("w: %s 0x%08lx -> 0x%08x\n", unit, (unsigned long)reg & 0xfff, value); + + writel(value, reg); +} + +uint32_t ipureadl(void __iomem *reg) +{ + uint32_t val; + + val = readl(reg); + + pr_debug("r: 0x%p -> 0x%08x\n", reg - 0x02600000, val); + + return val; +} + +static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset) +{ + return ipureadl(ipu->cm_reg + offset); +} + +static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset) +{ + ipuwritel("cm", value, ipu->cm_reg + offset); +} + +static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) +{ + return ipureadl(ipu->idmac_reg + offset); +} + +static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, + unsigned offset) +{ + ipuwritel("idmac", value, ipu->idmac_reg + offset); +} + +void ipu_srm_dp_sync_update(struct ipu_soc *ipu) +{ + u32 val; + + val = ipu_cm_read(ipu, IPU_SRM_PRI2); + val |= 0x8; + ipu_cm_write(ipu, val, IPU_SRM_PRI2); +} +EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); + +struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + + return ipu->cpmem_base + channel->num; +} +EXPORT_SYMBOL_GPL(ipu_get_cpmem); + +void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel); + u32 val; + + if (ipu->ipu_type == IPUV3EX) + ipu_ch_param_write_field(p, IPU_FIELD_ID, 1); + + val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num)); + val |= 1 << (channel->num % 32); + ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num)); +}; +EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); + +void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v) +{ + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val; + + pr_debug("%s %d %d %d 0x%08x\n", __func__, word, bit , size, v); + + val = ipureadl(&base->word[word].data[i]); + val &= ~(mask << ofs); + val |= v << ofs; + ipuwritel("chp", val, &base->word[word].data[i]); + + if ((bit + size - 1) / 32 > i) { + val = ipureadl(&base->word[word].data[i + 1]); + val &= ~(mask >> (ofs ? (32 - ofs) : 0)); + val |= v >> (ofs ? (32 - ofs) : 0); + ipuwritel("chp", val, &base->word[word].data[i + 1]); + } +} +EXPORT_SYMBOL_GPL(ipu_ch_param_write_field); + +u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) +{ + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val = 0; + + pr_debug("%s %d %d %d\n", __func__, word, bit , size); + + val = (ipureadl(&base->word[word].data[i]) >> ofs) & mask; + + if ((bit + size - 1) / 32 > i) { + u32 tmp; + tmp = ipureadl(&base->word[word].data[i + 1]); + tmp &= mask >> (ofs ? (32 - ofs) : 0); + val |= tmp << (ofs ? (32 - ofs) : 0); + } + + return val; +} +EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); + +int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p, + const struct ipu_rgb *rgb) +{ + int bpp = 0, npb = 0, ro, go, bo, to; + + ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; + go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; + bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; + to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; + + ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro); + ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go); + ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo); + + if (rgb->transp.length) { + ipu_ch_param_write_field(p, IPU_FIELD_WID3, + rgb->transp.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to); + } else { + ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7); + ipu_ch_param_write_field(p, IPU_FIELD_OFS3, + rgb->bits_per_pixel); + } + + switch (rgb->bits_per_pixel) { + case 32: + bpp = 0; + npb = 15; + break; + case 24: + bpp = 1; + npb = 19; + break; + case 16: + bpp = 3; + npb = 31; + break; + case 8: + bpp = 5; + npb = 63; + break; + default: + return -EINVAL; + } + ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); + ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); + ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */ + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); + +static struct ipu_rgb def_rgb_32 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static struct ipu_rgb def_bgr_32 = { + .red = { .offset = 0, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static struct ipu_rgb def_rgb_24 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static struct ipu_rgb def_bgr_24 = { + .red = { .offset = 0, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static struct ipu_rgb def_rgb_16 = { + .red = { .offset = 11, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 0, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + +static struct ipu_rgb def_bgr_16 = { + .red = { .offset = 0, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 11, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + +struct ipu_rgb *drm_fourcc_to_rgb(u32 drm_fourcc) +{ + switch (drm_fourcc) { + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + return &def_bgr_32; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + return &def_rgb_32; + case DRM_FORMAT_BGR888: + return &def_bgr_24; + case DRM_FORMAT_RGB888: + return &def_rgb_24; + case DRM_FORMAT_RGB565: + return &def_rgb_16; + case DRM_FORMAT_BGR565: + return &def_bgr_16; + default: + return NULL; + } +} + +#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 4) + (x) / 2) +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * pix->height / 4) + \ + (pix->width * (y) / 4) + (x) / 2) + +int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc) +{ + switch (drm_fourcc) { + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); + break; + case DRM_FORMAT_BGR888: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); + break; + case DRM_FORMAT_RGB888: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24); + break; + case DRM_FORMAT_RGB565: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); + break; + case DRM_FORMAT_BGR565: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); + +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) +{ + struct ipuv3_channel *channel; + + dev_dbg(ipu->dev, "%s %d\n", __func__, num); + + if (num > 63) + return ERR_PTR(-ENODEV); + + mutex_lock(&ipu->channel_lock); + + channel = &ipu->channel[num]; + + if (channel->busy) { + channel = ERR_PTR(-EBUSY); + goto out; + } + + channel->busy = true; + channel->num = num; + +out: + mutex_unlock(&ipu->channel_lock); + + return channel; +} +EXPORT_SYMBOL_GPL(ipu_idmac_get); + +void ipu_idmac_put(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + + dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num); + + mutex_lock(&ipu->channel_lock); + + channel->busy = false; + + mutex_unlock(&ipu->channel_lock); +} +EXPORT_SYMBOL_GPL(ipu_idmac_put); + +#define idma_mask(ch) (1 << (ch & 0x1f)) + +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, + bool doublebuffer) +{ + struct ipu_soc *ipu = channel->ipu; + u32 reg; + + reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num)); + if (doublebuffer) + reg |= idma_mask(channel->num); + else + reg &= ~idma_mask(channel->num); + ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num)); +} +EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); + +int ipu_module_enable(struct ipu_soc *ipu, u32 mask) +{ + u32 val; + + val = ipu_cm_read(ipu, IPU_DISP_GEN); + + if (mask & IPU_CONF_DI0_EN) + val |= IPU_DI0_COUNTER_RELEASE; + if (mask & IPU_CONF_DI1_EN) + val |= IPU_DI1_COUNTER_RELEASE; + + ipu_cm_write(ipu, val, IPU_DISP_GEN); + + val = ipu_cm_read(ipu, IPU_CONF); + val |= mask; + ipu_cm_write(ipu, val, IPU_CONF); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_module_enable); + +int ipu_module_disable(struct ipu_soc *ipu, u32 mask) +{ + u32 val; + + val = ipu_cm_read(ipu, IPU_CONF); + val &= ~mask; + ipu_cm_write(ipu, val, IPU_CONF); + + val = ipu_cm_read(ipu, IPU_DISP_GEN); + + if (mask & IPU_CONF_DI0_EN) + val &= ~IPU_DI0_COUNTER_RELEASE; + if (mask & IPU_CONF_DI1_EN) + val &= ~IPU_DI1_COUNTER_RELEASE; + + ipu_cm_write(ipu, val, IPU_DISP_GEN); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_module_disable); + +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) +{ + struct ipu_soc *ipu = channel->ipu; + unsigned int chno = channel->num; + + /* Mark buffer as ready. */ + if (buf_num == 0) + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno)); + else + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno)); +} +EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); + +int ipu_idmac_enable_channel(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + u32 val; + + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num)); + val |= idma_mask(channel->num); + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); + +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) +{ + struct ipu_soc *ipu = channel->ipu; + uint64_t start; + + start = get_time_ns(); + + while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) & + idma_mask(channel->num)) { + if (is_timeout(start, ms * MSECOND)) + return -ETIMEDOUT; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy); + +int ipu_idmac_disable_channel(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + u32 val; + + /* Disable DMA channel(s) */ + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num)); + val &= ~idma_mask(channel->num); + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); + + /* Set channel buffers NOT to be ready */ + ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */ + + if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) & + idma_mask(channel->num)) { + ipu_cm_write(ipu, idma_mask(channel->num), + IPU_CHA_BUF0_RDY(channel->num)); + } + + if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) & + idma_mask(channel->num)) { + ipu_cm_write(ipu, idma_mask(channel->num), + IPU_CHA_BUF1_RDY(channel->num)); + } + + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */ + + /* Reset the double buffer */ + val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num)); + val &= ~idma_mask(channel->num); + ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num)); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); + +static int ipu_memory_reset(struct ipu_soc *ipu) +{ + uint64_t start; + + ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST); + + start = get_time_ns(); + + while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) { + if (is_timeout(start, SECOND)) + return -ETIMEDOUT; + } + + return 0; +} + +static int imx6_ipu_reset(struct ipu_soc *ipu) +{ + uint32_t val; + int ret; + void __iomem *reg; + + reg = (void *)MX6_SRC_BASE_ADDR; + val = ipureadl(reg); + if (ipu->base == (void *)MX6_IPU1_BASE_ADDR) + val |= (1 << 3); + else + val |= (1 << 12); + + ipuwritel("reset", val, reg); + + ret = wait_on_timeout(100 * MSECOND, !(readl(reg) & (1 << 3))); + + return ret; + +} + +struct ipu_devtype { + const char *name; + unsigned long cm_ofs; + unsigned long cpmem_ofs; + unsigned long srm_ofs; + unsigned long tpm_ofs; + unsigned long disp0_ofs; + unsigned long disp1_ofs; + unsigned long dc_tmpl_ofs; + unsigned long vdi_ofs; + enum ipuv3_type type; + int (*reset)(struct ipu_soc *ipu); +}; + +static struct ipu_devtype ipu_type_imx51 = { + .name = "IPUv3EX", + .cm_ofs = 0x1e000000, + .cpmem_ofs = 0x1f000000, + .srm_ofs = 0x1f040000, + .tpm_ofs = 0x1f060000, + .disp0_ofs = 0x1e040000, + .disp1_ofs = 0x1e048000, + .dc_tmpl_ofs = 0x1f080000, + .vdi_ofs = 0x1e068000, + .type = IPUV3EX, +}; + +static struct ipu_devtype ipu_type_imx53 = { + .name = "IPUv3M", + .cm_ofs = 0x06000000, + .cpmem_ofs = 0x07000000, + .srm_ofs = 0x07040000, + .tpm_ofs = 0x07060000, + .disp0_ofs = 0x06040000, + .disp1_ofs = 0x06048000, + .dc_tmpl_ofs = 0x07080000, + .vdi_ofs = 0x06068000, + .type = IPUV3M, +}; + +static struct ipu_devtype ipu_type_imx6q = { + .name = "IPUv3H", + .cm_ofs = 0x00200000, + .cpmem_ofs = 0x00300000, + .srm_ofs = 0x00340000, + .tpm_ofs = 0x00360000, + .disp0_ofs = 0x00240000, + .disp1_ofs = 0x00248000, + .dc_tmpl_ofs = 0x00380000, + .vdi_ofs = 0x00268000, + .type = IPUV3H, + .reset = imx6_ipu_reset, +}; + +static struct of_device_id imx_ipu_dt_ids[] = { + { .compatible = "fsl,imx51-ipu", .data = (unsigned long)&ipu_type_imx51, }, + { .compatible = "fsl,imx53-ipu", .data = (unsigned long)&ipu_type_imx53, }, + { .compatible = "fsl,imx6q-ipu", .data = (unsigned long)&ipu_type_imx6q, }, + { /* sentinel */ } +}; + +static int ipu_submodules_init(struct ipu_soc *ipu, + struct device_d *dev, void __iomem *ipu_base, + struct clk *ipu_clk) +{ + char *unit; + int ret; + const struct ipu_devtype *devtype = ipu->devtype; + + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, + IPU_CONF_DI0_EN, ipu_clk); + if (ret) { + unit = "di0"; + goto err_di_0; + } + + ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs, + IPU_CONF_DI1_EN, ipu_clk); + if (ret) { + unit = "di1"; + goto err_di_1; + } + + ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs + + IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs); + if (ret) { + unit = "dc_template"; + goto err_dc; + } + + ret = ipu_dmfc_init(ipu, dev, ipu_base + + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk); + if (ret) { + unit = "dmfc"; + goto err_dmfc; + } + + ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs); + if (ret) { + unit = "dp"; + goto err_dp; + } + + return 0; + +err_dp: + ipu_dmfc_exit(ipu); +err_dmfc: + ipu_dc_exit(ipu); +err_dc: + ipu_di_exit(ipu, 1); +err_di_1: + ipu_di_exit(ipu, 0); +err_di_0: + dev_err(dev, "init %s failed with %d\n", unit, ret); + return ret; +} + +static void ipu_submodules_exit(struct ipu_soc *ipu) +{ + ipu_dp_exit(ipu); + ipu_dmfc_exit(ipu); + ipu_dc_exit(ipu); + ipu_di_exit(ipu, 1); + ipu_di_exit(ipu, 0); +} + +struct ipu_platform_reg { + struct ipu_client_platformdata pdata; + const char *name; +}; + +static struct ipu_platform_reg client_reg[] = { + { + .pdata = { + .di = 0, + .dc = 5, + .dp = IPU_DP_FLOW_SYNC_BG, + .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC, + .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC, + }, + .name = "imx-ipuv3-crtc", + }, { + .pdata = { + .di = 1, + .dc = 1, + .dp = -EINVAL, + .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC, + .dma[1] = -EINVAL, + }, + .name = "imx-ipuv3-crtc", + }, +}; + +static int ipu_client_id; + +static int ipu_add_subdevice_pdata(struct device_d *ipu_dev, + struct ipu_platform_reg *reg) +{ + struct device_d *dev; + int ret; + + dev = device_alloc(reg->name, ipu_client_id++); + dev->parent = ipu_dev; + device_add_data(dev, ®->pdata, sizeof(reg->pdata)); + ((struct ipu_client_platformdata *)dev->platform_data)->device_node = ipu_dev->device_node; + + ret = platform_device_register(dev); + + return ret; +} + +static int ipu_add_client_devices(struct ipu_soc *ipu) +{ + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(client_reg); i++) { + struct ipu_platform_reg *reg = &client_reg[i]; + ret = ipu_add_subdevice_pdata(ipu->dev, reg); + if (ret) + goto err_register; + } + + return 0; + +err_register: + + return ret; +} + +static int ipu_probe(struct device_d *dev) +{ + struct ipu_soc *ipu; + void __iomem *ipu_base; + int i, ret; + const struct ipu_devtype *devtype; + + ret = dev_get_drvdata(dev, (unsigned long *)&devtype); + if (ret) + return ret; + + ipu_base = dev_request_mem_region(dev, 0); + if (!ipu_base) + return -EBUSY; + + ipu = xzalloc(sizeof(*ipu)); + + ipu->base = ipu_base; + + for (i = 0; i < 64; i++) + ipu->channel[i].ipu = ipu; + ipu->devtype = devtype; + ipu->ipu_type = devtype->type; + + dev_dbg(dev, "cm_reg: 0x%p\n", + ipu_base + devtype->cm_ofs); + dev_dbg(dev, "idmac: 0x%p\n", + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); + dev_dbg(dev, "cpmem: 0x%p\n", + ipu_base + devtype->cpmem_ofs); + dev_dbg(dev, "disp0: 0x%p\n", + ipu_base + devtype->disp0_ofs); + dev_dbg(dev, "disp1: 0x%p\n", + ipu_base + devtype->disp1_ofs); + dev_dbg(dev, "srm: 0x%p\n", + ipu_base + devtype->srm_ofs); + dev_dbg(dev, "tpm: 0x%p\n", + ipu_base + devtype->tpm_ofs); + dev_dbg(dev, "dc: 0x%p\n", + ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS); + dev_dbg(dev, "ic: 0x%p\n", + ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS); + dev_dbg(dev, "dmfc: 0x%p\n", + ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS); + dev_dbg(dev, "vdi: 0x%p\n", + ipu_base + devtype->vdi_ofs); + + ipu->cm_reg = ipu_base + devtype->cm_ofs, PAGE_SIZE; + ipu->idmac_reg = ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS; + ipu->cpmem_base = ipu_base + devtype->cpmem_ofs; + + ipu->clk = clk_get(dev, "bus"); + if (IS_ERR(ipu->clk)) { + ret = PTR_ERR(ipu->clk); + dev_err(dev, "clk_get failed with %d", ret); + return ret; + } + + dev->priv = ipu; + + ret = clk_enable(ipu->clk); + if (ret) + return ret; + + ipu->dev = dev; + + ret = devtype->reset(ipu); + if (ret) { + dev_err(dev, "failed to reset: %d\n", ret); + goto out_failed_reset; + } + + ret = ipu_memory_reset(ipu); + if (ret) + goto out_failed_reset; + + /* Set MCU_T to divide MCU access window into 2 */ + ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), + IPU_DISP_GEN); + + ret = ipu_submodules_init(ipu, dev, ipu_base, ipu->clk); + if (ret) + goto failed_submodules_init; + + ret = ipu_add_client_devices(ipu); + if (ret) { + dev_err(dev, "adding client devices failed with %d\n", + ret); + goto failed_add_clients; + } + + dev_info(dev, "%s probed\n", devtype->name); + + return 0; + +failed_add_clients: + ipu_submodules_exit(ipu); +failed_submodules_init: +out_failed_reset: + clk_disable(ipu->clk); + return ret; +} + +static struct driver_d imx_ipu_driver = { + .name = "imx-ipuv3", + .of_compatible = imx_ipu_dt_ids, + .probe = ipu_probe, +}; + +device_platform_driver(imx_ipu_driver); + +MODULE_DESCRIPTION("i.MX IPU v3 driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c new file mode 100644 index 0000000000..2deb2ae048 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-dc.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <malloc.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2) +#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2) + +#define DC_EVT_NF 0 +#define DC_EVT_NL 1 +#define DC_EVT_EOF 2 +#define DC_EVT_NFIELD 3 +#define DC_EVT_EOL 4 +#define DC_EVT_EOFIELD 5 +#define DC_EVT_NEW_ADDR 6 +#define DC_EVT_NEW_CHAN 7 +#define DC_EVT_NEW_DATA 8 + +#define DC_EVT_NEW_ADDR_W_0 0 +#define DC_EVT_NEW_ADDR_W_1 1 +#define DC_EVT_NEW_CHAN_W_0 2 +#define DC_EVT_NEW_CHAN_W_1 3 +#define DC_EVT_NEW_DATA_W_0 4 +#define DC_EVT_NEW_DATA_W_1 5 +#define DC_EVT_NEW_ADDR_R_0 6 +#define DC_EVT_NEW_ADDR_R_1 7 +#define DC_EVT_NEW_CHAN_R_0 8 +#define DC_EVT_NEW_CHAN_R_1 9 +#define DC_EVT_NEW_DATA_R_0 10 +#define DC_EVT_NEW_DATA_R_1 11 + +#define DC_WR_CH_CONF 0x0 +#define DC_WR_CH_ADDR 0x4 +#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2) + +#define DC_GEN 0xd4 +#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4) +#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4) +#define DC_STAT 0x1c8 + +#define WROD(lf) (0x18 | ((lf) << 1)) +#define WRG 0x01 +#define WCLK 0xc9 + +#define SYNC_WAVE 0 +#define NULL_WAVE (-1) + +#define DC_GEN_SYNC_1_6_SYNC (2 << 1) +#define DC_GEN_SYNC_PRIORITY_1 (1 << 7) + +#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0) +#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3) +#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3) +#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4) +#define DC_WR_CH_CONF_FIELD_MODE (1 << 9) +#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5) +#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5) +#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2) +#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3) + +#define IPU_DC_NUM_CHANNELS 10 + +struct ipu_dc_priv; + +enum ipu_dc_map { + IPU_DC_MAP_RGB24, + IPU_DC_MAP_RGB565, + IPU_DC_MAP_GBR24, /* TVEv2 */ + IPU_DC_MAP_BGR666, + IPU_DC_MAP_BGR24, +}; + +struct ipu_dc { + /* The display interface number assigned to this dc channel */ + unsigned int di; + void __iomem *base; + struct ipu_dc_priv *priv; + int chno; + bool in_use; +}; + +struct ipu_dc_priv { + void __iomem *dc_reg; + void __iomem *dc_tmpl_reg; + struct ipu_soc *ipu; + struct device_d *dev; + struct ipu_dc channels[IPU_DC_NUM_CHANNELS]; +}; + +static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) +{ + u32 reg; + + reg = ipureadl(dc->base + DC_RL_CH(event)); + reg &= ~(0xffff << (16 * (event & 0x1))); + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); + ipuwritel("dc", reg, dc->base + DC_RL_CH(event)); +} + +static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, + int map, int wave, int glue, int sync, int stop) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 reg1, reg2; + + if (opcode == WCLK) { + reg1 = (operand << 20) & 0xfff00000; + reg2 = operand >> 12 | opcode << 1 | stop << 9; + } else if (opcode == WRG) { + reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000); + reg2 = operand >> 17 | opcode << 7 | stop << 9; + } else { + reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000); + reg2 = operand >> 12 | opcode << 4 | stop << 9; + } + ipuwritel("dc", reg1, priv->dc_tmpl_reg + word * 8); + ipuwritel("dc", reg2, priv->dc_tmpl_reg + word * 8 + 4); +} + +static int ipu_pixfmt_to_map(u32 fmt) +{ + switch (fmt) { + case V4L2_PIX_FMT_RGB24: + return IPU_DC_MAP_RGB24; + case V4L2_PIX_FMT_RGB565: + return IPU_DC_MAP_RGB565; + case IPU_PIX_FMT_GBR24: + return IPU_DC_MAP_GBR24; + case V4L2_PIX_FMT_BGR666: + return IPU_DC_MAP_BGR666; + case V4L2_PIX_FMT_BGR24: + return IPU_DC_MAP_BGR24; + default: + return -EINVAL; + } +} + +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + u32 pixel_fmt, u32 width) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 reg = 0; + int map; + + dc->di = ipu_di_get_num(di); + + map = ipu_pixfmt_to_map(pixel_fmt); + if (map < 0) { + dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); + return map; + } + + if (interlaced) { + dc_link_event(dc, DC_EVT_NL, 0, 3); + dc_link_event(dc, DC_EVT_EOL, 0, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1); + + /* Init template microcode */ + dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1); + } else { + if (dc->di) { + dc_link_event(dc, DC_EVT_NL, 2, 3); + dc_link_event(dc, DC_EVT_EOL, 3, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 1, 1); + /* Init template microcode */ + dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0); + dc_write_tmpl(dc, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1); + dc_write_tmpl(dc, 1, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + } else { + dc_link_event(dc, DC_EVT_NL, 5, 3); + dc_link_event(dc, DC_EVT_EOL, 6, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 8, 1); + /* Init template microcode */ + dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0); + dc_write_tmpl(dc, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1); + dc_write_tmpl(dc, 8, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + } + } + dc_link_event(dc, DC_EVT_NF, 0, 0); + dc_link_event(dc, DC_EVT_NFIELD, 0, 0); + dc_link_event(dc, DC_EVT_EOF, 0, 0); + dc_link_event(dc, DC_EVT_EOFIELD, 0, 0); + dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0); + dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0); + + reg = ipureadl(dc->base + DC_WR_CH_CONF); + if (interlaced) + reg |= DC_WR_CH_CONF_FIELD_MODE; + else + reg &= ~DC_WR_CH_CONF_FIELD_MODE; + ipuwritel("dc", reg, dc->base + DC_WR_CH_CONF); + + ipuwritel("dc", 0x0, dc->base + DC_WR_CH_ADDR); + ipuwritel("dc", width, priv->dc_reg + DC_DISP_CONF2(dc->di)); + + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dc_init_sync); + +void ipu_dc_enable_channel(struct ipu_dc *dc) +{ + int di; + u32 reg; + + di = dc->di; + + reg = ipureadl(dc->base + DC_WR_CH_CONF); + reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL; + ipuwritel("dc", reg, dc->base + DC_WR_CH_CONF); +} +EXPORT_SYMBOL_GPL(ipu_dc_enable_channel); + +void ipu_dc_disable_channel(struct ipu_dc *dc) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 val; + int irq = 0, timeout = 50; + + if (dc->chno == 1) + irq = IPU_IRQ_DC_FC_1; + else if (dc->chno == 5) + irq = IPU_IRQ_DP_SF_END; + else + return; + + /* should wait for the interrupt here */ + mdelay(50); + + if (dc->di == 0) + val = 0x00000002; + else + val = 0x00000020; + + /* Wait for DC triple buffer to empty */ + while ((ipureadl(priv->dc_reg + DC_STAT) & val) != val) { + mdelay(2); + timeout -= 2; + if (timeout <= 0) + break; + } + + val = ipureadl(dc->base + DC_WR_CH_CONF); + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + ipuwritel("dc", val, dc->base + DC_WR_CH_CONF); +} +EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); + +static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map, + int byte_num, int offset, int mask) +{ + int ptr = map * 3 + byte_num; + u32 reg; + + reg = ipureadl(priv->dc_reg + DC_MAP_CONF_VAL(ptr)); + reg &= ~(0xffff << (16 * (ptr & 0x1))); + reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1)); + ipuwritel("dc", reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr)); + + reg = ipureadl(priv->dc_reg + DC_MAP_CONF_PTR(map)); + reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num))); + reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num)); + ipuwritel("dc", reg, priv->dc_reg + DC_MAP_CONF_PTR(map)); +} + +static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map) +{ + u32 reg = ipureadl(priv->dc_reg + DC_MAP_CONF_PTR(map)); + + ipuwritel("dc", reg & ~(0xffff << (16 * (map & 0x1))), + priv->dc_reg + DC_MAP_CONF_PTR(map)); +} + +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel) +{ + struct ipu_dc_priv *priv = ipu->dc_priv; + struct ipu_dc *dc; + + if (channel >= IPU_DC_NUM_CHANNELS) + return ERR_PTR(-ENODEV); + + dc = &priv->channels[channel]; + + if (dc->in_use) + return ERR_PTR(-EBUSY); + + dc->in_use = true; + + return dc; +} +EXPORT_SYMBOL_GPL(ipu_dc_get); + +void ipu_dc_put(struct ipu_dc *dc) +{ + dc->in_use = false; +} +EXPORT_SYMBOL_GPL(ipu_dc_put); + +int ipu_dc_init(struct ipu_soc *ipu, struct device_d *dev, + void __iomem *base, void __iomem *template_base) +{ + struct ipu_dc_priv *priv; + static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, + 0x78, 0, 0x94, 0xb4}; + int i; + + priv = xzalloc(sizeof(*priv)); + + priv->dev = dev; + priv->ipu = ipu; + priv->dc_reg = base; + priv->dc_tmpl_reg = template_base; + + for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) { + priv->channels[i].chno = i; + priv->channels[i].priv = priv; + priv->channels[i].base = priv->dc_reg + channel_offsets[i]; + } + + ipuwritel("dc", DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) | + DC_WR_CH_CONF_PROG_DI_ID, + priv->channels[1].base + DC_WR_CH_CONF); + ipuwritel("dc", DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0), + priv->channels[5].base + DC_WR_CH_CONF); + + ipuwritel("dc", DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN); + + ipu->dc_priv = priv; + + dev_dbg(dev, "DC base: 0x%p template base: 0x%p\n", + base, template_base); + + /* rgb24 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24); + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */ + + /* rgb565 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565); + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */ + + /* gbr24 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24); + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */ + + /* bgr666 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666); + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */ + + /* bgr24 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24); + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */ + + return 0; +} + +void ipu_dc_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c new file mode 100644 index 0000000000..e3338d09ba --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-di.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <asm-generic/div64.h> +#include <malloc.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +struct ipu_di { + void __iomem *base; + int id; + u32 module; + struct clk *clk_di; /* display input clock */ + struct clk *clk_ipu; /* IPU bus clock */ + struct clk clk_di_pixel; /* resulting pixel clock */ + char *clk_name; + const char *di_parent_names[2]; + bool inuse; + unsigned long clkflags; + struct ipu_soc *ipu; +}; + +struct di_sync_config { + int run_count; + int run_src; + int offset_count; + int offset_src; + int repeat_count; + int cnt_clr_src; + int cnt_polarity_gen_en; + int cnt_polarity_clr_src; + int cnt_polarity_trigger_src; + int cnt_up; + int cnt_down; +}; + +enum di_pins { + DI_PIN11 = 0, + DI_PIN12 = 1, + DI_PIN13 = 2, + DI_PIN14 = 3, + DI_PIN15 = 4, + DI_PIN16 = 5, + DI_PIN17 = 6, + DI_PIN_CS = 7, + + DI_PIN_SER_CLK = 0, + DI_PIN_SER_RS = 1, +}; + +enum di_sync_wave { + DI_SYNC_NONE = 0, + DI_SYNC_CLK = 1, + DI_SYNC_INT_HSYNC = 2, + DI_SYNC_HSYNC = 3, + DI_SYNC_VSYNC = 4, + DI_SYNC_DE = 6, +}; + +#define SYNC_WAVE 0 + +#define DI_GENERAL 0x0000 +#define DI_BS_CLKGEN0 0x0004 +#define DI_BS_CLKGEN1 0x0008 +#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1)) +#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1)) +#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2)) +#define DI_SYNC_AS_GEN 0x0054 +#define DI_DW_GEN(gen) (0x0058 + 4 * (gen)) +#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set))) +#define DI_SER_CONF 0x015c +#define DI_SSC 0x0160 +#define DI_POL 0x0164 +#define DI_AW0 0x0168 +#define DI_AW1 0x016c +#define DI_SCR_CONF 0x0170 +#define DI_STAT 0x0174 + +#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19) +#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16) +#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3) +#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0) + +#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29) +#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25) +#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12) +#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9) +#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16) +#define DI_SW_GEN1_CNT_UP(x) (x) +#define DI_SW_GEN1_AUTO_RELOAD (0x10000000) + +#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24 +#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16 + +#define DI_GEN_POLARITY_1 (1 << 0) +#define DI_GEN_POLARITY_2 (1 << 1) +#define DI_GEN_POLARITY_3 (1 << 2) +#define DI_GEN_POLARITY_4 (1 << 3) +#define DI_GEN_POLARITY_5 (1 << 4) +#define DI_GEN_POLARITY_6 (1 << 5) +#define DI_GEN_POLARITY_7 (1 << 6) +#define DI_GEN_POLARITY_8 (1 << 7) +#define DI_GEN_POLARITY_DISP_CLK (1 << 17) +#define DI_GEN_DI_CLK_EXT (1 << 20) +#define DI_GEN_DI_VSYNC_EXT (1 << 21) + +#define DI_POL_DRDY_DATA_POLARITY (1 << 7) +#define DI_POL_DRDY_POLARITY_15 (1 << 4) + +#define DI_VSYNC_SEL_OFFSET 13 + +static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset) +{ + return readl(di->base + offset); +} + +static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset) +{ + ipuwritel("di", value, di->base + offset); +} + +static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate) +{ + u64 tmp = inrate; + int div; + + tmp *= 16; + + do_div(tmp, outrate); + + div = tmp; + + if (div < 0x10) + div = 0x10; + +#ifdef WTF_IS_THIS + /* + * Freescale has this in their Kernel. It is neither clear what + * it does nor why it does it + */ + if (div & 0x10) + div &= ~0x7; + else { + /* Round up divider if it gets us closer to desired pix clk */ + if ((div & 0xC) == 0xC) { + div += 0x10; + div &= ~0xF; + } + } +#endif + return div; +} + +static unsigned long clk_di_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); + unsigned long outrate; + u32 div = ipu_di_read(di, DI_BS_CLKGEN0); + + if (div < 0x10) + div = 0x10; + + outrate = (parent_rate / div) * 16; + + return outrate; +} + +static long clk_di_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); + unsigned long outrate; + int div; + u32 val; + + div = ipu_di_clk_calc_div(*prate, rate); + + outrate = (*prate / div) * 16; + + val = ipu_di_read(di, DI_GENERAL); + + if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2) + outrate = *prate / 2; + + dev_dbg(di->ipu->dev, + "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n", + __func__, *prate, div, outrate, rate); + + return outrate; +} + +static int clk_di_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); + int div; + u32 clkgen0; + + clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff; + + div = ipu_di_clk_calc_div(parent_rate, rate); + + ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0); + + dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n", + __func__, parent_rate, rate, div); + return 0; +} + +static int clk_di_get_parent(struct clk *clk) +{ + struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); + u32 val; + + val = ipu_di_read(di, DI_GENERAL); + + return val & DI_GEN_DI_CLK_EXT ? 1 : 0; +} + +static int clk_di_set_parent(struct clk *clk, u8 index) +{ + struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); + u32 val; + + val = ipu_di_read(di, DI_GENERAL); + + if (index) + val |= DI_GEN_DI_CLK_EXT; + else + val &= ~DI_GEN_DI_CLK_EXT; + + ipu_di_write(di, val, DI_GENERAL); + + return 0; +} + +static struct clk_ops clk_di_ops = { + .round_rate = clk_di_round_rate, + .set_rate = clk_di_set_rate, + .recalc_rate = clk_di_recalc_rate, + .set_parent = clk_di_set_parent, + .get_parent = clk_di_get_parent, +}; + +static void ipu_di_data_wave_config(struct ipu_di *di, + int wave_gen, + int access_size, int component_size) +{ + u32 reg; + reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | + (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); + ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); +} + +static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, + int set, int up, int down) +{ + u32 reg; + + reg = ipu_di_read(di, DI_DW_GEN(wave_gen)); + reg &= ~(0x3 << (di_pin * 2)); + reg |= set << (di_pin * 2); + ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); + + ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set)); +} + +static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, + int start, int count) +{ + u32 reg; + int i; + + for (i = 0; i < count; i++) { + struct di_sync_config *c = &config[i]; + int wave_gen = start + i + 1; + + if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || + (c->repeat_count >= 0x1000) || + (c->cnt_up >= 0x400) || + (c->cnt_down >= 0x400)) { + dev_err(di->ipu->dev, "DI%d counters out of range.\n", + di->id); + return; + } + + reg = DI_SW_GEN0_RUN_COUNT(c->run_count) | + DI_SW_GEN0_RUN_SRC(c->run_src) | + DI_SW_GEN0_OFFSET_COUNT(c->offset_count) | + DI_SW_GEN0_OFFSET_SRC(c->offset_src); + ipu_di_write(di, reg, DI_SW_GEN0(wave_gen)); + + reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) | + DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) | + DI_SW_GEN1_CNT_POL_TRIGGER_SRC( + c->cnt_polarity_trigger_src) | + DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) | + DI_SW_GEN1_CNT_DOWN(c->cnt_down) | + DI_SW_GEN1_CNT_UP(c->cnt_up); + + /* Enable auto reload */ + if (c->repeat_count == 0) + reg |= DI_SW_GEN1_AUTO_RELOAD; + + ipu_di_write(di, reg, DI_SW_GEN1(wave_gen)); + + reg = ipu_di_read(di, DI_STP_REP(wave_gen)); + reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1))); + reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1)); + ipu_di_write(di, reg, DI_STP_REP(wave_gen)); + } +} + +static void ipu_di_sync_config_interlaced(struct ipu_di *di, + struct ipu_di_signal_cfg *sig) +{ + u32 h_total = sig->width + sig->h_sync_width + + sig->h_start_width + sig->h_end_width; + u32 v_total = sig->height + sig->v_sync_width + + sig->v_start_width + sig->v_end_width; + u32 reg; + struct di_sync_config cfg[] = { + { + .run_count = h_total / 2 - 1, + .run_src = DI_SYNC_CLK, + }, { + .run_count = h_total - 11, + .run_src = DI_SYNC_CLK, + .cnt_down = 4, + }, { + .run_count = v_total * 2 - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = 1, + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_down = 4, + }, { + .run_count = v_total / 2 - 1, + .run_src = DI_SYNC_HSYNC, + .offset_count = sig->v_start_width, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = 2, + .cnt_clr_src = DI_SYNC_VSYNC, + }, { + .run_src = DI_SYNC_HSYNC, + .repeat_count = sig->height / 2, + .cnt_clr_src = 4, + }, { + .run_count = v_total - 1, + .run_src = DI_SYNC_HSYNC, + }, { + .run_count = v_total / 2 - 1, + .run_src = DI_SYNC_HSYNC, + .offset_count = 9, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = 2, + .cnt_clr_src = DI_SYNC_VSYNC, + }, { + .run_src = DI_SYNC_CLK, + .offset_count = sig->h_start_width, + .offset_src = DI_SYNC_CLK, + .repeat_count = sig->width, + .cnt_clr_src = 5, + }, { + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = v_total / 2, + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_clr_src = DI_SYNC_HSYNC, + .cnt_down = 4, + } + }; + + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); + + /* set gentime select and tag sel */ + reg = ipu_di_read(di, DI_SW_GEN1(9)); + reg &= 0x1FFFFFFF; + reg |= (3 - 1) << 29 | 0x00008000; + ipu_di_write(di, reg, DI_SW_GEN1(9)); + + ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF); +} + +static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, + struct ipu_di_signal_cfg *sig, int div) +{ + u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + + sig->h_end_width; + u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + + sig->v_end_width; + struct di_sync_config cfg[] = { + { + /* 1: INT_HSYNC */ + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + } , { + /* PIN2: HSYNC */ + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + .offset_count = div * sig->v_to_h_sync, + .offset_src = DI_SYNC_CLK, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_CLK, + .cnt_down = sig->h_sync_width * 2, + } , { + /* PIN3: VSYNC */ + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, + .cnt_down = sig->v_sync_width * 2, + } , { + /* 4: Line Active */ + .run_src = DI_SYNC_HSYNC, + .offset_count = sig->v_sync_width + sig->v_start_width, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = sig->height, + .cnt_clr_src = DI_SYNC_VSYNC, + } , { + /* 5: Pixel Active, referenced by DC */ + .run_src = DI_SYNC_CLK, + .offset_count = sig->h_sync_width + sig->h_start_width, + .offset_src = DI_SYNC_CLK, + .repeat_count = sig->width, + .cnt_clr_src = 5, /* Line Active */ + } , { + /* unused */ + } , { + /* unused */ + } , { + /* unused */ + } , { + /* unused */ + }, + }; + /* can't use #7 and #8 for line active and pixel active counters */ + struct di_sync_config cfg_vga[] = { + { + /* 1: INT_HSYNC */ + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + } , { + /* 2: VSYNC */ + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + } , { + /* 3: Line Active */ + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = sig->v_sync_width + sig->v_start_width, + .offset_src = DI_SYNC_INT_HSYNC, + .repeat_count = sig->height, + .cnt_clr_src = 3 /* VSYNC */, + } , { + /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */ + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */ + .offset_src = DI_SYNC_CLK, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_CLK, + .cnt_down = sig->h_sync_width * 2, + } , { + /* 5: Pixel Active signal to DC */ + .run_src = DI_SYNC_CLK, + .offset_count = sig->h_sync_width + sig->h_start_width, + .offset_src = DI_SYNC_CLK, + .repeat_count = sig->width, + .cnt_clr_src = 4, /* Line Active */ + } , { + /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */ + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = 1, /* magic value from Freescale TVE driver */ + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, + .cnt_down = sig->v_sync_width * 2, + } , { + /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */ + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */ + .offset_src = DI_SYNC_CLK, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_CLK, + .cnt_down = sig->h_sync_width * 2, + } , { + /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */ + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = 1, /* magic value from Freescale TVE driver */ + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, + .cnt_down = sig->v_sync_width * 2, + } , { + /* unused */ + }, + }; + + ipu_di_write(di, v_total - 1, DI_SCR_CONF); + if (sig->hsync_pin == 2 && sig->vsync_pin == 3) + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); + else + ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga)); +} + +int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) +{ + u32 reg; + u32 di_gen, vsync_cnt; + u32 div; + u32 h_total, v_total; + int ret; + unsigned long round; + struct clk *parent; + + dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d, pixelclock = %ld\n", + di->id, sig->width, sig->height, sig->pixelclock); + + if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0)) + return -EINVAL; + + if (sig->clkflags & IPU_DI_CLKMODE_EXT) + parent = di->clk_di; + else + parent = di->clk_ipu; + + ret = clk_set_parent(&di->clk_di_pixel, parent); + if (ret) { + dev_err(di->ipu->dev, + "setting pixel clock to parent %s failed with %d\n", + parent->name, ret); + return ret; + } + + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) { + ret = clk_set_rate(clk_get_parent(parent), sig->pixelclock); + round = sig->pixelclock; + } else if (sig->clkflags & IPU_DI_CLKMODE_NON_FRACTIONAL) { + unsigned div; + + round = clk_get_rate(parent); + div = DIV_ROUND_CLOSEST(round, sig->pixelclock); + round = round / div; + } else { + round = sig->pixelclock; + } + + ret = clk_set_rate(&di->clk_di_pixel, round); + + h_total = sig->width + sig->h_sync_width + sig->h_start_width + + sig->h_end_width; + v_total = sig->height + sig->v_sync_width + sig->v_start_width + + sig->v_end_width; + + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff; + div = div / 16; /* Now divider is integer portion */ + + /* Setup pixel clock timing */ + /* Down time is half of period */ + ipu_di_write(di, (div << 16), DI_BS_CLKGEN1); + + ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1); + ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); + + di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT; + di_gen |= DI_GEN_DI_VSYNC_EXT; + + if (sig->interlaced) { + ipu_di_sync_config_interlaced(di, sig); + + /* set y_sel = 1 */ + di_gen |= 0x10000000; + di_gen |= DI_GEN_POLARITY_5; + di_gen |= DI_GEN_POLARITY_8; + + vsync_cnt = 7; + + if (sig->Hsync_pol) + di_gen |= DI_GEN_POLARITY_3; + if (sig->Vsync_pol) + di_gen |= DI_GEN_POLARITY_2; + } else { + ipu_di_sync_config_noninterlaced(di, sig, div); + + vsync_cnt = 3; + if (di->id == 1) + /* + * TODO: change only for TVEv2, parallel display + * uses pin 2 / 3 + */ + if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3)) + vsync_cnt = 6; + + if (sig->Hsync_pol) { + if (sig->hsync_pin == 2) + di_gen |= DI_GEN_POLARITY_2; + else if (sig->hsync_pin == 4) + di_gen |= DI_GEN_POLARITY_4; + else if (sig->hsync_pin == 7) + di_gen |= DI_GEN_POLARITY_7; + } + if (sig->Vsync_pol) { + if (sig->vsync_pin == 3) + di_gen |= DI_GEN_POLARITY_3; + else if (sig->vsync_pin == 6) + di_gen |= DI_GEN_POLARITY_6; + else if (sig->vsync_pin == 8) + di_gen |= DI_GEN_POLARITY_8; + } + } + + if (!sig->clk_pol) + di_gen |= DI_GEN_POLARITY_DISP_CLK; + + ipu_di_write(di, di_gen, DI_GENERAL); + + ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002, + DI_SYNC_AS_GEN); + + reg = ipu_di_read(di, DI_POL); + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); + + if (sig->enable_pol) + reg |= DI_POL_DRDY_POLARITY_15; + if (sig->data_pol) + reg |= DI_POL_DRDY_DATA_POLARITY; + + ipu_di_write(di, reg, DI_POL); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel); + +int ipu_di_enable(struct ipu_di *di) +{ + int ret = clk_enable(&di->clk_di_pixel); + if (ret) + return ret; + + ipu_module_enable(di->ipu, di->module); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_enable); + +int ipu_di_disable(struct ipu_di *di) +{ + ipu_module_disable(di->ipu, di->module); + + clk_disable(&di->clk_di_pixel); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_disable); + +int ipu_di_get_num(struct ipu_di *di) +{ + return di->id; +} +EXPORT_SYMBOL_GPL(ipu_di_get_num); + +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp) +{ + struct ipu_di *di; + + if (disp > 1) + return ERR_PTR(-EINVAL); + + di = ipu->di_priv[disp]; + + if (di->inuse) { + di = ERR_PTR(-EBUSY); + goto out; + } + + di->inuse = true; +out: + return di; +} +EXPORT_SYMBOL_GPL(ipu_di_get); + +void ipu_di_put(struct ipu_di *di) +{ + di->inuse = false; +} +EXPORT_SYMBOL_GPL(ipu_di_put); + +int ipu_di_init(struct ipu_soc *ipu, struct device_d *dev, int id, + void __iomem *base, + u32 module, struct clk *clk_ipu) +{ + struct ipu_di *di; + int ret; + + if (id > 1) + return -ENODEV; + + di = xzalloc(sizeof(*di)); + + ipu->di_priv[id] = di; + + di->clk_di = clk_get(dev, id ? "di1" : "di0"); + if (IS_ERR(di->clk_di)) + return PTR_ERR(di->clk_di); + + di->module = module; + di->id = id; + di->clk_ipu = clk_ipu; + di->base = base; + + di->di_parent_names[0] = di->clk_ipu->name; + di->di_parent_names[1] = di->clk_di->name; + + ipu_di_write(di, 0x10, DI_BS_CLKGEN0); + + di->clk_di_pixel.parent_names = di->di_parent_names; + di->clk_name = asprintf("%s_di%d_pixel", + dev_name(dev), id); + if (!di->clk_name) + return -ENOMEM; + + di->clk_di_pixel.ops = &clk_di_ops; + di->clk_di_pixel.num_parents = 2; + di->clk_di_pixel.name = di->clk_name; + ret = clk_register(&di->clk_di_pixel); + if (ret) + goto failed_clk_register; + + dev_dbg(dev, "DI%d base: 0x%p\n", id, base); + di->inuse = false; + di->ipu = ipu; + + return 0; + +failed_clk_register: + + free(di->clk_name); + + return ret; +} + +void ipu_di_exit(struct ipu_soc *ipu, int id) +{ +} diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c new file mode 100644 index 0000000000..7b54e25001 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DMFC_RD_CHAN 0x0000 +#define DMFC_WR_CHAN 0x0004 +#define DMFC_WR_CHAN_DEF 0x0008 +#define DMFC_DP_CHAN 0x000c +#define DMFC_DP_CHAN_DEF 0x0010 +#define DMFC_GENERAL1 0x0014 +#define DMFC_GENERAL2 0x0018 +#define DMFC_IC_CTRL 0x001c +#define DMFC_STAT 0x0020 + +#define DMFC_WR_CHAN_1_28 0 +#define DMFC_WR_CHAN_2_41 8 +#define DMFC_WR_CHAN_1C_42 16 +#define DMFC_WR_CHAN_2C_43 24 + +#define DMFC_DP_CHAN_5B_23 0 +#define DMFC_DP_CHAN_5F_27 8 +#define DMFC_DP_CHAN_6B_24 16 +#define DMFC_DP_CHAN_6F_29 24 + +#define DMFC_FIFO_SIZE_64 (3 << 3) +#define DMFC_FIFO_SIZE_128 (2 << 3) +#define DMFC_FIFO_SIZE_256 (1 << 3) +#define DMFC_FIFO_SIZE_512 (0 << 3) + +#define DMFC_SEGMENT(x) ((x & 0x7) << 0) +#define DMFC_BURSTSIZE_128 (0 << 6) +#define DMFC_BURSTSIZE_64 (1 << 6) +#define DMFC_BURSTSIZE_32 (2 << 6) +#define DMFC_BURSTSIZE_16 (3 << 6) + +struct dmfc_channel_data { + int ipu_channel; + unsigned long channel_reg; + unsigned long shift; + unsigned eot_shift; + unsigned max_fifo_lines; +}; + +static const struct dmfc_channel_data dmfcdata[] = { + { + .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_5B_23, + .eot_shift = 20, + .max_fifo_lines = 3, + }, { + .ipu_channel = 24, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_6B_24, + .eot_shift = 22, + .max_fifo_lines = 1, + }, { + .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_5F_27, + .eot_shift = 21, + .max_fifo_lines = 2, + }, { + .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, + .channel_reg = DMFC_WR_CHAN, + .shift = DMFC_WR_CHAN_1_28, + .eot_shift = 16, + .max_fifo_lines = 2, + }, { + .ipu_channel = 29, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_6F_29, + .eot_shift = 23, + .max_fifo_lines = 1, + }, +}; + +#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) + +struct ipu_dmfc_priv; + +struct dmfc_channel { + unsigned slots; + unsigned slotmask; + unsigned segment; + int burstsize; + struct ipu_soc *ipu; + struct ipu_dmfc_priv *priv; + const struct dmfc_channel_data *data; +}; + +struct ipu_dmfc_priv { + struct ipu_soc *ipu; + struct device_d *dev; + struct dmfc_channel channels[DMFC_NUM_CHANNELS]; + unsigned long bandwidth_per_slot; + void __iomem *base; + int use_count; +}; + +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); + + priv->use_count++; + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); + +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + + priv->use_count--; + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); + + if (priv->use_count < 0) + priv->use_count = 0; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); + +static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, + int segment, int burstsize) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + u32 val, field; + + dev_dbg(priv->dev, + "dmfc: using %d slots starting from segment %d for IPU channel %d\n", + slots, segment, dmfc->data->ipu_channel); + + if (!dmfc) + return -EINVAL; + + switch (slots) { + case 1: + field = DMFC_FIFO_SIZE_64; + break; + case 2: + field = DMFC_FIFO_SIZE_128; + break; + case 4: + field = DMFC_FIFO_SIZE_256; + break; + case 8: + field = DMFC_FIFO_SIZE_512; + break; + default: + return -EINVAL; + } + + switch (burstsize) { + case 16: + field |= DMFC_BURSTSIZE_16; + break; + case 32: + field |= DMFC_BURSTSIZE_32; + break; + case 64: + field |= DMFC_BURSTSIZE_64; + break; + case 128: + field |= DMFC_BURSTSIZE_128; + break; + } + + field |= DMFC_SEGMENT(segment); + + val = ipureadl(priv->base + dmfc->data->channel_reg); + + val &= ~(0xff << dmfc->data->shift); + val |= field << dmfc->data->shift; + + ipuwritel("dmfc", val, priv->base + dmfc->data->channel_reg); + + dmfc->slots = slots; + dmfc->segment = segment; + dmfc->burstsize = burstsize; + dmfc->slotmask = ((1 << slots) - 1) << segment; + + return 0; +} + +static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv, + unsigned long bandwidth) +{ + int slots = 1; + + while (slots * priv->bandwidth_per_slot < bandwidth) + slots *= 2; + + return slots; +} + +static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots) +{ + unsigned slotmask_need, slotmask_used = 0; + int i, segment = 0; + + slotmask_need = (1 << slots) - 1; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + slotmask_used |= priv->channels[i].slotmask; + + while (slotmask_need <= 0xff) { + if (!(slotmask_used & slotmask_need)) + return segment; + + slotmask_need <<= 1; + segment++; + } + + return -EBUSY; +} + +void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + int i; + + dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n", + dmfc->slots, dmfc->segment); + + if (!dmfc->slots) + return; + + dmfc->slotmask = 0; + dmfc->slots = 0; + dmfc->segment = 0; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + priv->channels[i].slotmask = 0; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + if (priv->channels[i].slots > 0) { + priv->channels[i].segment = + dmfc_find_slots(priv, priv->channels[i].slots); + priv->channels[i].slotmask = + ((1 << priv->channels[i].slots) - 1) << + priv->channels[i].segment; + } + } + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + if (priv->channels[i].slots > 0) + ipu_dmfc_setup_channel(&priv->channels[i], + priv->channels[i].slots, + priv->channels[i].segment, + priv->channels[i].burstsize); + } +} +EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth); + +int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, + unsigned long bandwidth_pixel_per_second, int burstsize) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second); + int segment = -1, ret = 0; + + dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n", + bandwidth_pixel_per_second / 1000000, + dmfc->data->ipu_channel); + + ipu_dmfc_free_bandwidth(dmfc); + + if (slots > 8) { + ret = -EBUSY; + goto out; + } + + /* For the MEM_BG channel, first try to allocate twice the slots */ + if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC) + segment = dmfc_find_slots(priv, slots * 2); + else if (slots < 2) + /* Always allocate at least 128*4 bytes (2 slots) */ + slots = 2; + + if (segment >= 0) + slots *= 2; + else + segment = dmfc_find_slots(priv, slots); + if (segment < 0) { + ret = -EBUSY; + goto out; + } + + ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth); + +int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + u32 dmfc_gen1; + + dmfc_gen1 = ipureadl(priv->base + DMFC_GENERAL1); + + if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) + dmfc_gen1 |= 1 << dmfc->data->eot_shift; + else + dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); + + ipuwritel("dmfc", dmfc_gen1, priv->base + DMFC_GENERAL1); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel); + +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) +{ + struct ipu_dmfc_priv *priv = ipu->dmfc_priv; + int i; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + if (dmfcdata[i].ipu_channel == ipu_channel) + return &priv->channels[i]; + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_get); + +void ipu_dmfc_put(struct dmfc_channel *dmfc) +{ + ipu_dmfc_free_bandwidth(dmfc); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_put); + +int ipu_dmfc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base, + struct clk *ipu_clk) +{ + struct ipu_dmfc_priv *priv; + int i; + + priv = xzalloc(sizeof(*priv)); + + priv->base = base; + + priv->dev = dev; + priv->ipu = ipu; + + ipu->dmfc_priv = priv; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + priv->channels[i].priv = priv; + priv->channels[i].ipu = ipu; + priv->channels[i].data = &dmfcdata[i]; + } + + ipuwritel("dmfc", 0x0, priv->base + DMFC_WR_CHAN); + ipuwritel("dmfc", 0x0, priv->base + DMFC_DP_CHAN); + + /* + * We have a total bandwidth of clkrate * 4pixel divided + * into 8 slots. + */ + priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8; + + dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n", + priv->bandwidth_per_slot / 1000000); + + ipuwritel("dmfc", 0x202020f6, priv->base + DMFC_WR_CHAN_DEF); + ipuwritel("dmfc", 0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); + ipuwritel("dmfc", 0x00000003, priv->base + DMFC_GENERAL1); + + return 0; +} + +void ipu_dmfc_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c new file mode 100644 index 0000000000..8829954db0 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-dp.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <malloc.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DP_SYNC 0 +#define DP_ASYNC0 0x60 +#define DP_ASYNC1 0xBC + +#define DP_COM_CONF 0x0 +#define DP_GRAPH_WIND_CTRL 0x0004 +#define DP_FG_POS 0x0008 +#define DP_CSC_A_0 0x0044 +#define DP_CSC_A_1 0x0048 +#define DP_CSC_A_2 0x004C +#define DP_CSC_A_3 0x0050 +#define DP_CSC_0 0x0054 +#define DP_CSC_1 0x0058 + +#define DP_COM_CONF_FG_EN (1 << 0) +#define DP_COM_CONF_GWSEL (1 << 1) +#define DP_COM_CONF_GWAM (1 << 2) +#define DP_COM_CONF_GWCKE (1 << 3) +#define DP_COM_CONF_CSC_DEF_MASK (3 << 8) +#define DP_COM_CONF_CSC_DEF_OFFSET 8 +#define DP_COM_CONF_CSC_DEF_FG (3 << 8) +#define DP_COM_CONF_CSC_DEF_BG (2 << 8) +#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8) + +#define IPUV3_NUM_FLOWS 3 + +struct ipu_dp_priv; + +struct ipu_dp { + u32 flow; + bool in_use; + bool foreground; + enum ipu_color_space in_cs; +}; + +struct ipu_flow { + struct ipu_dp foreground; + struct ipu_dp background; + enum ipu_color_space out_cs; + void __iomem *base; + struct ipu_dp_priv *priv; +}; + +struct ipu_dp_priv { + struct ipu_soc *ipu; + struct device_d *dev; + void __iomem *base; + struct ipu_flow flow[IPUV3_NUM_FLOWS]; + int use_count; +}; + +static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1}; + +static inline struct ipu_flow *to_flow(struct ipu_dp *dp) +{ + if (dp->foreground) + return container_of(dp, struct ipu_flow, foreground); + else + return container_of(dp, struct ipu_flow, background); +} + +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, + u8 alpha, bool bg_chan) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + u32 reg; + + reg = ipureadl(flow->base + DP_COM_CONF); + if (bg_chan) + reg &= ~DP_COM_CONF_GWSEL; + else + reg |= DP_COM_CONF_GWSEL; + ipuwritel("dp", reg, flow->base + DP_COM_CONF); + + if (enable) { + reg = ipureadl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL; + ipuwritel("dp", reg | ((u32) alpha << 24), + flow->base + DP_GRAPH_WIND_CTRL); + + reg = ipureadl(flow->base + DP_COM_CONF); + ipuwritel("dp", reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF); + } else { + reg = ipureadl(flow->base + DP_COM_CONF); + ipuwritel("dp", reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF); + } + + ipu_srm_dp_sync_update(priv->ipu); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha); + +int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + ipuwritel("dp", (x_pos << 16) | y_pos, flow->base + DP_FG_POS); + + ipu_srm_dp_sync_update(priv->ipu); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos); + +static void ipu_dp_csc_init(struct ipu_flow *flow, + enum ipu_color_space in, + enum ipu_color_space out, + u32 place) +{ + u32 reg; + + reg = ipureadl(flow->base + DP_COM_CONF); + reg &= ~DP_COM_CONF_CSC_DEF_MASK; + + if (in == out) { + ipuwritel("dp", reg, flow->base + DP_COM_CONF); + return; + } + + if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) { + ipuwritel("dp", 0x099 | (0x12d << 16), flow->base + DP_CSC_A_0); + ipuwritel("dp", 0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1); + ipuwritel("dp", 0x356 | (0x100 << 16), flow->base + DP_CSC_A_2); + ipuwritel("dp", 0x100 | (0x329 << 16), flow->base + DP_CSC_A_3); + ipuwritel("dp", 0x3d6 | (0x0000 << 16) | (2 << 30), + flow->base + DP_CSC_0); + ipuwritel("dp", 0x200 | (2 << 14) | (0x200 << 16) | (2 << 30), + flow->base + DP_CSC_1); + } else { + ipuwritel("dp", 0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); + ipuwritel("dp", 0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1); + ipuwritel("dp", 0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2); + ipuwritel("dp", 0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3); + ipuwritel("dp", 0x000 | (0x3e42 << 16) | (1 << 30), + flow->base + DP_CSC_0); + ipuwritel("dp", 0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30), + flow->base + DP_CSC_1); + } + + reg |= place; + + ipuwritel("dp", reg, flow->base + DP_COM_CONF); +} + +int ipu_dp_setup_channel(struct ipu_dp *dp, + enum ipu_color_space in, + enum ipu_color_space out) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + dp->in_cs = in; + + if (!dp->foreground) + flow->out_cs = out; + + if (flow->foreground.in_cs == flow->background.in_cs) { + /* + * foreground and background are of same colorspace, put + * colorspace converter after combining unit. + */ + ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs, + DP_COM_CONF_CSC_DEF_BOTH); + } else { + if (flow->foreground.in_cs == flow->out_cs) + /* + * foreground identical to output, apply color + * conversion on background + */ + ipu_dp_csc_init(flow, flow->background.in_cs, + flow->out_cs, DP_COM_CONF_CSC_DEF_BG); + else + ipu_dp_csc_init(flow, flow->foreground.in_cs, + flow->out_cs, DP_COM_CONF_CSC_DEF_FG); + } + + ipu_srm_dp_sync_update(priv->ipu); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_setup_channel); + +int ipu_dp_enable_channel(struct ipu_dp *dp) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DP_EN); + + priv->use_count++; + + if (dp->foreground) { + u32 reg; + + reg = ipureadl(flow->base + DP_COM_CONF); + reg |= DP_COM_CONF_FG_EN; + ipuwritel("dp", reg, flow->base + DP_COM_CONF); + + ipu_srm_dp_sync_update(priv->ipu); + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_enable_channel); + +void ipu_dp_disable_channel(struct ipu_dp *dp) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + priv->use_count--; + + if (dp->foreground) { + u32 reg, csc; + + reg = ipureadl(flow->base + DP_COM_CONF); + csc = reg & DP_COM_CONF_CSC_DEF_MASK; + if (csc == DP_COM_CONF_CSC_DEF_FG) + reg &= ~DP_COM_CONF_CSC_DEF_MASK; + + reg &= ~DP_COM_CONF_FG_EN; + ipuwritel("dp", reg, flow->base + DP_COM_CONF); + + ipuwritel("dp", 0, flow->base + DP_FG_POS); + ipu_srm_dp_sync_update(priv->ipu); + } + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DP_EN); + + if (priv->use_count < 0) + priv->use_count = 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); + +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow) +{ + struct ipu_dp_priv *priv = ipu->dp_priv; + struct ipu_dp *dp; + + if ((flow >> 1) >= IPUV3_NUM_FLOWS) + return ERR_PTR(-EINVAL); + + if (flow & 1) + dp = &priv->flow[flow >> 1].foreground; + else + dp = &priv->flow[flow >> 1].background; + + if (dp->in_use) + return ERR_PTR(-EBUSY); + + dp->in_use = true; + + return dp; +} +EXPORT_SYMBOL_GPL(ipu_dp_get); + +void ipu_dp_put(struct ipu_dp *dp) +{ + dp->in_use = false; +} +EXPORT_SYMBOL_GPL(ipu_dp_put); + +int ipu_dp_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base) +{ + struct ipu_dp_priv *priv; + int i; + + priv = xzalloc(sizeof(*priv)); + priv->dev = dev; + priv->ipu = ipu; + + ipu->dp_priv = priv; + + priv->base = base; + + for (i = 0; i < IPUV3_NUM_FLOWS; i++) { + priv->flow[i].foreground.foreground = true; + priv->flow[i].base = priv->base + ipu_dp_flow_base[i]; + priv->flow[i].priv = priv; + } + + return 0; +} + +void ipu_dp_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h new file mode 100644 index 0000000000..44d7802521 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipu-prv.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * 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. + */ +#ifndef __IPU_PRV_H__ +#define __IPU_PRV_H__ + +struct ipu_soc; + +#include "imx-ipu-v3.h" + +#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3') + +#define IPUV3_CHANNEL_CSI0 0 +#define IPUV3_CHANNEL_CSI1 1 +#define IPUV3_CHANNEL_CSI2 2 +#define IPUV3_CHANNEL_CSI3 3 +#define IPUV3_CHANNEL_MEM_BG_SYNC 23 +#define IPUV3_CHANNEL_MEM_FG_SYNC 27 +#define IPUV3_CHANNEL_MEM_DC_SYNC 28 +#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31 +#define IPUV3_CHANNEL_MEM_DC_ASYNC 41 +#define IPUV3_CHANNEL_ROT_ENC_MEM 45 +#define IPUV3_CHANNEL_ROT_VF_MEM 46 +#define IPUV3_CHANNEL_ROT_PP_MEM 47 +#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48 +#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49 +#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50 +#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51 + +#define IPU_MCU_T_DEFAULT 8 +#define IPU_CM_IDMAC_REG_OFS 0x00008000 +#define IPU_CM_IC_REG_OFS 0x00020000 +#define IPU_CM_IRT_REG_OFS 0x00028000 +#define IPU_CM_CSI0_REG_OFS 0x00030000 +#define IPU_CM_CSI1_REG_OFS 0x00038000 +#define IPU_CM_SMFC_REG_OFS 0x00050000 +#define IPU_CM_DC_REG_OFS 0x00058000 +#define IPU_CM_DMFC_REG_OFS 0x00060000 + +/* Register addresses */ +/* IPU Common registers */ +#define IPU_CM_REG(offset) (offset) + +#define IPU_CONF IPU_CM_REG(0) + +#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0) +#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4) +#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8) +#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac) +#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0) +#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4) +#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8) +#define IPU_SKIP IPU_CM_REG(0x00bc) +#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0) +#define IPU_DISP_GEN IPU_CM_REG(0x00c4) +#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8) +#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc) +#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0) +#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4) +#define IPU_SNOOP IPU_CM_REG(0x00d8) +#define IPU_MEM_RST IPU_CM_REG(0x00dc) +#define IPU_PM IPU_CM_REG(0x00e0) +#define IPU_GPR IPU_CM_REG(0x00e4) +#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32)) +#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32)) +#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244) +#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248) +#define IPU_SRM_STAT IPU_CM_REG(0x024C) +#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250) +#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254) +#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32)) +#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32)) + +#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n)) +#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n)) + +#define IPU_DI0_COUNTER_RELEASE (1 << 24) +#define IPU_DI1_COUNTER_RELEASE (1 << 25) + +#define IPU_IDMAC_REG(offset) (offset) + +#define IDMAC_CONF IPU_IDMAC_REG(0x0000) +#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32)) +#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c) +#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010) +#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32)) +#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32)) +#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024) +#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028) +#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c) +#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030) +#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034) +#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32)) +#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32)) + +#define IPU_NUM_IRQS (32 * 15) + +enum ipu_modules { + IPU_CONF_CSI0_EN = (1 << 0), + IPU_CONF_CSI1_EN = (1 << 1), + IPU_CONF_IC_EN = (1 << 2), + IPU_CONF_ROT_EN = (1 << 3), + IPU_CONF_ISP_EN = (1 << 4), + IPU_CONF_DP_EN = (1 << 5), + IPU_CONF_DI0_EN = (1 << 6), + IPU_CONF_DI1_EN = (1 << 7), + IPU_CONF_SMFC_EN = (1 << 8), + IPU_CONF_DC_EN = (1 << 9), + IPU_CONF_DMFC_EN = (1 << 10), + + IPU_CONF_VDI_EN = (1 << 12), + + IPU_CONF_IDMAC_DIS = (1 << 22), + + IPU_CONF_IC_DMFC_SEL = (1 << 25), + IPU_CONF_IC_DMFC_SYNC = (1 << 26), + IPU_CONF_VDI_DMFC_SYNC = (1 << 27), + + IPU_CONF_CSI0_DATA_SOURCE = (1 << 28), + IPU_CONF_CSI1_DATA_SOURCE = (1 << 29), + IPU_CONF_IC_INPUT = (1 << 30), + IPU_CONF_CSI_SEL = (1 << 31), +}; + +struct ipuv3_channel { + unsigned int num; + + bool enabled; + bool busy; + + struct ipu_soc *ipu; +}; + +struct ipu_dc_priv; +struct ipu_dmfc_priv; +struct ipu_di; +struct ipu_devtype; + +struct ipu_soc { + struct device_d *dev; + const struct ipu_devtype *devtype; + enum ipuv3_type ipu_type; + spinlock_t lock; + struct mutex channel_lock; + + void __iomem *base; + void __iomem *cm_reg; + void __iomem *idmac_reg; + struct ipu_ch_param __iomem *cpmem_base; + + int usecount; + + struct clk *clk; + + struct ipuv3_channel channel[64]; + + int irq_sync; + int irq_err; + struct irq_domain *domain; + + struct ipu_dc_priv *dc_priv; + struct ipu_dp_priv *dp_priv; + struct ipu_dmfc_priv *dmfc_priv; + struct ipu_di *di_priv[2]; +}; + +void ipu_srm_dp_sync_update(struct ipu_soc *ipu); + +int ipu_module_enable(struct ipu_soc *ipu, u32 mask); +int ipu_module_disable(struct ipu_soc *ipu, u32 mask); + +int ipu_di_init(struct ipu_soc *ipu, struct device_d *dev, int id, + void __iomem *base, u32 module, struct clk *ipu_clk); +void ipu_di_exit(struct ipu_soc *ipu, int id); + +int ipu_dmfc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base, + struct clk *ipu_clk); +void ipu_dmfc_exit(struct ipu_soc *ipu); + +int ipu_dp_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base); +void ipu_dp_exit(struct ipu_soc *ipu); + +int ipu_dc_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base, + void __iomem *template_base); +void ipu_dc_exit(struct ipu_soc *ipu); + +int ipu_cpmem_init(struct ipu_soc *ipu, struct device_d *dev, void __iomem *base); +void ipu_cpmem_exit(struct ipu_soc *ipu); + +#endif /* __IPU_PRV_H__ */ diff --git a/drivers/video/imx-ipu-v3/ipufb.c b/drivers/video/imx-ipu-v3/ipufb.c new file mode 100644 index 0000000000..14a099e14a --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipufb.c @@ -0,0 +1,353 @@ +/* + * Freescale i.MX Frame Buffer device driver + * + * Copyright (C) 2004 Sascha Hauer, Pengutronix + * Based on acornfb.c Copyright (C) Russell King. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#define pr_fmt(fmt) "IPU: " fmt + +#include <common.h> +#include <fb.h> +#include <io.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <init.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <asm-generic/div64.h> +#include <asm/mmu.h> + +#include "imx-ipu-v3.h" +#include "ipuv3-plane.h" + +/* + * These are the bitfields for each + * display depth that we support. + */ +struct ipufb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +struct ipufb_info { + void __iomem *regs; + + struct clk *ahb_clk; + struct clk *ipg_clk; + struct clk *per_clk; + + struct fb_videomode *mode; + + struct fb_info info; + struct device_d *dev; + + /* plane[0] is the full plane, plane[1] is the partial plane */ + struct ipu_plane *plane[2]; + + void (*enable)(int enable); + + unsigned int di_clkflags; + u32 interface_pix_fmt; + struct ipu_dc *dc; + struct ipu_di *di; + + struct list_head list; + char *name; + int id; + + struct ipu_output *output; +}; + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static LIST_HEAD(ipu_outputs); +static LIST_HEAD(ipu_fbs); + +int ipu_register_output(struct ipu_output *ouput) +{ + list_add_tail(&ouput->list, &ipu_outputs); + + return 0; +} + +static int ipu_register_fb(struct ipufb_info *ipufb) +{ + list_add_tail(&ipufb->list, &ipu_fbs); + + return 0; +} + +int ipu_crtc_mode_set(struct ipufb_info *fbi, + struct fb_videomode *mode, + int x, int y) +{ + struct fb_info *info = &fbi->info; + int ret; + struct ipu_di_signal_cfg sig_cfg = {}; + u32 out_pixel_fmt; + + dev_info(fbi->dev, "%s: mode->xres: %d\n", __func__, + mode->xres); + dev_info(fbi->dev, "%s: mode->yres: %d\n", __func__, + mode->yres); + + out_pixel_fmt = fbi->output->out_pixel_fmt; + + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) + sig_cfg.Hsync_pol = 1; + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + sig_cfg.Vsync_pol = 1; + + sig_cfg.enable_pol = 1; + sig_cfg.clk_pol = 1; + sig_cfg.width = mode->xres; + sig_cfg.height = mode->yres; + sig_cfg.pixel_fmt = out_pixel_fmt; + sig_cfg.h_start_width = mode->left_margin; + sig_cfg.h_sync_width = mode->hsync_len; + sig_cfg.h_end_width = mode->right_margin; + + sig_cfg.v_start_width = mode->upper_margin; + sig_cfg.v_sync_width = mode->vsync_len; + sig_cfg.v_end_width = mode->lower_margin; + sig_cfg.pixelclock = PICOS2KHZ(mode->pixclock) * 1000UL; + sig_cfg.clkflags = fbi->output->di_clkflags; + + sig_cfg.v_to_h_sync = 0; + + sig_cfg.hsync_pin = 2; + sig_cfg.vsync_pin = 3; + + ret = ipu_dc_init_sync(fbi->dc, fbi->di, sig_cfg.interlaced, + out_pixel_fmt, mode->xres); + if (ret) { + dev_err(fbi->dev, + "initializing display controller failed with %d\n", + ret); + return ret; + } + + ret = ipu_di_init_sync_panel(fbi->di, &sig_cfg); + if (ret) { + dev_err(fbi->dev, + "initializing panel failed with %d\n", ret); + return ret; + } + + ret = ipu_plane_mode_set(fbi->plane[0], mode, info, DRM_FORMAT_XRGB8888, + 0, 0, mode->xres, mode->yres, + x, y, mode->xres, mode->yres); + if (ret) { + dev_err(fbi->dev, "initialising plane failed with %s\n", strerror(-ret)); + return ret; + } + + ret = ipu_di_enable(fbi->di); + if (ret) { + dev_err(fbi->dev, "enabling di failed with %s\n", strerror(-ret)); + return ret; + } + + ipu_dc_enable_channel(fbi->dc); + + ipu_plane_enable(fbi->plane[0]); + + return 0; +} + +static void ipufb_enable_controller(struct fb_info *info) +{ + struct ipufb_info *fbi = container_of(info, struct ipufb_info, info); + struct ipu_output *output = fbi->output; + + if (output->ops->prepare) + output->ops->prepare(output, info->mode, fbi->id); + + ipu_crtc_mode_set(fbi, info->mode, 0, 0); + + if (output->ops->enable) + output->ops->enable(output, info->mode, fbi->id); +} + +static void ipufb_disable_controller(struct fb_info *info) +{ + struct ipufb_info *fbi = container_of(info, struct ipufb_info, info); + struct ipu_output *output = fbi->output; + + if (output->ops->disable) + output->ops->disable(output); + + ipu_plane_disable(fbi->plane[0]); + ipu_dc_disable_channel(fbi->dc); + ipu_di_disable(fbi->di); + + if (output->ops->unprepare) + output->ops->unprepare(output); +} + +static int ipufb_activate_var(struct fb_info *info) +{ + struct ipufb_info *fbi = container_of(info, struct ipufb_info, info); + + info->line_length = info->xres * (info->bits_per_pixel >> 3); + fbi->info.screen_base = dma_alloc_coherent(info->line_length * info->yres); + if (!fbi->info.screen_base) + return -ENOMEM; + + memset(fbi->info.screen_base, 0, info->line_length * info->yres); + + return 0; +} + +static struct fb_ops ipufb_ops = { + .fb_enable = ipufb_enable_controller, + .fb_disable = ipufb_disable_controller, + .fb_activate_var = ipufb_activate_var, +}; + +static struct ipufb_info *ipu_output_find_di(struct ipu_output *output) +{ + struct ipufb_info *ipufb; + + list_for_each_entry(ipufb, &ipu_fbs, list) { + if (!(output->ipu_mask & (1 << ipufb->id))) + continue; + if (ipufb->output) + continue; + + return ipufb; + } + + return NULL; +} + +static int ipu_init(void) +{ + struct ipu_output *output; + struct ipufb_info *ipufb; + int ret; + + list_for_each_entry(output, &ipu_outputs, list) { + pr_info("found output: %s\n", output->name); + ipufb = ipu_output_find_di(output); + if (!ipufb) { + pr_info("no di found for output %s\n", output->name); + continue; + } + pr_info("using di %s for output %s\n", ipufb->name, output->name); + + ipufb->output = output; + + ipufb->info.edid_i2c_adapter = output->edid_i2c_adapter; + if (output->modes) { + ipufb->info.modes.modes = output->modes->modes; + ipufb->info.modes.num_modes = output->modes->num_modes; + } + + ret = register_framebuffer(&ipufb->info); + if (ret < 0) { + dev_err(ipufb->dev, "failed to register framebuffer\n"); + return ret; + } + } + + return 0; +} +late_initcall(ipu_init); + +static int ipu_get_resources(struct ipufb_info *fbi, + struct ipu_client_platformdata *pdata) +{ + struct ipu_soc *ipu = fbi->dev->parent->priv; + int ret; + int dp = -EINVAL; + + fbi->dc = ipu_dc_get(ipu, pdata->dc); + if (IS_ERR(fbi->dc)) { + ret = PTR_ERR(fbi->dc); + goto err_out; + } + + fbi->di = ipu_di_get(ipu, pdata->di); + if (IS_ERR(fbi->di)) { + ret = PTR_ERR(fbi->di); + goto err_out; + } + + if (pdata->dp >= 0) + dp = IPU_DP_FLOW_SYNC_BG; + + fbi->plane[0] = ipu_plane_init(ipu, pdata->dma[0], dp); + ret = ipu_plane_get_resources(fbi->plane[0]); + if (ret) { + dev_err(fbi->dev, "getting plane 0 resources failed with %d.\n", + ret); + goto err_out; + } + + return 0; +err_out: + return ret; +} + +static int ipufb_probe(struct device_d *dev) +{ + struct ipufb_info *fbi; + struct fb_info *info; + int ret, ipuid; + struct ipu_client_platformdata *pdata = dev->platform_data; + struct ipu_rgb *ipu_rgb; + + fbi = xzalloc(sizeof(*fbi)); + info = &fbi->info; + + ipuid = of_alias_get_id(dev->parent->device_node, "ipu"); + fbi->name = asprintf("ipu%d-di%d", ipuid + 1, pdata->di); + fbi->id = ipuid * 2 + pdata->di; + + fbi->dev = dev; + info->priv = fbi; + info->fbops = &ipufb_ops; + + ipu_rgb = drm_fourcc_to_rgb(DRM_FORMAT_RGB888); + + info->bits_per_pixel = 32; + info->red = ipu_rgb->red; + info->green = ipu_rgb->green; + info->blue = ipu_rgb->blue; + info->transp = ipu_rgb->transp; + + dev_dbg(dev, "i.MX Framebuffer driver\n"); + + ret = ipu_get_resources(fbi, pdata); + if (ret) + return ret; + + ret = ipu_register_fb(fbi); + + return ret; +} + +static void ipufb_remove(struct device_d *dev) +{ +} + +static struct driver_d ipufb_driver = { + .name = "imx-ipuv3-crtc", + .probe = ipufb_probe, + .remove = ipufb_remove, +}; +device_platform_driver(ipufb_driver); diff --git a/drivers/video/imx-ipu-v3/ipuv3-plane.c b/drivers/video/imx-ipu-v3/ipuv3-plane.c new file mode 100644 index 0000000000..9dffcfc670 --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipuv3-plane.c @@ -0,0 +1,239 @@ +/* + * i.MX IPUv3 DP Overlay Planes + * + * Copyright (C) 2013 Philipp Zabel, Pengutronix + * + * 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. + */ +#include <common.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <malloc.h> +#include <fb.h> + +#include "ipuv3-plane.h" +#include "imx-ipu-v3.h" + +static int calc_vref(struct fb_videomode *mode) +{ + unsigned long htotal, vtotal; + + htotal = mode->left_margin + mode->right_margin + mode->xres + mode->hsync_len; + vtotal = mode->upper_margin + mode->lower_margin + mode->yres + mode->vsync_len; + + return DIV_ROUND_UP(PICOS2KHZ(mode->pixclock) * 1000, vtotal * htotal); +} + +static inline int calc_bandwidth(int width, int height, unsigned int vref) +{ + return width * height * vref; +} + +int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct fb_info *info, + int x, int y) +{ + struct ipu_ch_param __iomem *cpmem; + + pr_debug("phys = 0x%p, x = %d, y = %d, line_length = %d\n", + info->screen_base, x, y, info->line_length); + + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); + ipu_cpmem_set_stride(cpmem, info->line_length); + ipu_cpmem_set_buffer(cpmem, 0, (unsigned long)info->screen_base + + info->line_length * y + x); + ipu_cpmem_set_buffer(cpmem, 1, (unsigned long)info->screen_base + + info->line_length * y + x); + + return 0; +} + +int ipu_plane_mode_set(struct ipu_plane *ipu_plane, + struct fb_videomode *mode, + struct fb_info *info, u32 pixel_format, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct ipu_ch_param __iomem *cpmem; + struct device_d *dev = &info->dev; + int ret; + + /* no scaling */ + if (src_w != crtc_w || src_h != crtc_h) + return -EINVAL; + + /* clip to crtc bounds */ + if (crtc_x < 0) { + if (-crtc_x > crtc_w) + return -EINVAL; + src_x += -crtc_x; + src_w -= -crtc_x; + crtc_w -= -crtc_x; + crtc_x = 0; + } + if (crtc_y < 0) { + if (-crtc_y > crtc_h) + return -EINVAL; + src_y += -crtc_y; + src_h -= -crtc_y; + crtc_h -= -crtc_y; + crtc_y = 0; + } + if (crtc_x + crtc_w > mode->xres) { + if (crtc_x > mode->xres) + return -EINVAL; + crtc_w = mode->xres - crtc_x; + src_w = crtc_w; + } + if (crtc_y + crtc_h > mode->yres) { + if (crtc_y > mode->yres) + return -EINVAL; + crtc_h = mode->yres - crtc_y; + src_h = crtc_h; + } + /* full plane minimum width is 13 pixels */ + if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG)) + return -EINVAL; + if (crtc_h < 2) + return -EINVAL; + + switch (ipu_plane->dp_flow) { + case IPU_DP_FLOW_SYNC_BG: + ret = ipu_dp_setup_channel(ipu_plane->dp, + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_RGB); + if (ret) { + dev_err(dev, + "initializing display processor failed with %d\n", + ret); + return ret; + } + ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1); + break; + case IPU_DP_FLOW_SYNC_FG: + ipu_dp_setup_channel(ipu_plane->dp, + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_UNKNOWN); + ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y); + break; + } + + ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w); + if (ret) { + dev_err(dev, "initializing dmfc channel failed with %d\n", ret); + return ret; + } + + ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc, + calc_bandwidth(crtc_w, crtc_h, + calc_vref(mode)), 64); + if (ret) { + dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret); + return ret; + } + + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); + ipu_ch_param_zero(cpmem); + ipu_cpmem_set_resolution(cpmem, src_w, src_h); + ret = ipu_cpmem_set_fmt(cpmem, pixel_format); + if (ret < 0) { + dev_err(dev, "unsupported pixel format 0x%08x\n", + pixel_format); + return ret; + } + ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); + + ret = ipu_plane_set_base(ipu_plane, info, src_x, src_y); + if (ret < 0) + return ret; + + return 0; +} + +void ipu_plane_put_resources(struct ipu_plane *ipu_plane) +{ + if (!IS_ERR_OR_NULL(ipu_plane->dp)) + ipu_dp_put(ipu_plane->dp); + if (!IS_ERR_OR_NULL(ipu_plane->dmfc)) + ipu_dmfc_put(ipu_plane->dmfc); + if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch)) + ipu_idmac_put(ipu_plane->ipu_ch); +} + +int ipu_plane_get_resources(struct ipu_plane *ipu_plane) +{ + int ret; + + ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma); + if (IS_ERR(ipu_plane->ipu_ch)) { + ret = PTR_ERR(ipu_plane->ipu_ch); + pr_err("failed to get idmac channel: %d\n", ret); + return ret; + } + + ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma); + if (IS_ERR(ipu_plane->dmfc)) { + ret = PTR_ERR(ipu_plane->dmfc); + pr_err("failed to get dmfc: ret %d\n", ret); + goto err_out; + } + + if (ipu_plane->dp_flow >= 0) { + ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow); + if (IS_ERR(ipu_plane->dp)) { + ret = PTR_ERR(ipu_plane->dp); + pr_err("failed to get dp flow: %d\n", ret); + goto err_out; + } + } + + return 0; +err_out: + ipu_plane_put_resources(ipu_plane); + + return ret; +} + +void ipu_plane_enable(struct ipu_plane *ipu_plane) +{ + ipu_dmfc_enable_channel(ipu_plane->dmfc); + ipu_idmac_enable_channel(ipu_plane->ipu_ch); + if (ipu_plane->dp) + ipu_dp_enable_channel(ipu_plane->dp); + + ipu_plane->enabled = true; +} + +void ipu_plane_disable(struct ipu_plane *ipu_plane) +{ + ipu_plane->enabled = false; + + ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); + + if (ipu_plane->dp) + ipu_dp_disable_channel(ipu_plane->dp); + ipu_idmac_disable_channel(ipu_plane->ipu_ch); + ipu_dmfc_disable_channel(ipu_plane->dmfc); +} + +struct ipu_plane *ipu_plane_init(struct ipu_soc *ipu, + int dma, int dp) +{ + struct ipu_plane *ipu_plane; + + ipu_plane = xzalloc(sizeof(*ipu_plane)); + + ipu_plane->ipu = ipu; + ipu_plane->dma = dma; + ipu_plane->dp_flow = dp; + + return ipu_plane; +} diff --git a/drivers/video/imx-ipu-v3/ipuv3-plane.h b/drivers/video/imx-ipu-v3/ipuv3-plane.h new file mode 100644 index 0000000000..3d52f807fe --- /dev/null +++ b/drivers/video/imx-ipu-v3/ipuv3-plane.h @@ -0,0 +1,51 @@ +#ifndef __IPUV3_PLANE_H__ +#define __IPUV3_PLANE_H__ + +struct drm_plane; +struct drm_device; +struct ipu_soc; +struct drm_crtc; +struct drm_framebuffer; + +struct ipuv3_channel; +struct dmfc_channel; +struct ipu_dp; + +struct ipu_plane { + struct ipu_soc *ipu; + struct ipuv3_channel *ipu_ch; + struct dmfc_channel *dmfc; + struct ipu_dp *dp; + + int dma; + int dp_flow; + + int x; + int y; + + bool enabled; +}; + +struct ipu_plane *ipu_plane_init(struct ipu_soc *ipu, + int dma, int dp); + +/* Init IDMAC, DMFC, DP */ +int ipu_plane_mode_set(struct ipu_plane *ipu_plane, + struct fb_videomode *mode, + struct fb_info *info, u32 pixel_format, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); + +void ipu_plane_enable(struct ipu_plane *plane); +void ipu_plane_disable(struct ipu_plane *plane); +int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct fb_info *info, + int x, int y); + +int ipu_plane_get_resources(struct ipu_plane *plane); +void ipu_plane_put_resources(struct ipu_plane *plane); + +int ipu_plane_irq(struct ipu_plane *plane); + +#endif diff --git a/drivers/video/imx.c b/drivers/video/imx.c index 05c6105c7a..b12c09c8cf 100644 --- a/drivers/video/imx.c +++ b/drivers/video/imx.c @@ -294,7 +294,7 @@ static int imxfb_activate_var(struct fb_info *info) u32 pcr; int i; - for (i = 0; i < info->num_modes; i++) { + for (i = 0; i < info->modes.num_modes; i++) { if (!strcmp(fbi->mode[i].mode.name, mode->name)) { fbi->pcr = fbi->mode[i].pcr; break; @@ -551,8 +551,8 @@ static int imxfb_probe(struct device_d *dev) fbi->enable = pdata->enable; fbi->dev = dev; info->priv = fbi; - info->mode_list = mode_list; - info->num_modes = pdata->num_modes; + info->modes.modes = mode_list; + info->modes.num_modes = pdata->num_modes; info->mode = &pdata->mode->mode; info->xres = pdata->mode->mode.xres; info->yres = pdata->mode->mode.yres; @@ -580,13 +580,8 @@ static int imxfb_probe(struct device_d *dev) return 0; } -static void imxfb_remove(struct device_d *dev) -{ -} - static struct driver_d imxfb_driver = { .name = "imxfb", .probe = imxfb_probe, - .remove = imxfb_remove, }; device_platform_driver(imxfb_driver); diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c new file mode 100644 index 0000000000..5dfd5b3f1c --- /dev/null +++ b/drivers/video/of_display_timing.c @@ -0,0 +1,238 @@ +/* + * OF helpers for parsing display timings + * + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix + * + * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de> + * + * This file is released under the GPLv2 + */ +#include <common.h> +#include <of.h> +#include <fb.h> +#include <malloc.h> + +void display_timings_release(struct display_timings *disp) +{ + free(disp->modes); + free(disp); +} +EXPORT_SYMBOL_GPL(display_timings_release); + +/** + * parse_timing_property - parse timing_entry from device_node + * @np: device_node with the property + * @name: name of the property + * @result: will be set to the return value + * + * DESCRIPTION: + * Every display_timing can be specified with either just the typical value or + * a range consisting of min/typ/max. This function helps handling this + **/ +static int parse_timing_property(const struct device_node *np, const char *name, + u32 *res) +{ + struct property *prop; + int length, cells, ret; + + prop = of_find_property(np, name, &length); + if (!prop) { + pr_err("%s: could not find property %s\n", + np->full_name, name); + return -EINVAL; + } + + cells = length / sizeof(u32); + if (cells == 1) { + ret = of_property_read_u32(np, name, res); + } else { + pr_err("%s: illegal timing specification in %s\n", + np->full_name, name); + return -EINVAL; + } + + return ret; +} + +/** + * of_parse_display_timing - parse display_timing entry from device_node + * @np: device_node with the properties + **/ +static int of_parse_display_timing(const struct device_node *np, + struct fb_videomode *mode) +{ + u32 val = 0, pixelclock = 0; + int ret = 0; + + memset(mode, 0, sizeof(*mode)); + + ret |= parse_timing_property(np, "hback-porch", &mode->left_margin); + ret |= parse_timing_property(np, "hfront-porch", &mode->right_margin); + ret |= parse_timing_property(np, "hactive", &mode->xres); + ret |= parse_timing_property(np, "hsync-len", &mode->hsync_len); + ret |= parse_timing_property(np, "vback-porch", &mode->upper_margin); + ret |= parse_timing_property(np, "vfront-porch", &mode->lower_margin); + ret |= parse_timing_property(np, "vactive", &mode->yres); + ret |= parse_timing_property(np, "vsync-len", &mode->vsync_len); + ret |= parse_timing_property(np, "clock-frequency", &pixelclock); + + mode->pixclock = pixelclock ? KHZ2PICOS(pixelclock / 1000) : 0; + + if (!of_property_read_u32(np, "vsync-active", &val)) + mode->sync |= val ? FB_SYNC_VERT_HIGH_ACT : 0; + if (!of_property_read_u32(np, "hsync-active", &val)) + mode->sync |= val ? FB_SYNC_HOR_HIGH_ACT : 0; + if (!of_property_read_u32(np, "de-active", &val)) + mode->display_flags |= val ? DISPLAY_FLAGS_DE_HIGH : + DISPLAY_FLAGS_DE_LOW; + if (!of_property_read_u32(np, "pixelclk-active", &val)) + mode->display_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : + DISPLAY_FLAGS_PIXDATA_NEGEDGE; + + if (ret) { + pr_err("%s: error reading timing properties\n", + np->full_name); + return -EINVAL; + } + + return 0; +} + +/** + * of_get_display_timing - parse a display_timing entry + * @np: device_node with the timing subnode + * @name: name of the timing node + * @dt: display_timing struct to fill + **/ +int of_get_display_timing(struct device_node *np, const char *name, + struct fb_videomode *mode) +{ + struct device_node *timing_np; + + if (!np) { + pr_err("%s: no devicenode given\n", np->full_name); + return -EINVAL; + } + + timing_np = of_get_child_by_name(np, name); + if (!timing_np) { + pr_err("%s: could not find node '%s'\n", + np->full_name, name); + return -ENOENT; + } + + return of_parse_display_timing(timing_np, mode); +} +EXPORT_SYMBOL_GPL(of_get_display_timing); + +/** + * of_get_display_timings - parse all display_timing entries from a device_node + * @np: device_node with the subnodes + **/ +struct display_timings *of_get_display_timings(struct device_node *np) +{ + struct device_node *timings_np; + struct device_node *entry; + struct device_node *native_mode; + struct display_timings *disp; + + if (!np) { + pr_err("%s: no device node given\n", np->full_name); + return NULL; + } + + timings_np = of_get_child_by_name(np, "display-timings"); + if (!timings_np) { + pr_debug("%s: could not find display-timings node\n", + np->full_name); + return NULL; + } + + disp = xzalloc(sizeof(*disp)); + + entry = of_parse_phandle(timings_np, "native-mode", 0); + /* assume first child as native mode if none provided */ + if (!entry) + entry = of_get_next_available_child(np, NULL); + /* if there is no child, it is useless to go on */ + if (!entry) { + pr_err("%s: no timing specifications given\n", + np->full_name); + goto entryfail; + } + + pr_debug("%s: using %s as default timing\n", + np->full_name, entry->name); + + native_mode = entry; + + disp->num_modes = of_get_child_count(timings_np); + if (disp->num_modes == 0) { + /* should never happen, as entry was already found above */ + pr_err("%s: no timings specified\n", np->full_name); + goto entryfail; + } + + disp->modes = xzalloc(sizeof(struct fb_videomode) * disp->num_modes); + + disp->num_modes = 0; + disp->native_mode = 0; + + for_each_child_of_node(timings_np, entry) { + struct fb_videomode *mode; + int r; + + mode = &disp->modes[disp->num_modes]; + + r = of_parse_display_timing(entry, mode); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of + * an error + */ + pr_err("%s: error in timing %d\n", + np->full_name, disp->num_modes + 1); + goto timingfail; + } + + mode->name = xstrdup(entry->name); + + if (native_mode == entry) + disp->native_mode = disp->num_modes; + + disp->num_modes++; + } + + pr_debug("%s: got %d timings. Using timing #%d as default\n", + np->full_name, disp->num_modes, + disp->native_mode + 1); + + return disp; + +timingfail: + display_timings_release(disp); +entryfail: + free(disp); + + return NULL; +} +EXPORT_SYMBOL_GPL(of_get_display_timings); + +/** + * of_display_timings_exist - check if a display-timings node is provided + * @np: device_node with the timing + **/ +int of_display_timings_exist(struct device_node *np) +{ + struct device_node *timings_np; + + if (!np) + return -EINVAL; + + timings_np = of_parse_phandle(np, "display-timings", 0); + if (!timings_np) + return -EINVAL; + + return 1; +} +EXPORT_SYMBOL_GPL(of_display_timings_exist); diff --git a/drivers/video/omap.c b/drivers/video/omap.c index 487aca6f26..485cc7538b 100644 --- a/drivers/video/omap.c +++ b/drivers/video/omap.c @@ -467,8 +467,8 @@ static int omapfb_probe(struct device_d *dev) for (i = 0; i < pdata->num_displays; ++i) fbi->video_modes[i] = pdata->displays[i].mode; - info->mode_list = fbi->video_modes; - info->num_modes = pdata->num_displays; + info->modes.modes = fbi->video_modes; + info->modes.num_modes = pdata->num_displays; info->priv = fbi; info->fbops = &omapfb_ops; diff --git a/drivers/video/pxa.c b/drivers/video/pxa.c index 529190baec..b4ce3a1bf8 100644 --- a/drivers/video/pxa.c +++ b/drivers/video/pxa.c @@ -536,13 +536,8 @@ static int pxafb_probe(struct device_d *dev) return 0; } -static void pxafb_remove(struct device_d *dev) -{ -} - static struct driver_d pxafb_driver = { .name = "pxafb", .probe = pxafb_probe, - .remove = pxafb_remove, }; device_platform_driver(pxafb_driver); diff --git a/drivers/video/s3c24xx.c b/drivers/video/s3c24xx.c index c3e05c6cd7..b1883e232c 100644 --- a/drivers/video/s3c24xx.c +++ b/drivers/video/s3c24xx.c @@ -376,9 +376,9 @@ static int s3cfb_probe(struct device_d *hw_dev) hw_dev->priv = &fbi; /* add runtime video info */ - fbi.info.mode_list = pdata->mode_list; - fbi.info.num_modes = pdata->mode_cnt; - fbi.info.mode = &fbi.info.mode_list[1]; + fbi.info.modes.modes = pdata->mode_list; + fbi.info.modes.num_modes = pdata->mode_cnt; + fbi.info.mode = &fbi.info.modes.modes[0]; fbi.info.xres = fbi.info.mode->xres; fbi.info.yres = fbi.info.mode->yres; if (pdata->bits_per_pixel) diff --git a/drivers/video/sdl.c b/drivers/video/sdl.c index 8dec5e5778..a56834004c 100644 --- a/drivers/video/sdl.c +++ b/drivers/video/sdl.c @@ -37,8 +37,8 @@ static int sdlfb_probe(struct device_d *dev) return -EIO; fb = xzalloc(sizeof(*fb)); - fb->mode_list = fb->mode = dev->platform_data; - fb->num_modes = 1; + fb->modes.modes = fb->mode = dev->platform_data; + fb->modes.num_modes = 1; fb->bits_per_pixel = 4 << 3; fb->xres = fb->mode->xres; fb->yres = fb->mode->yres; diff --git a/drivers/video/stm.c b/drivers/video/stm.c index fdeaf9c645..175e4b611d 100644 --- a/drivers/video/stm.c +++ b/drivers/video/stm.c @@ -499,9 +499,9 @@ static int stmfb_probe(struct device_d *hw_dev) clk_enable(fbi.clk); /* add runtime video info */ - fbi.info.mode_list = pdata->mode_list; - fbi.info.num_modes = pdata->mode_cnt; - fbi.info.mode = &fbi.info.mode_list[0]; + fbi.info.modes.modes = pdata->mode_list; + fbi.info.modes.num_modes = pdata->mode_cnt; + fbi.info.mode = &fbi.info.modes.modes[0]; fbi.info.xres = fbi.info.mode->xres; fbi.info.yres = fbi.info.mode->yres; if (pdata->bits_per_pixel) diff --git a/images/Makefile.imx b/images/Makefile.imx index 5b650de69b..06794fd379 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -82,6 +82,12 @@ CFG_start_imx6q_mba6x.pblx.imximg = $(board)/tqma6x/flash-header-tqma6q.imxcfg FILE_barebox-tq-tqma6q-mba6x.img = start_imx6q_mba6x.pblx.imximg image-$(CONFIG_MACH_TQMA6X) += barebox-tq-tqma6q-mba6x.img +pblx-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01_4gib +CFG_start_phytec_pbab01_4gib.pblx.imximg = $(board)/phytec-phyflex-imx6/flash-header-phytec-pfla02-4gib.imxcfg +imximage-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01_4gib.pblx.imximg +FILE_barebox-phytec-pbab01-4gib.img = start_phytec_pbab01_4gib.pblx.imximg +image-$(CONFIG_MACH_PHYTEC_PFLA02) += barebox-phytec-pbab01-4gib.img + pblx-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01_2gib CFG_start_phytec_pbab01_2gib.pblx.imximg = $(board)/phytec-phyflex-imx6/flash-header-phytec-pfla02-2gib.imxcfg FILE_barebox-phytec-pbab01-2gib.img = start_phytec_pbab01_2gib.pblx.imximg @@ -92,6 +98,18 @@ CFG_start_phytec_pbab01_1gib.pblx.imximg = $(board)/phytec-phyflex-imx6/flash-he FILE_barebox-phytec-pbab01-1gib.img = start_phytec_pbab01_1gib.pblx.imximg image-$(CONFIG_MACH_PHYTEC_PFLA02) += barebox-phytec-pbab01-1gib.img +pblx-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01dl_1gib +CFG_start_phytec_pbab01dl_1gib.pblx.imximg = $(board)/phytec-phyflex-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg +imximage-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01dl_1gib.pblx.imximg +FILE_barebox-phytec-pbab01dl-1gib.img = start_phytec_pbab01dl_1gib.pblx.imximg +image-$(CONFIG_MACH_PHYTEC_PFLA02) += barebox-phytec-pbab01dl-1gib.img + +pblx-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01s_512mb +CFG_start_phytec_pbab01s_512mb.pblx.imximg = $(board)/phytec-phyflex-imx6/flash-header-phytec-pfla02s-512mb.imxcfg +imximage-$(CONFIG_MACH_PHYTEC_PFLA02) += start_phytec_pbab01s_512mb.pblx.imximg +FILE_barebox-phytec-pbab01s-512mb.img = start_phytec_pbab01s_512mb.pblx.imximg +image-$(CONFIG_MACH_PHYTEC_PFLA02) += barebox-phytec-pbab01s-512mb.img + pblx-$(CONFIG_MACH_DFI_FS700_M60) += start_imx6dl_dfi_fs700_m60_6s CFG_start_imx6dl_dfi_fs700_m60_6s.pblx.imximg = $(board)/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg FILE_barebox-dfi-fs700-m60-6s.img = start_imx6dl_dfi_fs700_m60_6s.pblx.imximg @@ -143,3 +161,8 @@ pblx-$(CONFIG_MACH_UDOO) += start_imx6_udoo CFG_start_imx6_udoo.pblx.imximg = $(board)/udoo/flash-header-mx6-udoo.imxcfg FILE_barebox-udoo-imx6q.img = start_imx6_udoo.pblx.imximg image-$(CONFIG_MACH_UDOO) += barebox-udoo-imx6q.img + +pblx-$(CONFIG_MACH_VARISCITE_MX6) += start_variscite_custom +CFG_start_variscite_custom.pblx.imximg = $(board)/variscite-mx6/flash-header-variscite.imxcfg +FILE_barebox-variscite-custom.img = start_variscite_custom.pblx.imximg +image-$(CONFIG_MACH_VARISCITE_MX6) += barebox-variscite-custom.img diff --git a/include/blspec.h b/include/blspec.h index 66d2e8485d..afac5ed7ba 100644 --- a/include/blspec.h +++ b/include/blspec.h @@ -35,7 +35,6 @@ int blspec_boot_devicename(const char *devname, int verbose, int dryrun); int blspec_scan_devices(struct blspec *blspec); -struct blspec_entry *blspec_entry_default(struct blspec *l); int blspec_scan_devicename(struct blspec *blspec, const char *devname); int blspec_scan_directory(struct blspec *blspec, const char *root); @@ -91,4 +90,13 @@ static inline void blspec_free(struct blspec *blspec) free(blspec); } +#ifdef CONFIG_BLSPEC +struct blspec_entry *blspec_entry_default(struct blspec *l); +#else +static inline struct blspec_entry *blspec_entry_default(struct blspec *l) +{ + return NULL; +} +#endif + #endif /* __LOADER_H__ */ diff --git a/include/common.h b/include/common.h index 6987b4f16d..bfd3ce8b7b 100644 --- a/include/common.h +++ b/include/common.h @@ -165,6 +165,15 @@ void arch_shutdown(void); int run_shell(void); +#ifdef CONFIG_SHELL_HUSH +char *shell_expand(char *str); +#else +static inline char *shell_expand(char *str) +{ + return strdup(str); +} +#endif + /* Force a compilation error if condition is true */ #define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) diff --git a/include/dt-bindings/clock/ar933x-clk.h b/include/dt-bindings/clock/ar933x-clk.h new file mode 100644 index 0000000000..f048930726 --- /dev/null +++ b/include/dt-bindings/clock/ar933x-clk.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com> + * + * 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. + * + */ + +#ifndef __DT_BINDINGS_AR933X_CLK_H +#define __DT_BINDINGS_AR933X_CLK_H + +#define AR933X_CLK_REF 0 +#define AR933X_CLK_UART 1 +#define AR933X_CLK_CPU 2 +#define AR933X_CLK_DDR 3 +#define AR933X_CLK_AHB 4 +#define AR933X_CLK_WDT 5 + +#define AR933X_CLK_END 6 + +#endif /* __DT_BINDINGS_AR933X_CLK_H */ diff --git a/include/fb.h b/include/fb.h index 22fa9b130b..2db6ad6f37 100644 --- a/include/fb.h +++ b/include/fb.h @@ -4,6 +4,7 @@ #include <ioctl.h> #include <param.h> #include <driver.h> +#include <linux/bitops.h> #define FB_VISUAL_TRUECOLOR 2 /* True color */ #define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ @@ -32,6 +33,16 @@ #define PICOS2KHZ(a) (1000000000UL/(a)) #define KHZ2PICOS(a) (1000000000UL/(a)) +enum display_flags { + /* data enable flag */ + DISPLAY_FLAGS_DE_LOW = BIT(4), + DISPLAY_FLAGS_DE_HIGH = BIT(5), + /* drive data on pos. edge */ + DISPLAY_FLAGS_PIXDATA_POSEDGE = BIT(6), + /* drive data on neg. edge */ + DISPLAY_FLAGS_PIXDATA_NEGEDGE = BIT(7), +}; + struct fb_videomode { const char *name; /* optional */ u32 refresh; /* optional */ @@ -46,7 +57,7 @@ struct fb_videomode { u32 vsync_len; u32 sync; u32 vmode; - u32 flag; + u32 display_flags; }; /* Interpretation of offset for color fields: All offsets are from the right, @@ -77,10 +88,30 @@ struct fb_ops { int (*fb_activate_var)(struct fb_info *info); }; +/* + * This describes all timing settings a display provides. + * The native_mode is the default setting for this display. + * Drivers that can handle multiple videomodes should work with this struct and + * convert each entry to the desired end result. + */ +struct display_timings { + unsigned int native_mode; + + unsigned int num_modes; + struct fb_videomode *modes; +}; + +struct i2c_adapter; + struct fb_info { struct fb_videomode *mode; - struct fb_videomode *mode_list; - unsigned num_modes; + struct display_timings modes; + + int current_mode; + + void *edid_data; + struct i2c_adapter *edid_i2c_adapter; + struct display_timings edid_modes; struct fb_ops *fbops; struct device_d dev; /* This is this fb device */ @@ -111,6 +142,8 @@ struct fb_info { */ }; +struct display_timings *of_get_display_timings(struct device_node *np); + int register_framebuffer(struct fb_info *info); #define FBIOGET_SCREENINFO _IOR('F', 1, loff_t) @@ -123,5 +156,8 @@ extern struct bus_type fb_bus; int fb_register_simplefb(struct fb_info *info); -#endif /* __FB_H */ +int edid_to_display_timings(struct display_timings *, unsigned char *edid); +void *edid_read_i2c(struct i2c_adapter *adapter); +void fb_edid_add_modes(struct fb_info *info); +#endif /* __FB_H */ diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h index 81e5daa200..f89fefbb27 100644 --- a/include/i2c/i2c.h +++ b/include/i2c/i2c.h @@ -133,6 +133,7 @@ static inline int i2c_register_board_info(int busnum, #endif extern int i2c_add_numbered_adapter(struct i2c_adapter *adapter); struct i2c_adapter *i2c_get_adapter(int busnum); +struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node); /* For devices that use several addresses, use i2c_new_dummy() to make * client handles for the extra addresses. diff --git a/include/linux/clk.h b/include/linux/clk.h index af38c720e8..07b27cf148 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -196,6 +196,9 @@ static inline int clk_set_rate(struct clk *clk, unsigned long rate) #endif #ifdef CONFIG_COMMON_CLK + +#define CLK_SET_RATE_PARENT (1 << 0) /* propagate rate change up one level */ + struct clk_ops { int (*enable)(struct clk *clk); void (*disable)(struct clk *clk); @@ -237,36 +240,46 @@ struct clk_divider { const char *parent; #define CLK_DIVIDER_ONE_BASED (1 << 0) unsigned flags; + const struct clk_div_table *table; + int max_div_index; + int table_size; }; extern struct clk_ops clk_divider_ops; struct clk *clk_divider(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width); + void __iomem *reg, u8 shift, u8 width, unsigned flags); struct clk *clk_divider_one_based(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width); + void __iomem *reg, u8 shift, u8 width, unsigned flags); struct clk *clk_divider_table(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, - const struct clk_div_table *table); + const struct clk_div_table *table, unsigned flags); struct clk *clk_fixed_factor(const char *name, - const char *parent, unsigned int mult, unsigned int div); + const char *parent, unsigned int mult, unsigned int div, + unsigned flags); struct clk *clk_mux_alloc(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents); + u8 shift, u8 width, const char **parents, u8 num_parents, + unsigned flags); void clk_mux_free(struct clk *clk_mux); struct clk *clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents); + u8 shift, u8 width, const char **parents, u8 num_parents, + unsigned flags); struct clk *clk_gate_alloc(const char *name, const char *parent, - void __iomem *reg, u8 shift); + void __iomem *reg, u8 shift, unsigned flags); void clk_gate_free(struct clk *clk_gate); struct clk *clk_gate(const char *name, const char *parent, void __iomem *reg, - u8 shift); + u8 shift, unsigned flags); struct clk *clk_gate_inverted(const char *name, const char *parent, void __iomem *reg, - u8 shift); + u8 shift, unsigned flags); int clk_is_enabled(struct clk *clk); int clk_is_enabled_always(struct clk *clk); +long clk_parent_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate); +int clk_parent_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate); int clk_register(struct clk *clk); diff --git a/include/linux/const.h b/include/linux/const.h new file mode 100644 index 0000000000..c872bfd25e --- /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) */ diff --git a/include/linux/err.h b/include/linux/err.h index 19fb70dc08..ed563f2c4a 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -52,6 +52,14 @@ static inline void *ERR_CAST(const void *ptr) return (void *) ptr; } +static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) +{ + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + else + return 0; +} + #endif #endif /* _LINUX_ERR_H */ diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index 11d51e2744..c1ba55bd2d 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -9,6 +9,8 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS +#include <asm-generic/div64.h> + struct erase_info_user { uint32_t start; uint32_t length; @@ -73,7 +75,7 @@ enum { struct mtd_info_user { uint8_t type; uint32_t flags; - uint32_t size; // Total size of the MTD + uint64_t size; /* Total size of the MTD */ uint32_t erasesize; uint32_t writesize; uint32_t oobsize; // Amount of OOB data per block (e.g. 16) @@ -173,6 +175,14 @@ enum mtd_file_modes { MTD_MODE_RAW, }; + +static inline uint32_t mtd_user_div_by_eb(uint64_t sz, + struct mtd_info_user *mtd_user) +{ + do_div(sz, mtd_user->erasesize); + return sz; +} + #endif /* DOXYGEN_SHOULD_SKIP_THIS */ #endif /* __MTD_ABI_H__ */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index e02204a503..c63b514f44 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -86,7 +86,7 @@ struct mtd_oob_ops { struct mtd_info { u_char type; u_int32_t flags; - u_int32_t size; // Total size of the MTD + u_int64_t size; /* Total size of the MTD */ /* "Major" erase size for the device. Naïve users may take this * to be the only erase size available, or may use the more detailed @@ -219,7 +219,7 @@ struct mtd_info { int p_allow_erasebad; struct mtd_info *master; - uint32_t master_offset; + loff_t master_offset; }; int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); @@ -256,6 +256,13 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd) { return do_div(sz, mtd->erasesize); } + +static inline uint32_t mtd_div_by_wb(uint64_t sz, struct mtd_info *mtd) +{ + do_div(sz, mtd->writesize); + return sz; +} + /* Kernel-side ioctl definitions */ extern int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id); @@ -273,8 +280,8 @@ struct mtd_notifier { struct list_head list; }; -struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, - unsigned long flags, const char *name); +struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, + uint64_t size, unsigned long flags, const char *name); int mtd_del_partition(struct mtd_info *mtd); extern void register_mtd_user (struct mtd_notifier *new); diff --git a/include/menu.h b/include/menu.h index f63a405121..8b0ffb1f83 100644 --- a/include/menu.h +++ b/include/menu.h @@ -106,4 +106,6 @@ struct menu_entry* menu_entry_get_by_num(struct menu* m, int num); */ void menu_action_exit(struct menu *m, struct menu_entry *me); +int menutree(const char *path, int toplevel); + #endif /* __MENU_H__ */ diff --git a/include/mfd/imx6q-iomuxc-gpr.h b/include/mfd/imx6q-iomuxc-gpr.h index db43d5905c..24993ffe7e 100644 --- a/include/mfd/imx6q-iomuxc-gpr.h +++ b/include/mfd/imx6q-iomuxc-gpr.h @@ -103,15 +103,15 @@ #define IMX6Q_GPR1_EXC_MON_MASK BIT(22) #define IMX6Q_GPR1_EXC_MON_OKAY 0x0 #define IMX6Q_GPR1_EXC_MON_SLVE BIT(22) -#define IMX6Q_GPR1_MIPI_IPU2_SEL_MASK BIT(21) -#define IMX6Q_GPR1_MIPI_IPU2_SEL_GASKET 0x0 -#define IMX6Q_GPR1_MIPI_IPU2_SEL_IOMUX BIT(21) -#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK BIT(20) -#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET 0x0 -#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX BIT(20) -#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK BIT(19) +#define IMX6Q_GPR1_ENET_CLK_SEL_MASK BIT(21) +#define IMX6Q_GPR1_ENET_CLK_SEL_PAD 0 +#define IMX6Q_GPR1_ENET_CLK_SEL_ANATOP BIT(21) +#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK BIT(20) #define IMX6Q_GPR1_MIPI_IPU2_MUX_GASKET 0x0 -#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX BIT(19) +#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX BIT(20) +#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK BIT(19) +#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET 0x0 +#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX BIT(19) #define IMX6Q_GPR1_PCIE_TEST_PD BIT(18) #define IMX6Q_GPR1_IPU_VPU_MUX_MASK BIT(17) #define IMX6Q_GPR1_IPU_VPU_MUX_IPU1 0x0 @@ -241,6 +241,24 @@ #define IMX6Q_GPR5_L2_CLK_STOP BIT(8) +#define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0) +#define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4) +#define IMX6Q_GPR6_IPU1_ID10_WR_QOS_MASK (0xf << 8) +#define IMX6Q_GPR6_IPU1_ID11_WR_QOS_MASK (0xf << 12) +#define IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK (0xf << 16) +#define IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK (0xf << 20) +#define IMX6Q_GPR6_IPU1_ID10_RD_QOS_MASK (0xf << 24) +#define IMX6Q_GPR6_IPU1_ID11_RD_QOS_MASK (0xf << 28) + +#define IMX6Q_GPR7_IPU2_ID00_WR_QOS_MASK (0xf << 0) +#define IMX6Q_GPR7_IPU2_ID01_WR_QOS_MASK (0xf << 4) +#define IMX6Q_GPR7_IPU2_ID10_WR_QOS_MASK (0xf << 8) +#define IMX6Q_GPR7_IPU2_ID11_WR_QOS_MASK (0xf << 12) +#define IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK (0xf << 16) +#define IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK (0xf << 20) +#define IMX6Q_GPR7_IPU2_ID10_RD_QOS_MASK (0xf << 24) +#define IMX6Q_GPR7_IPU2_ID11_RD_QOS_MASK (0xf << 28) + #define IMX6Q_GPR9_TZASC2_BYP BIT(1) #define IMX6Q_GPR9_TZASC1_BYP BIT(0) diff --git a/include/param.h b/include/param.h index e8458b5b2d..eac3372f34 100644 --- a/include/param.h +++ b/include/param.h @@ -54,6 +54,11 @@ struct param_d *dev_add_param_ip(struct device_d *dev, const char *name, int (*get)(struct param_d *p, void *priv), IPaddr_t *ip, void *priv); +struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + u8 *mac, void *priv); + int dev_add_param_fixed(struct device_d *dev, char *name, const char *value); void dev_remove_param(struct param_d *p); @@ -126,6 +131,14 @@ static inline struct param_d *dev_add_param_ip(struct device_d *dev, const char return NULL; } +static inline struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + u8 *mac, void *priv) +{ + return NULL; +} + static inline int dev_add_param_fixed(struct device_d *dev, char *name, char *value) { return 0; diff --git a/include/video/fourcc.h b/include/video/fourcc.h new file mode 100644 index 0000000000..322142c1ba --- /dev/null +++ b/include/video/fourcc.h @@ -0,0 +1,261 @@ +#ifndef __VIDEO_FOURCC_H +#define __VIDEO_FOURCC_H + +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a, b, c, d)\ + ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) + +/* Pixel format FOURCC depth Description */ + +/* RGB formats */ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ +#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ + +/* Grey formats */ +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ +#define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ +#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ +#define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ +#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ + +/* Grey bit-packed formats */ +#define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ + +/* Palette formats */ +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ + +/* Chrominance formats */ +#define V4L2_PIX_FMT_UV8 v4l2_fourcc('U', 'V', '8', ' ') /* 8 UV 4:4 */ + +/* Luminance+Chrominance formats */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ +#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ +#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ +#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ +#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ +#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ + +/* two non contiguous planes - one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ +#define V4L2_PIX_FMT_NV16M v4l2_fourcc('N', 'M', '1', '6') /* 16 Y/CbCr 4:2:2 */ +#define V4L2_PIX_FMT_NV61M v4l2_fourcc('N', 'M', '6', '1') /* 16 Y/CrCb 4:2:2 */ +#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ + +/* three non contiguous planes - Y, Cb, Cr */ +#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ +#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12 YVU420 planar */ + +/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ +#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ +#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ +#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ + /* 10bit raw bayer a-law compressed to 8 bits */ +#define V4L2_PIX_FMT_SBGGR10ALAW8 v4l2_fourcc('a', 'B', 'A', '8') +#define V4L2_PIX_FMT_SGBRG10ALAW8 v4l2_fourcc('a', 'G', 'A', '8') +#define V4L2_PIX_FMT_SGRBG10ALAW8 v4l2_fourcc('a', 'g', 'A', '8') +#define V4L2_PIX_FMT_SRGGB10ALAW8 v4l2_fourcc('a', 'R', 'A', '8') + /* 10bit raw bayer DPCM compressed to 8 bits */ +#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8') +#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8') +#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') +#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8') + /* + * 10bit raw bayer, expanded to 16 bits + * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... + */ +#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ + +/* compressed formats */ +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ +#define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ +#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ +#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ +#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ +#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */ +#define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ +#define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ +#define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ +#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */ +#define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ +#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ +#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ +#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */ + +/* Vendor-specific formats */ +#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */ +#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */ +#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */ +#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */ +#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */ +#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */ +#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */ +#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */ +#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ +#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ +#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ +#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ +#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */ +#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ +#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ +#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ +#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */ +#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ +#define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */ +#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */ +#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ +#define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ +#define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ +#define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ +#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ + +#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ + ((__u32)(c) << 16) | ((__u32)(d) << 24)) + +#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ + +/* color index */ +#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ + +/* 8 bpp RGB */ +#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ +#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ + +/* 16 bpp RGB */ +#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */ + +#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */ + +#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */ + +#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */ + +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ +#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */ + +/* 24 bpp RGB */ +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */ +#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */ + +/* 32 bpp RGB */ +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */ + +#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ + +#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */ + +#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ + +/* packed YCbCr */ +#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ +#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ + +#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ + +/* + * 2 plane YCbCr + * index 0 = Y plane, [7:0] Y + * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian + * or + * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian + */ +#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ + +/* special NV12 tiled format */ +#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */ + +/* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + * index 1: Cb plane, [7:0] Cb + * index 2: Cr plane, [7:0] Cr + * or + * index 1: Cr plane, [7:0] Cr + * index 2: Cb plane, [7:0] Cb + */ +#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ + +#endif /* __VIDEO_FOURCC_H */ diff --git a/lib/libmtd.c b/lib/libmtd.c index 1606b872fd..56672bd951 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -195,7 +195,7 @@ int libmtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, void *buf, int len) { int ret, rd = 0; - off_t seek; + loff_t seek; ret = mtd_valid_erase_block(mtd, eb); if (ret) @@ -209,7 +209,7 @@ int libmtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, } /* Seek to the beginning of the eraseblock */ - seek = (off_t)eb * mtd->eb_size + offs; + seek = (loff_t)eb * mtd->eb_size + offs; if (lseek(fd, seek, SEEK_SET) != seek) return sys_errmsg("cannot seek %s to offset %llu", mtd->node, (unsigned long long)seek); @@ -229,7 +229,7 @@ int libmtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, void *buf, int len) { int ret; - off_t seek; + loff_t seek; ret = mtd_valid_erase_block(mtd, eb); if (ret) @@ -255,7 +255,7 @@ int libmtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, } /* Seek to the beginning of the eraseblock */ - seek = (off_t)eb * mtd->eb_size + offs; + seek = (loff_t)eb * mtd->eb_size + offs; if (lseek(fd, seek, SEEK_SET) != seek) return sys_errmsg("cannot seek %s to offset %llu", mtd->node, (unsigned long long)seek); @@ -326,7 +326,7 @@ int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd) goto out_close; } - mtd->eb_cnt = ui.size / ui.erasesize; + mtd->eb_cnt = mtd_user_div_by_eb(ui.size, &ui); switch(mtd->type) { case MTD_ABSENT: diff --git a/lib/parameter.c b/lib/parameter.c index 9dfde3f698..baa2b156c0 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -542,6 +542,93 @@ struct param_d *dev_add_param_ip(struct device_d *dev, const char *name, return &pi->param; } + +struct param_mac { + struct param_d param; + char *mac; + u8 mac_str[sizeof("xx:xx:xx:xx:xx:xx")]; + const char *format; + int (*set)(struct param_d *p, void *priv); + int (*get)(struct param_d *p, void *priv); +}; + +int string_to_ethaddr(const char *str, u8 enetaddr[6]); +void ethaddr_to_string(const u8 enetaddr[6], char *str); + +static inline struct param_mac *to_param_mac(struct param_d *p) +{ + return container_of(p, struct param_mac, param); +} + +static int param_mac_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_mac *pm = to_param_mac(p); + char mac_save[6]; + int ret; + + if (!val) + return -EINVAL; + + memcpy(mac_save, pm->mac, 6); + + ret = string_to_ethaddr(val, pm->mac); + if (ret) + goto out; + + if (!pm->set) + return 0; + + ret = pm->set(p, p->driver_priv); + if (ret) + goto out; + + return 0; +out: + memcpy(pm->mac, mac_save, 6); + + return ret; +} + +static const char *param_mac_get(struct device_d *dev, struct param_d *p) +{ + struct param_mac *pm = to_param_mac(p); + int ret; + + if (pm->get) { + ret = pm->get(p, p->driver_priv); + if (ret) + return NULL; + } + + ethaddr_to_string(pm->mac, p->value); + + return p->value; +} + +struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + u8 *mac, void *priv) +{ + struct param_mac *pm; + int ret; + + pm = xzalloc(sizeof(*pm)); + pm->mac = mac; + pm->set = set; + pm->get = get; + pm->param.driver_priv = priv; + pm->param.value = pm->mac_str; + + ret = __dev_add_param(&pm->param, dev, name, + param_mac_set, param_mac_get, 0); + if (ret) { + free(pm); + return ERR_PTR(ret); + } + + return &pm->param; +} #endif /** diff --git a/lib/string.c b/lib/string.c index ceced7f48e..6a39eb5ced 100644 --- a/lib/string.c +++ b/lib/string.c @@ -16,7 +16,7 @@ */ #include <linux/types.h> -#include <linux/string.h> +#include <string.h> #include <linux/ctype.h> #include <malloc.h> @@ -257,17 +257,9 @@ int eth_rx(void) return eth_current->recv(eth_current); } -static int eth_set_ethaddr(struct device_d *dev, struct param_d *param, const char *val) +static int eth_set_ethaddr(struct param_d *param, void *priv) { - struct eth_device *edev = dev_to_edev(dev); - - if (!val) - return dev_param_set_generic(dev, param, NULL); - - if (string_to_ethaddr(val, edev->ethaddr) < 0) - return -EINVAL; - - dev_param_set_generic(dev, param, val); + struct eth_device *edev = priv; edev->set_ethaddr(edev, edev->ethaddr); @@ -345,7 +337,7 @@ int eth_register(struct eth_device *edev) dev_add_param_ip(dev, "serverip", NULL, NULL, &edev->serverip, edev); dev_add_param_ip(dev, "gateway", NULL, NULL, &edev->gateway, edev); dev_add_param_ip(dev, "netmask", NULL, NULL, &edev->netmask, edev); - dev_add_param(dev, "ethaddr", eth_set_ethaddr, NULL, 0); + dev_add_param_mac(dev, "ethaddr", eth_set_ethaddr, NULL, edev->ethaddr, edev); if (edev->init) edev->init(edev); diff --git a/net/netconsole.c b/net/netconsole.c index 2ab19de4d5..86a68e19d9 100644 --- a/net/netconsole.c +++ b/net/netconsole.c @@ -81,6 +81,9 @@ static int nc_getc(struct console_device *cdev) struct nc_priv, cdev); unsigned char c; + if (!priv->con) + return 0; + while (!kfifo_len(priv->fifo)) net_poll(); @@ -94,6 +97,9 @@ static int nc_tstc(struct console_device *cdev) struct nc_priv *priv = container_of(cdev, struct nc_priv, cdev); + if (!priv->con) + return 0; + if (priv->busy) return kfifo_len(priv->fifo) ? 1 : 0; diff --git a/scripts/omap4_usbboot/omap4_usbboot.c b/scripts/omap4_usbboot/omap4_usbboot.c index e52108614b..0e5abcb159 100644 --- a/scripts/omap4_usbboot/omap4_usbboot.c +++ b/scripts/omap4_usbboot/omap4_usbboot.c @@ -35,16 +35,17 @@ #define WHITE 8 #define RED 1 #define BLACK 0 -#define FORMAT "%c[%d;%d;%dm" -#define TARGET_FORMAT 0x1B, BRIGHT, RED+30, BLACK+40 -#define HOST_FORMAT 0x1B, RESET, WHITE+30, BLACK+40 -#define host_print(fmt, arg...) printf(FORMAT fmt FORMAT, \ +#define TFORMAT "%c[%d;%dm" +#define HFORMAT "%c[%dm" +#define TARGET_FORMAT 0x1B, BRIGHT, RED+30 +#define HOST_FORMAT 0x1B, RESET +#define host_print(fmt, arg...) printf(HFORMAT fmt TFORMAT, \ HOST_FORMAT, ##arg, TARGET_FORMAT) void panic(struct termios *t_restore) { tcsetattr(STDIN_FILENO, TCSANOW, t_restore); - printf(FORMAT, HOST_FORMAT); + printf(HFORMAT, HOST_FORMAT); exit(1); } @@ -354,7 +355,7 @@ int usb_boot( tcgetattr(STDIN_FILENO, &vars.t_restore); tn = vars.t_restore; tn.c_lflag &= ~(ICANON | ECHO); - printf(FORMAT, TARGET_FORMAT); + printf(TFORMAT, TARGET_FORMAT); tcsetattr(STDIN_FILENO, TCSANOW, &tn); if (pthread_create(&thread, NULL, listenerTask, &vars)) host_print("listenerTask failed\n"); @@ -375,7 +376,7 @@ int usb_boot( usb_close(usb); pthread_mutex_destroy(&vars.usb_mutex); tcsetattr(STDIN_FILENO, TCSANOW, &vars.t_restore); - printf(FORMAT, HOST_FORMAT); + printf(HFORMAT, HOST_FORMAT); return 0; } @@ -415,7 +416,7 @@ int main(int argc, char **argv) sz = s.st_size; close(fd); argv++; - printf(FORMAT, HOST_FORMAT); + printf(HFORMAT, HOST_FORMAT); for (once = 1;;) { usb = usb_open(match_omap4_bootloader); if (usb) |