diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-04-18 15:16:23 -0400 |
---|---|---|
committer | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-04-18 15:16:23 -0400 |
commit | 2a7f487cf26649ab3e9a8d8b366325fedc63c231 (patch) | |
tree | e0bb1e30c3fda79b5b542c8d62876e8d1caa5b5a | |
parent | 4fcd294d4a6e156cccd077f24c6a255298df0fd8 (diff) | |
parent | c54d751aad27da1e9dabdea706dd627379a0a7be (diff) | |
download | linux-linaro-android-testing.tar.gz |
Merge remote-tracking branch 'agreen/for-nicolas' into linaro-2.6.38testing
41 files changed, 2070 insertions, 706 deletions
diff --git a/arch/arm/configs/omap4_defconfig b/arch/arm/configs/omap4_defconfig new file mode 100644 index 00000000000..1a0e375af71 --- /dev/null +++ b/arch/arm/configs/omap4_defconfig @@ -0,0 +1,315 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_PERF_COUNTERS=y +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_OMAP=y +CONFIG_OMAP_SMARTREFLEX=y +CONFIG_OMAP_SMARTREFLEX_CLASS3=y +CONFIG_OMAP_MUX_DEBUG=y +CONFIG_OMAP_MBOX_FWK=y +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_MACH_OMAP3_BEAGLE is not set +# CONFIG_MACH_DEVKIT8000 is not set +# CONFIG_MACH_OMAP_LDP is not set +# CONFIG_MACH_OMAP3530_LV_SOM is not set +# CONFIG_MACH_OMAP3_TORPEDO is not set +# CONFIG_MACH_OVERO is not set +# CONFIG_MACH_OMAP3EVM is not set +# CONFIG_MACH_OMAP3517EVM is not set +# CONFIG_MACH_OMAP3_PANDORA is not set +# CONFIG_MACH_OMAP3_TOUCHBOOK is not set +# CONFIG_MACH_OMAP_3430SDP is not set +# CONFIG_MACH_NOKIA_RM680 is not set +# CONFIG_MACH_NOKIA_RX51 is not set +# CONFIG_MACH_OMAP_ZOOM2 is not set +# CONFIG_MACH_OMAP_ZOOM3 is not set +# CONFIG_MACH_CM_T35 is not set +# CONFIG_MACH_CM_T3517 is not set +# CONFIG_MACH_IGEP0020 is not set +# CONFIG_MACH_IGEP0030 is not set +# CONFIG_MACH_SBC3530 is not set +# CONFIG_MACH_OMAP_3630SDP is not set +CONFIG_ARM_THUMBEE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_HIGHMEM=y +CONFIG_LEDS=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200" +CONFIG_KEXEC=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEBUG=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_FPE_NWFPE=y +CONFIG_BINFMT_MISC=y +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_CFG80211=y +CONFIG_CFG80211_REG_DEBUG=y +CONFIG_CFG80211_DEBUGFS=y +CONFIG_LIB80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_DEBUG_MENU=y +CONFIG_MAC80211_VERBOSE_DEBUG=y +CONFIG_RFKILL=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_OOPS=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_OMAP2=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_MISC_DEVICES=y +CONFIG_TI_ST=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_MD=y +CONFIG_NETDEVICES=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMC91X=y +CONFIG_SMSC911X=y +CONFIG_KS8851=y +CONFIG_KS8851_MLL=y +# CONFIG_NETDEV_10000 is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_DEBUG=y +CONFIG_WL12XX_MENU=m +CONFIG_WL12XX=m +CONFIG_WL12XX_HT=y +CONFIG_WL12XX_SDIO=m +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_OMAP4=y +CONFIG_KEYBOARD_TWL4030=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_TWL4030_PWRBUTTON=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_HW_RANDOM=y +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_OMAP24XX=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_TWL4030=y +CONFIG_W1=y +CONFIG_POWER_SUPPLY=y +CONFIG_WATCHDOG=y +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL4030_WATCHDOG=y +CONFIG_REGULATOR_DUMMY=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_TPS65023=y +CONFIG_REGULATOR_TPS6507X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_MEDIA_TUNER_SIMPLE is not set +# CONFIG_MEDIA_TUNER_TDA8290 is not set +# CONFIG_MEDIA_TUNER_TDA827X is not set +# CONFIG_MEDIA_TUNER_TDA18271 is not set +# CONFIG_MEDIA_TUNER_TDA9887 is not set +# CONFIG_MEDIA_TUNER_TEA5761 is not set +CONFIG_VIDEO_OMAP2_VOUT=y +CONFIG_RADIO_WL1273=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +CONFIG_OMAP2_VRAM_SIZE=32 +CONFIG_OMAP2_DSS_DSI=y +CONFIG_OMAP2_DSS_FAKE_VSYNC=y +CONFIG_FB_OMAP2=y +CONFIG_FB_OMAP2_NUM_FBS=2 +CONFIG_PANEL_GENERIC_DPI=y +CONFIG_PANEL_TAAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_DISPLAY_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +CONFIG_SND_DEBUG_VERBOSE=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_SDP4430=y +CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_OMAP2PLUS=y +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_TEST=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_ZERO=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_TWL4030_USB=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_SDIO_UART=y +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TWL4030=y +CONFIG_STAGING=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +CONFIG_HWSPINLOCK=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_UBIFS_FS=y +CONFIG_CRAMFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_SECURITY=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC_CCITT=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 56702c5e577..7e4bc49505d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -311,11 +311,17 @@ static struct platform_device sdp4430_lcd_device = { .id = -1, }; +static struct platform_device sdp4430_hdmi_audio_device = { + .name = "hdmi-audio-dai", + .id = -1, +}; + static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, &sdp4430_leds_pwm, + &sdp4430_hdmi_audio_device, }; static struct omap_lcd_config sdp4430_lcd_config __initdata = { diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 920b7ba1c45..a0c7ba847df 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -57,16 +57,6 @@ #define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ -/* wl127x BT, FM, GPS connectivity chip */ -static int wl1271_gpios[] = {46, -1, -1}; -static struct platform_device wl1271_device = { - .name = "kim", - .id = -1, - .dev = { - .platform_data = &wl1271_gpios, - }, -}; - static struct gpio_led gpio_leds[] = { { .name = "pandaboard::status1", @@ -93,11 +83,60 @@ static struct platform_device leds_gpio = { }, }; +static struct platform_device omap4panda_hdmi_audio_device = { + .name = "hdmi-audio-dai", + .id = -1, +}; + static struct platform_device *panda_devices[] __initdata = { &leds_gpio, - &wl1271_device, + &omap4panda_hdmi_audio_device, +}; + +/* Display DVI */ +#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0 + +static int panda_enable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 1); + return 0; +} + +static void panda_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 0); +} + +/* Using generic display panel */ +static struct panel_generic_dpi_data dvi_panel = { + .name = "generic", + .platform_enable = panda_enable_dvi, + .platform_disable = panda_disable_dvi, +}; + +struct omap_dss_device panda_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "generic_dpi_panel", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, + .reset_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO, + .channel = OMAP_DSS_CHANNEL_LCD2, }; +int __init panda_dvi_init(void) +{ + int r; + + /* Requesting TFP410 DVI GPIO and disabling it, at bootup */ + r = gpio_request_one(panda_dvi_device.reset_gpio, + GPIOF_OUT_INIT_LOW, "DVI PD"); + if (r) + pr_err("Failed to get DVI powerdown GPIO\n"); + + return r; +} + static void __init omap4_panda_init_early(void) { omap2_init_common_infrastructure(); @@ -522,6 +561,19 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), /* dispc2_data0 */ OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* WLAN IRQ - GPIO 53 */ + OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + /* WLAN POWER ENABLE - GPIO 43 */ + OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT), + /* WLAN SDIO: MMC5 CMD */ + OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC5 CLK */ + OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC5 DAT[0-3] */ + OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), { .reg_offset = OMAP_MUX_TERMINATOR }, }; @@ -696,13 +748,15 @@ static struct omap_dss_device omap4_panda_hdmi_device = { static struct omap_dss_device *omap4_panda_dss_devices[] = { &omap4_panda_dvi_device, +#ifdef CONFIG_OMAP4_DSS_HDMI &omap4_panda_hdmi_device, +#endif }; static struct omap_dss_board_info omap4_panda_dss_data = { .num_devices = ARRAY_SIZE(omap4_panda_dss_devices), .devices = omap4_panda_dss_devices, - .default_device = &omap4_panda_dvi_device, + .default_device = &omap4_panda_hdmi_device, }; void omap4_panda_display_init(void) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index cbd6b3550ff..03b5b783457 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -30,6 +30,7 @@ #include <mach/gpio.h> #include <plat/mmc.h> #include <plat/dma.h> +#include <plat/gpu.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> #include <plat/omap4-keypad.h> @@ -735,6 +736,63 @@ static void omap_init_vout(void) static inline void omap_init_vout(void) {} #endif +static struct omap_device_pm_latency omap_gpu_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static struct platform_device omap_omaplfb_device = { + .name = "omaplfb", + .id = -1, +}; + + +static void omap_init_gpu(void) +{ + struct omap_hwmod *oh; + struct omap_device *od; + int max_omap_gpu_hwmod_name_len = 16; + char oh_name[max_omap_gpu_hwmod_name_len]; + int l; + struct gpu_platform_data *pdata; + char *name = "pvrsrvkm"; + + l = snprintf(oh_name, max_omap_gpu_hwmod_name_len, + "gpu"); + WARN(l >= max_omap_gpu_hwmod_name_len, + "String buffer overflow in GPU device setup\n"); + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + + pr_err("omap_init_gpu: Could not look up %s\n", oh_name); + return; + } + + pdata = kzalloc(sizeof(struct gpu_platform_data), + GFP_KERNEL); + if (!pdata) { + pr_err("omap_init_gpu: Platform data memory allocation failed\n"); + return; + } + + pdata->device_enable = omap_device_enable; + pdata->device_idle = omap_device_idle; + pdata->device_shutdown = omap_device_shutdown; + + od = omap_device_build(name, 0, oh, pdata, + sizeof(struct gpu_platform_data), + omap_gpu_latency, ARRAY_SIZE(omap_gpu_latency), 0); + WARN(IS_ERR(od), "Could not build omap_device for %s %s\n", + name, oh_name); + + kfree(pdata); + platform_device_register(&omap_omaplfb_device); +} + /*-------------------------------------------------------------------------*/ static int __init omap2_init_devices(void) @@ -753,6 +811,7 @@ static int __init omap2_init_devices(void) omap_init_sham(); omap_init_aes(); omap_init_vout(); + omap_init_gpu(); return 0; } diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index e46b430c701..8887a5e69b8 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -141,14 +141,14 @@ static void __init omap24xx_check_revision(void) dev_type = (prod_id >> 16) & 0x0f; omap_get_die_id(&odi); - pr_debug("OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n", + pr_info("OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n", idcode, rev, hawkeye, (idcode >> 1) & 0x7ff); - pr_debug("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0); - pr_debug("OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n", + pr_info("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0); + pr_info("OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n", odi.id_1, (odi.id_1 >> 28) & 0xf); - pr_debug("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2); - pr_debug("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3); - pr_debug("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n", + pr_info("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2); + pr_info("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3); + pr_info("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n", prod_id, dev_type); /* Check hawkeye ids */ @@ -333,6 +333,14 @@ static void __init omap4_check_revision(void) u32 idcode; u16 hawkeye; u8 rev; + struct omap_die_id odi; + + omap_get_die_id(&odi); + + pr_info("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0); + pr_info("OMAP_TAP_DIE_ID_1: 0x%08x\n", odi.id_1); + pr_info("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2); + pr_info("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3); /* * The IC rev detection is done with hawkeye and rev. diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index ab738789f65..4edb3ecb219 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -22,6 +22,7 @@ #include <plat/dmtimer.h> #include <plat/l3_2xxx.h> #include <plat/l4_2xxx.h> +#include <plat/mmc.h> #include "omap_hwmod_common_data.h" @@ -54,6 +55,7 @@ static struct omap_hwmod omap2420_gpio4_hwmod; static struct omap_hwmod omap2420_dma_system_hwmod; static struct omap_hwmod omap2420_mcspi1_hwmod; static struct omap_hwmod omap2420_mcspi2_hwmod; +static struct omap_hwmod omap2420_mmc_hwmod; /* L3 -> L4_CORE interface */ static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = { @@ -156,6 +158,24 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* L4 CORE -> MMC interface */ +static struct omap_hwmod_addr_space omap2420_mmc_addr_space[] = { + { + .pa_start = 0x4809c000, + .pa_end = 0x4809c07f, + .flags = ADDR_TYPE_RT, + }, +}; + +static struct omap_hwmod_ocp_if omap2420_l4_core__mmc = { + .master = &omap2420_l4_core_hwmod, + .slave = &omap2420_mmc_hwmod, + .clk = "mmc_ick", + .addr = omap2420_mmc_addr_space, + .addr_cnt = ARRAY_SIZE(omap2420_mmc_addr_space), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* L4 CORE -> UART1 interface */ static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = { { @@ -257,6 +277,7 @@ static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = { /* Master interfaces on the L4_CORE interconnect */ static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = { &omap2420_l4_core__l4_wkup, + &omap2420_l4_core__mmc, &omap2_l4_core__uart1, &omap2_l4_core__uart2, &omap2_l4_core__uart3, @@ -1919,6 +1940,17 @@ static struct omap_hwmod_class_sysconfig omap2420_mcspi_sysc = { .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +/* MMC/SD/SDIO common */ + +static struct omap_hwmod_class_sysconfig mmc_sysc = { + .rev_offs = 0x3c, + .sysc_offs = 0x64, + .syss_offs = 0x68, + .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -2139,6 +2171,54 @@ static struct omap_hwmod omap2420_mcbsp2_hwmod = { }, .slaves = omap2420_mcbsp2_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_mcbsp2_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + + +static struct omap_hwmod_class mmc_class = { + .name = "mmc", + .sysc = &mmc_sysc, +}; + +/* MMC/SD/SDIO1 */ + +static struct mmc_dev_attr mmc_dev_attr = { + .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, +}; + +static struct omap_hwmod_irq_info mmc_mpu_irqs[] = { + { .irq = 83 }, +}; + +static struct omap_hwmod_dma_info mmc_sdma_reqs[] = { + { .name = "tx", .dma_req = 61 }, /* DMA_MMC_TX */ + { .name = "rx", .dma_req = 62 }, /* DMA_MMC_RX */ +}; + +static struct omap_hwmod_ocp_if *omap2420_mmc_slaves[] = { + &omap2420_l4_core__mmc, +}; + +static struct omap_hwmod omap2420_mmc_hwmod = { + .name = "mmc_hwmod", + .mpu_irqs = mmc_mpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(mmc_mpu_irqs), + .sdma_reqs = mmc_sdma_reqs, + .sdma_reqs_cnt = ARRAY_SIZE(mmc_sdma_reqs), + .main_clk = "mmc_fck", + .prcm = { + .omap2 = { + .module_offs = CORE_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP2420_EN_MMC_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP2420_ST_MMC_SHIFT, + }, + }, + .slaves = omap2420_mmc_slaves, + .slaves_cnt = ARRAY_SIZE(omap2420_mmc_slaves), + .class = &mmc_class, + .dev_attr = &mmc_dev_attr, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -2163,6 +2243,7 @@ static __initdata struct omap_hwmod *omap2420_hwmods[] = { &omap2420_timer12_hwmod, &omap2420_wd_timer2_hwmod, + &omap2420_mmc_hwmod, &omap2420_uart1_hwmod, &omap2420_uart2_hwmod, &omap2420_uart3_hwmod, diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index c5b67207e3e..750ae607197 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -53,6 +53,7 @@ static struct omap_hwmod omap44xx_emif_fw_hwmod; static struct omap_hwmod omap44xx_hsi_hwmod; static struct omap_hwmod omap44xx_ipu_hwmod; static struct omap_hwmod omap44xx_iss_hwmod; +static struct omap_hwmod omap44xx_gpu_hwmod; static struct omap_hwmod omap44xx_iva_hwmod; static struct omap_hwmod omap44xx_l3_instr_hwmod; static struct omap_hwmod omap44xx_l3_main_1_hwmod; @@ -322,14 +323,21 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = { /* hsi -> l3_main_2 */ static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = { .master = &omap44xx_hsi_hwmod, + .slave = &omap44xx_l3_main_2_hwmod, + .clk = "l3_div_ck", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; +/* gpu -> l3_main_2 */ +static struct omap_hwmod_ocp_if omap44xx_gpu__l3_main_2 = { + .master = &omap44xx_gpu_hwmod, .slave = &omap44xx_l3_main_2_hwmod, .clk = "l3_div_ck", .user = OCP_USER_MPU | OCP_USER_SDMA, }; -/* ipu -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = { - .master = &omap44xx_ipu_hwmod, +/* iva -> l3_main_2 */ +static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = { + .master = &omap44xx_iva_hwmod, .slave = &omap44xx_l3_main_2_hwmod, .clk = "l3_div_ck", .user = OCP_USER_MPU | OCP_USER_SDMA, @@ -343,9 +351,9 @@ static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; -/* iva -> l3_main_2 */ -static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = { - .master = &omap44xx_iva_hwmod, +/* ipu -> l3_main_2 */ +static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = { + .master = &omap44xx_ipu_hwmod, .slave = &omap44xx_l3_main_2_hwmod, .clk = "l3_div_ck", .user = OCP_USER_MPU | OCP_USER_SDMA, @@ -393,6 +401,7 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = { &omap44xx_iss__l3_main_2, &omap44xx_iva__l3_main_2, &omap44xx_l3_main_1__l3_main_2, + &omap44xx_gpu__l3_main_2, &omap44xx_l4_cfg__l3_main_2, &omap44xx_usb_otg_hs__l3_main_2, }; @@ -630,7 +639,6 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { * elm * emif1 * emif2 - * fdif * gpmc * gpu * hdq1w @@ -2070,6 +2078,43 @@ static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = { { .pa_start = 0x4a058000, .pa_end = 0x4a05bfff, + .flags = ADDR_TYPE_RT + } +}; + +/* + * 'gpu' class + * 2d/3d graphics accelerator + */ + +static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = { + .rev_offs = 0xfe00, + .sysc_offs = 0xfe10, + .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class omap44xx_gpu_hwmod_class = { + .name = "gpu", + .sysc = &omap44xx_gpu_sysc, +}; + +/* gpu */ +static struct omap_hwmod_irq_info omap44xx_gpu_irqs[] = { + { .irq = 21 + OMAP44XX_IRQ_GIC_START }, +}; + +/* gpu master ports */ +static struct omap_hwmod_ocp_if *omap44xx_gpu_masters[] = { + &omap44xx_gpu__l3_main_2, +}; + +static struct omap_hwmod_addr_space omap44xx_gpu_addrs[] = { + { + .pa_start = 0x56000000, + .pa_end = 0x5600ffff, .flags = ADDR_TYPE_RT }, }; @@ -2104,6 +2149,41 @@ static struct omap_hwmod omap44xx_hsi_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_hsi_slaves), .masters = omap44xx_hsi_masters, .masters_cnt = ARRAY_SIZE(omap44xx_hsi_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + + +/* l3_main_2 -> gpu */ +static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpu = { + .master = &omap44xx_l3_main_2_hwmod, + .slave = &omap44xx_gpu_hwmod, + .clk = "l3_div_ck", + .addr = omap44xx_gpu_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_gpu_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* gpu slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_gpu_slaves[] = { + &omap44xx_l3_main_2__gpu, +}; + +static struct omap_hwmod omap44xx_gpu_hwmod = { + .name = "gpu", + .class = &omap44xx_gpu_hwmod_class, + .mpu_irqs = omap44xx_gpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_gpu_irqs), + .main_clk = "gpu_fck", + .vdd_name = "core", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_GFX_GFX_CLKCTRL, + }, + }, + .slaves = omap44xx_gpu_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_gpu_slaves), + .masters = omap44xx_gpu_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_gpu_masters), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), }; @@ -5100,6 +5180,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { /* hsi class */ /* &omap44xx_hsi_hwmod, */ + /* gpu class */ + &omap44xx_gpu_hwmod, + /* i2c class */ &omap44xx_i2c1_hwmod, &omap44xx_i2c2_hwmod, diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 283f4552d1d..87a0eed3118 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -72,7 +72,7 @@ config OMAP_SMARTREFLEX_CLASS3 config OMAP_RESET_CLOCKS bool "Reset unused clocks during boot" - depends on ARCH_OMAP + depends on ARCH_OMAP && BROKEN help Say Y if you want to reset unused clocks during boot. This option saves power, but assumes all drivers are diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 7d9f815cede..aa1f677a7c5 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/memblock.h> +#include <linux/err.h> #include <mach/hardware.h> #include <asm/mach-types.h> diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 5e04ddc18fa..2cba3d38888 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/device.h> +#include <linux/notifier.h> #include <linux/platform_device.h> #include <asm/atomic.h> @@ -459,6 +460,7 @@ struct omap_dss_device { struct omap_overlay_manager *manager; enum omap_dss_display_state state; + struct blocking_notifier_head notifier; /* platform specific */ int (*platform_enable)(struct omap_dss_device *dssdev); @@ -532,6 +534,18 @@ struct omap_dss_device *omap_dss_find_device(void *data, int omap_dss_start_device(struct omap_dss_device *dssdev); void omap_dss_stop_device(struct omap_dss_device *dssdev); +/* the event id of the event that occurred is passed in as the second arg + * to the notifier function, and the dssdev is passed as the third. + */ +enum omap_dss_event { + OMAP_DSS_SIZE_CHANGE + /* possibly add additional events, like hot-plug connect/disconnect */ +}; + +void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt); +void omap_dss_add_notify(struct omap_dss_device *dssdev, struct notifier_block *nb); +void omap_dss_remove_notify(struct omap_dss_device *dssdev, struct notifier_block *nb); + int omap_dss_get_num_overlay_managers(void); struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); diff --git a/arch/arm/plat-omap/include/plat/gpu.h b/arch/arm/plat-omap/include/plat/gpu.h new file mode 100644 index 00000000000..70dcc922bcb --- /dev/null +++ b/arch/arm/plat-omap/include/plat/gpu.h @@ -0,0 +1,33 @@ +/* + * arch/arm/plat-omap/include/plat/gpu.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMAP_GPU_H +#define OMAP_GPU_H + +#include <plat/omap-pm.h> +#include <linux/platform_device.h> + +struct gpu_platform_data { + void (*set_min_bus_tput)(struct device *dev, u8 agent_id, + unsigned long r); + int (*device_enable) (struct platform_device *pdev); + int (*device_shutdown) (struct platform_device *pdev); + int (*device_idle) (struct platform_device *pdev); +}; + +#endif diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index f38fef9f131..cc0ad22d72b 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -31,6 +31,7 @@ #define OMAP_MMC_MAX_SLOTS 2 +/* omap_hwmod integration data */ #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(1) struct omap_mmc_dev_attr { diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h index b127a1641f4..ef2c3b803d2 100644 --- a/arch/arm/plat-omap/include/plat/omap44xx.h +++ b/arch/arm/plat-omap/include/plat/omap44xx.h @@ -45,6 +45,7 @@ #define OMAP44XX_WKUPGEN_BASE 0x48281000 #define OMAP44XX_MCPDM_BASE 0x40132000 #define OMAP44XX_MCPDM_L3_BASE 0x49032000 +#define OMAP44XX_DSS_HDMI_L3_BASE 0x58006000 #define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000) #define OMAP44XX_HSUSB_OTG_BASE (L4_44XX_BASE + 0xAB000) diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 1adea9c6298..5bcbca86170 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -551,6 +551,8 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), int __init omap_hwmod_setup_one(const char *name); +int __init omap_hwmod_setup_one(const char *name); + int omap_hwmod_enable(struct omap_hwmod *oh); int _omap_hwmod_enable(struct omap_hwmod *oh); int omap_hwmod_idle(struct omap_hwmod *oh); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 271835a7157..7301d5e7fda 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -262,15 +262,12 @@ EXPORT_SYMBOL(drm_init); void drm_exit(struct drm_driver *driver) { - struct drm_device *dev, *tmp; DRM_DEBUG("\n"); - if (driver->driver_features & DRIVER_MODESET) { - pci_unregister_driver(&driver->pci_driver); - } else { - list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item) - drm_put_dev(dev); - } + if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE) + drm_platform_exit(driver); + else + drm_pci_exit(driver); DRM_INFO("Module unloaded\n"); } diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index be9a9c07d15..73bf49360c9 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -54,11 +54,11 @@ int drm_name_info(struct seq_file *m, void *data) if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) { if (master->unique) { seq_printf(m, "%s %s %s\n", - dev->driver->platform_device->name, + dev->platformdev->name, dev_name(dev->dev), master->unique); } else { seq_printf(m, "%s\n", - dev->driver->platform_device->name); + dev->platformdev->name); } } else { if (master->unique) { diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index f5bd9e590c8..6f7e41b5816 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -263,6 +263,19 @@ int drm_pci_init(struct drm_driver *driver) return 0; } +void drm_pci_exit(struct drm_driver *driver) +{ + struct drm_device *dev, *tmp; + + if (driver->driver_features & DRIVER_MODESET) { + pci_unregister_driver(&driver->pci_driver); + } else { + list_for_each_entry_safe(dev, tmp, &driver->device_list, + driver_item) + drm_put_dev(dev); + } +} + #else int drm_pci_init(struct drm_driver *driver) @@ -270,5 +283,9 @@ int drm_pci_init(struct drm_driver *driver) return -1; } +void drm_pci_exit(struct drm_driver *driver) +{ +} + #endif /*@}*/ diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 92d1d0fb7b7..8f68a5431db 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -123,5 +123,10 @@ EXPORT_SYMBOL(drm_get_platform_dev); int drm_platform_init(struct drm_driver *driver) { - return drm_get_platform_dev(driver->platform_device, driver); + return platform_driver_register(&driver->platform_driver); +} + +void drm_platform_exit(struct drm_driver *driver) +{ + platform_driver_unregister(&driver->platform_driver); } diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 029a4babfd6..de08878f73c 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -125,8 +125,8 @@ module_param(vid2_static_vrfb_alloc, bool, S_IRUGO); MODULE_PARM_DESC(vid2_static_vrfb_alloc, "Static allocation of the VRFB buffer for video2 device"); -module_param(debug, bool, S_IRUGO); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); +module_param(debug, int, S_IRUGO); +MODULE_PARM_DESC(debug, "Debug level"); /* list of image formats supported by OMAP2 video pipelines */ const static struct v4l2_fmtdesc omap_formats[] = { @@ -2235,6 +2235,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) mutex_init(&vout->lock); vfd->minor = -1; + vfd->debug = debug; + return 0; } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9050dd9b62d..8ceb6a0d53e 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -112,8 +112,8 @@ extern u32 wl12xx_debug_level; CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) -#define WL1271_FW_NAME "wl1271-fw.bin" -#define WL1271_NVS_NAME "wl1271-nvs.bin" +#define WL1271_FW_NAME "ti-connectivity/wl1271-fw.bin" +#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin" #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index a6d3f2ffe81..c2915133291 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -555,7 +555,6 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->ep0_stage = MUSB_EP0_START; musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); - musb_platform_set_vbus(musb, 1); handled = IRQ_HANDLED; } @@ -848,12 +847,16 @@ b_host: DBG(1, "HNP: in %s, %d msec timeout\n", otg_state_string(musb), TA_WAIT_BCON(musb)); +#ifdef CONFIG_USB_MUSB_OTG mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(TA_WAIT_BCON(musb))); +#endif break; case OTG_STATE_A_PERIPHERAL: musb->ignore_disconnect = 0; +#ifdef CONFIG_USB_MUSB_OTG del_timer(&musb->otg_timer); +#endif musb_g_reset(musb); break; case OTG_STATE_B_WAIT_ACON: @@ -1729,6 +1732,8 @@ musb_mode_store(struct device *dev, struct device_attribute *attr, unsigned long flags; int status; + pm_runtime_get_sync(musb->controller); + spin_lock_irqsave(&musb->lock, flags); if (sysfs_streq(buf, "host")) status = musb_platform_set_mode(musb, MUSB_HOST); @@ -1740,6 +1745,8 @@ musb_mode_store(struct device *dev, struct device_attribute *attr, status = -EINVAL; spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_put_sync(musb->controller); + return (status == 0) ? n : status; } static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); @@ -1837,6 +1844,9 @@ static void musb_irq_work(struct work_struct *data) struct musb *musb = container_of(data, struct musb, irq_work); static int old_state; + if(musb->xceiv->state = OTG_STATE_A_IDLE) + musb_platform_set_vbus(musb, 1); + if (musb->xceiv->state != old_state) { old_state = musb->xceiv->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 25cb8b0003b..50d2694409d 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -259,8 +259,10 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_VBUS: DBG(4, "VBUS Connect\n"); +#ifdef CONFIG_USB_GADGET_MUSB_HDRC if (musb->gadget_driver) pm_runtime_get_sync(musb->controller); +#endif otg_init(musb->xceiv); break; diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index bfc5da0e970..5c299d5552c 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -56,6 +56,7 @@ config OMAP2_DSS_RFBI config OMAP2_DSS_VENC bool "VENC support" + depends on BROKEN default y help OMAP Video Encoder support for S-Video and composite TV-out. diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 1aa2ed1e786..19075085f96 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -491,6 +491,9 @@ int omap_dss_register_device(struct omap_dss_device *dssdev) dssdev->dev.parent = &dss_bus; dssdev->dev.release = omap_dss_dev_release; dev_set_name(&dssdev->dev, "display%d", dev_num++); + + BLOCKING_INIT_NOTIFIER_HEAD(&dssdev->notifier); + return device_register(&dssdev->dev); } diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7804779c9da..abfe4b0bbdb 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -128,6 +128,16 @@ struct dispc_reg { u16 idx; }; #define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04) +/* + * The OMAP4 DISPC_DIVISOR1 is backward compatible to OMAP3xxx DISPC_DIVISOR. + * However DISPC_DIVISOR is also provided in OMAP4, to control DISPC_CORE_CLK. + * This allows DISPC_CORE_CLK to be independent of logical clock dividers (lcd) + * of LCD1 (primary) and LCD2 (secondary) displays. + * + * To derive pixel clocks for Primary and Secondary LCD channels, configure the + * lcd and pcd in DISPC_DIVISOR1 and DISPC_DIVISOR2 respectively, using the + * DISPC_DIVISORo(ch). + */ #define DISPC_DIVISOR DISPC_REG(0x0804) #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index a85a6f38b40..fa9df604387 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <plat/display.h> #include "dss.h" @@ -614,3 +615,51 @@ void omap_dss_stop_device(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omap_dss_stop_device); +/* since omap_dss_update_size can be called in irq context, schedule work from + * work-queue to deliver notification to client.. + */ +struct notify_work { + struct work_struct work; + struct omap_dss_device *dssdev; + enum omap_dss_event evt; +}; + +static void notify_worker(struct work_struct *work) +{ + struct notify_work *nw = + container_of(work, struct notify_work, work); + struct omap_dss_device *dssdev = nw->dssdev; + blocking_notifier_call_chain(&dssdev->notifier, nw->evt, dssdev); + kfree(work); +} + +/** + * Called by lower level driver to notify about a change in resolution, etc. + */ +void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt) +{ + struct notify_work *nw = + kmalloc(sizeof(struct notify_work), GFP_KERNEL); + if (nw) { + INIT_WORK(&nw->work, notify_worker); + nw->dssdev = dssdev; + nw->evt = evt; + schedule_work(&nw->work); + } +} +EXPORT_SYMBOL(omap_dss_notify); + +void omap_dss_add_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_register(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_add_notify); + +void omap_dss_remove_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_remove_notify); + diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index e9b734ccb1a..0b943f68979 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -190,11 +190,19 @@ typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); #define DSI_MAX_NR_ISRS 2 struct dsi_isr_data { - omap_dsi_isr_t isr; - void *arg; - u32 mask; + omap_dsi_isr_t isr; + void *arg; + u32 mask; }; +#define FINT_MAX 2100000 +#define FINT_MIN 750000 +#define REGN_MAX (1 << 7) +#define REGM_MAX ((1 << 11) - 1) +#define REGM_DISPC_MAX (1 << 4) +#define REGM_DSI_MAX (1 << 4) +#define LP_DIV_MAX ((1 << 13) - 1) + enum fifo_size { DSI_FIFO_SIZE_0 = 0, DSI_FIFO_SIZE_32 = 1, @@ -249,10 +257,8 @@ static struct unsigned pll_locked; - spinlock_t irq_lock; - struct dsi_isr_tables isr_tables; - /* space for a copy used by the interrupt handler */ - struct dsi_isr_tables isr_tables_copy; + struct completion bta_completion; + void (*bta_callback)(void); int update_channel; struct dsi_update_region update_region; @@ -287,11 +293,6 @@ static struct spinlock_t irq_stats_lock; struct dsi_irq_stats irq_stats; #endif - /* DSI PLL Parameter Ranges */ - unsigned long regm_max, regn_max; - unsigned long regm_dispc_max, regm_dsi_max; - unsigned long fint_min, fint_max; - unsigned long lpdiv_max; } dsi; #ifdef DEBUG @@ -335,11 +336,6 @@ static bool dsi_bus_is_locked(void) return dsi.bus_lock.count == 0; } -static void dsi_completion_handler(void *data, u32 mask) -{ - complete((struct completion *)data); -} - static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum, int value) { @@ -409,9 +405,6 @@ static void dsi_perf_show(const char *name) static void print_irq_status(u32 status) { - if (status == 0) - return; - #ifndef VERBOSE_IRQ if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) return; @@ -447,9 +440,6 @@ static void print_irq_status(u32 status) static void print_irq_status_vc(int channel, u32 status) { - if (status == 0) - return; - #ifndef VERBOSE_IRQ if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) return; @@ -509,33 +499,26 @@ static void print_irq_status_cio(u32 status) printk("\n"); } -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus) +static int debug_irq; + +/* called from dss */ +static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) { + u32 irqstatus, vcstatus, ciostatus; int i; - spin_lock(&dsi.irq_stats_lock); + irqstatus = dsi_read_reg(DSI_IRQSTATUS); + + /* IRQ is not for us */ + if (!irqstatus) + return IRQ_NONE; +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock(&dsi.irq_stats_lock); dsi.irq_stats.irq_count++; dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs); - - for (i = 0; i < 4; ++i) - dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]); - - dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs); - - spin_unlock(&dsi.irq_stats_lock); -} -#else -#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus) #endif -static int debug_irq; - -static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus) -{ - int i; - if (irqstatus & DSI_IRQ_ERROR_MASK) { DSSERR("DSI error, irqstatus %x\n", irqstatus); print_irq_status(irqstatus); @@ -546,88 +529,37 @@ static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus) print_irq_status(irqstatus); } - for (i = 0; i < 4; ++i) { - if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) { - DSSERR("DSI VC(%d) error, vc irqstatus %x\n", - i, vcstatus[i]); - print_irq_status_vc(i, vcstatus[i]); - } else if (debug_irq) { - print_irq_status_vc(i, vcstatus[i]); - } - } - - if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { - DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); - print_irq_status_cio(ciostatus); - } else if (debug_irq) { - print_irq_status_cio(ciostatus); - } -} - -static void dsi_call_isrs(struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 irqstatus) -{ - struct dsi_isr_data *isr_data; - int i; - - for (i = 0; i < isr_array_size; i++) { - isr_data = &isr_array[i]; - if (isr_data->isr && isr_data->mask & irqstatus) - isr_data->isr(isr_data->arg, irqstatus); - } -} - -static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables, - u32 irqstatus, u32 *vcstatus, u32 ciostatus) -{ - int i; - - dsi_call_isrs(isr_tables->isr_table, - ARRAY_SIZE(isr_tables->isr_table), - irqstatus); +#ifdef DSI_CATCH_MISSING_TE + if (irqstatus & DSI_IRQ_TE_TRIGGER) + del_timer(&dsi.te_timer); +#endif for (i = 0; i < 4; ++i) { - if (vcstatus[i] == 0) + if ((irqstatus & (1<<i)) == 0) continue; - dsi_call_isrs(isr_tables->isr_table_vc[i], - ARRAY_SIZE(isr_tables->isr_table_vc[i]), - vcstatus[i]); - } - if (ciostatus != 0) - dsi_call_isrs(isr_tables->isr_table_cio, - ARRAY_SIZE(isr_tables->isr_table_cio), - ciostatus); -} + vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i)); -static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) -{ - u32 irqstatus, vcstatus[4], ciostatus; - int i; - - spin_lock(&dsi.irq_lock); - - irqstatus = dsi_read_reg(DSI_IRQSTATUS); - - /* IRQ is not for us */ - if (!irqstatus) { - spin_unlock(&dsi.irq_lock); - return IRQ_NONE; - } +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); +#endif - dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); - /* flush posted write */ - dsi_read_reg(DSI_IRQSTATUS); + if (vcstatus & DSI_VC_IRQ_BTA) { + complete(&dsi.bta_completion); - for (i = 0; i < 4; ++i) { - if ((irqstatus & (1 << i)) == 0) { - vcstatus[i] = 0; - continue; + if (dsi.bta_callback) + dsi.bta_callback(); } - vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i)); + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { + DSSERR("DSI VC(%d) error, vc irqstatus %x\n", + i, vcstatus); + print_irq_status_vc(i, vcstatus); + } else if (debug_irq) { + print_irq_status_vc(i, vcstatus); + } - dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]); + dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus); /* flush posted write */ dsi_read_reg(DSI_VC_IRQSTATUS(i)); } @@ -635,289 +567,99 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) { ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs); +#endif + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus); /* flush posted write */ dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); - } else { - ciostatus = 0; - } - -#ifdef DSI_CATCH_MISSING_TE - if (irqstatus & DSI_IRQ_TE_TRIGGER) - del_timer(&dsi.te_timer); -#endif - - /* make a copy and unlock, so that isrs can unregister - * themselves */ - memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables)); - - spin_unlock(&dsi.irq_lock); - dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus); - - dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus); - - dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus); - - return IRQ_HANDLED; -} - -/* dsi.irq_lock has to be locked by the caller */ -static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 default_mask, - const struct dsi_reg enable_reg, - const struct dsi_reg status_reg) -{ - struct dsi_isr_data *isr_data; - u32 mask; - u32 old_mask; - int i; - - mask = default_mask; - - for (i = 0; i < isr_array_size; i++) { - isr_data = &isr_array[i]; - - if (isr_data->isr == NULL) - continue; - - mask |= isr_data->mask; + if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); + print_irq_status_cio(ciostatus); + } else if (debug_irq) { + print_irq_status_cio(ciostatus); + } } - old_mask = dsi_read_reg(enable_reg); - /* clear the irqstatus for newly enabled irqs */ - dsi_write_reg(status_reg, (mask ^ old_mask) & mask); - dsi_write_reg(enable_reg, mask); - - /* flush posted writes */ - dsi_read_reg(enable_reg); - dsi_read_reg(status_reg); -} + dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); + /* flush posted write */ + dsi_read_reg(DSI_IRQSTATUS); -/* dsi.irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs(void) -{ - u32 mask = DSI_IRQ_ERROR_MASK; -#ifdef DSI_CATCH_MISSING_TE - mask |= DSI_IRQ_TE_TRIGGER; +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_unlock(&dsi.irq_stats_lock); #endif - _omap_dsi_configure_irqs(dsi.isr_tables.isr_table, - ARRAY_SIZE(dsi.isr_tables.isr_table), mask, - DSI_IRQENABLE, DSI_IRQSTATUS); -} - -/* dsi.irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_vc(int vc) -{ - _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc], - ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]), - DSI_VC_IRQ_ERROR_MASK, - DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc)); -} - -/* dsi.irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_cio(void) -{ - _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio, - ARRAY_SIZE(dsi.isr_tables.isr_table_cio), - DSI_CIO_IRQ_ERROR_MASK, - DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS); + return IRQ_HANDLED; } static void _dsi_initialize_irq(void) { - unsigned long flags; - int vc; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables)); - - _omap_dsi_set_irqs(); - for (vc = 0; vc < 4; ++vc) - _omap_dsi_set_irqs_vc(vc); - _omap_dsi_set_irqs_cio(); - - spin_unlock_irqrestore(&dsi.irq_lock, flags); -} - -static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) -{ - struct dsi_isr_data *isr_data; - int free_idx; - int i; - - BUG_ON(isr == NULL); - - /* check for duplicate entry and find a free slot */ - free_idx = -1; - for (i = 0; i < isr_array_size; i++) { - isr_data = &isr_array[i]; - - if (isr_data->isr == isr && isr_data->arg == arg && - isr_data->mask == mask) { - return -EINVAL; - } - - if (isr_data->isr == NULL && free_idx == -1) - free_idx = i; - } - - if (free_idx == -1) - return -EBUSY; - - isr_data = &isr_array[free_idx]; - isr_data->isr = isr; - isr_data->arg = arg; - isr_data->mask = mask; - - return 0; -} - -static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) -{ - struct dsi_isr_data *isr_data; + u32 l; int i; - for (i = 0; i < isr_array_size; i++) { - isr_data = &isr_array[i]; - if (isr_data->isr != isr || isr_data->arg != arg || - isr_data->mask != mask) - continue; + /* disable all interrupts */ + dsi_write_reg(DSI_IRQENABLE, 0); + for (i = 0; i < 4; ++i) + dsi_write_reg(DSI_VC_IRQENABLE(i), 0); + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0); - isr_data->isr = NULL; - isr_data->arg = NULL; - isr_data->mask = 0; + /* clear interrupt status */ + l = dsi_read_reg(DSI_IRQSTATUS); + dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK); - return 0; + for (i = 0; i < 4; ++i) { + l = dsi_read_reg(DSI_VC_IRQSTATUS(i)); + dsi_write_reg(DSI_VC_IRQSTATUS(i), l); } - return -EINVAL; -} - -static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask) -{ - unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table, - ARRAY_SIZE(dsi.isr_tables.isr_table)); - - if (r == 0) - _omap_dsi_set_irqs(); - - spin_unlock_irqrestore(&dsi.irq_lock, flags); + l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l); - return r; -} - -static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask) -{ - unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table, - ARRAY_SIZE(dsi.isr_tables.isr_table)); - - if (r == 0) - _omap_dsi_set_irqs(); - - spin_unlock_irqrestore(&dsi.irq_lock, flags); - - return r; -} - -static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, - u32 mask) -{ - unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_register_isr(isr, arg, mask, - dsi.isr_tables.isr_table_vc[channel], - ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); - - if (r == 0) - _omap_dsi_set_irqs_vc(channel); + /* enable error irqs */ + l = DSI_IRQ_ERROR_MASK; +#ifdef DSI_CATCH_MISSING_TE + l |= DSI_IRQ_TE_TRIGGER; +#endif + dsi_write_reg(DSI_IRQENABLE, l); - spin_unlock_irqrestore(&dsi.irq_lock, flags); + l = DSI_VC_IRQ_ERROR_MASK; + for (i = 0; i < 4; ++i) + dsi_write_reg(DSI_VC_IRQENABLE(i), l); - return r; + l = DSI_CIO_IRQ_ERROR_MASK; + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); } -static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, - u32 mask) +static u32 dsi_get_errors(void) { unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_unregister_isr(isr, arg, mask, - dsi.isr_tables.isr_table_vc[channel], - ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); - - if (r == 0) - _omap_dsi_set_irqs_vc(channel); - - spin_unlock_irqrestore(&dsi.irq_lock, flags); - - return r; + u32 e; + spin_lock_irqsave(&dsi.errors_lock, flags); + e = dsi.errors; + dsi.errors = 0; + spin_unlock_irqrestore(&dsi.errors_lock, flags); + return e; } -static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) +static void dsi_vc_enable_bta_irq(int channel) { - unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, - ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); - - if (r == 0) - _omap_dsi_set_irqs_cio(); + u32 l; - spin_unlock_irqrestore(&dsi.irq_lock, flags); + dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA); - return r; + l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); + l |= DSI_VC_IRQ_BTA; + dsi_write_reg(DSI_VC_IRQENABLE(channel), l); } -static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) +static void dsi_vc_disable_bta_irq(int channel) { - unsigned long flags; - int r; - - spin_lock_irqsave(&dsi.irq_lock, flags); - - r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, - ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); - - if (r == 0) - _omap_dsi_set_irqs_cio(); - - spin_unlock_irqrestore(&dsi.irq_lock, flags); - - return r; -} + u32 l; -static u32 dsi_get_errors(void) -{ - unsigned long flags; - u32 e; - spin_lock_irqsave(&dsi.errors_lock, flags); - e = dsi.errors; - dsi.errors = 0; - spin_unlock_irqrestore(&dsi.errors_lock, flags); - return e; + l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); + l &= ~DSI_VC_IRQ_BTA; + dsi_write_reg(DSI_VC_IRQENABLE(channel), l); } /* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ @@ -1028,7 +770,7 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev) lp_clk_div = dssdev->phy.dsi.div.lp_clk_div; - if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max) + if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX) return -EINVAL; dsi_fclk = dsi_fclk_rate(); @@ -1078,16 +820,16 @@ static int dsi_pll_power(enum dsi_pll_power_state state) static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, struct dsi_clock_info *cinfo) { - if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max) + if (cinfo->regn == 0 || cinfo->regn > REGN_MAX) return -EINVAL; - if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max) + if (cinfo->regm == 0 || cinfo->regm > REGM_MAX) return -EINVAL; - if (cinfo->regm_dispc > dsi.regm_dispc_max) + if (cinfo->regm_dispc > REGM_DISPC_MAX) return -EINVAL; - if (cinfo->regm_dsi > dsi.regm_dsi_max) + if (cinfo->regm_dsi > REGM_DSI_MAX) return -EINVAL; if (cinfo->use_sys_clk) { @@ -1106,7 +848,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1)); - if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min) + if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN) return -EINVAL; cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint; @@ -1141,7 +883,7 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); - max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + max_dss_fck = dss_feat_get_max_dss_fck(); if (req_pck == dsi.cache_req_pck && dsi.cache_cinfo.clkin == dss_sys_clk) { @@ -1176,17 +918,17 @@ retry: /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ - for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) { + for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) { if (cur.highfreq == 0) cur.fint = cur.clkin / cur.regn; else cur.fint = cur.clkin / (2 * cur.regn); - if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min) + if (cur.fint > FINT_MAX || cur.fint < FINT_MIN) continue; /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ - for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) { + for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) { unsigned long a, b; a = 2 * cur.regm * (cur.clkin/1000); @@ -1198,7 +940,7 @@ retry: /* dsi_pll_hsdiv_dispc_clk(MHz) = * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */ - for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max; + for (cur.regm_dispc = 1; cur.regm_dispc < REGM_DISPC_MAX; ++cur.regm_dispc) { struct dispc_clock_info cur_dispc; cur.dsi_pll_hsdiv_dispc_clk = @@ -1270,9 +1012,7 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) { int r = 0; u32 l; - int f = 0; - u8 regn_start, regn_end, regm_start, regm_end; - u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; + int f; DSSDBGF(); @@ -1317,43 +1057,32 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), cinfo->dsi_pll_hsdiv_dsi_clk); - dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, ®n_start, ®n_end); - dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, ®m_start, ®m_end); - dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, ®m_dispc_start, - ®m_dispc_end); - dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, ®m_dsi_start, - ®m_dsi_end); - REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */ l = dsi_read_reg(DSI_PLL_CONFIGURATION1); l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */ - /* DSI_PLL_REGN */ - l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end); - /* DSI_PLL_REGM */ - l = FLD_MOD(l, cinfo->regm, regm_start, regm_end); - /* DSI_CLOCK_DIV */ + l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */ + l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */ l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0, - regm_dispc_start, regm_dispc_end); - /* DSIPROTO_CLOCK_DIV */ + 22, 19); /* DSI_CLOCK_DIV */ l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0, - regm_dsi_start, regm_dsi_end); + 26, 23); /* DSIPROTO_CLOCK_DIV */ dsi_write_reg(DSI_PLL_CONFIGURATION1, l); - BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max); - - if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { - f = cinfo->fint < 1000000 ? 0x3 : - cinfo->fint < 1250000 ? 0x4 : - cinfo->fint < 1500000 ? 0x5 : - cinfo->fint < 1750000 ? 0x6 : - 0x7; - } + BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000); + if (cinfo->fint < 1000000) + f = 0x3; + else if (cinfo->fint < 1250000) + f = 0x4; + else if (cinfo->fint < 1500000) + f = 0x5; + else if (cinfo->fint < 1750000) + f = 0x6; + else + f = 0x7; l = dsi_read_reg(DSI_PLL_CONFIGURATION2); - - if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) - l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ + l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1, 11, 11); /* DSI_PLL_CLKSEL */ l = FLD_MOD(l, cinfo->highfreq, @@ -1873,6 +1602,9 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev) DSSDBG("dsi_complexio_init\n"); + /* CIO_CLK_ICG, enable L3 clk to CIO */ + REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14); + /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ @@ -1897,12 +1629,10 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev) goto err; } - if (dss_has_feature(FEAT_DSI_LDO_STATUS)) { - if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) { - DSSERR("ComplexIO LDO power down.\n"); - r = -ENODEV; - goto err; - } + if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) { + DSSERR("ComplexIO LDO power down.\n"); + r = -ENODEV; + goto err; } dsi_complexio_timings(); @@ -2069,8 +1799,6 @@ static void dsi_vc_initial_config(int channel) r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */ r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */ - if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH)) - r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ @@ -2095,10 +1823,6 @@ static int dsi_vc_config_l4(int channel) REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ - /* DCS_CMD_ENABLE */ - if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) - REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 30, 30); - dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_L4; @@ -2123,10 +1847,6 @@ static int dsi_vc_config_vp(int channel) REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ - /* DCS_CMD_ENABLE */ - if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) - REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 30, 30); - dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_VP; @@ -2251,44 +1971,33 @@ static int dsi_vc_send_bta(int channel) int dsi_vc_send_bta_sync(int channel) { - DECLARE_COMPLETION_ONSTACK(completion); int r = 0; u32 err; - r = dsi_register_isr_vc(channel, dsi_completion_handler, - &completion, DSI_VC_IRQ_BTA); - if (r) - goto err0; + INIT_COMPLETION(dsi.bta_completion); - r = dsi_register_isr(dsi_completion_handler, &completion, - DSI_IRQ_ERROR_MASK); - if (r) - goto err1; + dsi_vc_enable_bta_irq(channel); r = dsi_vc_send_bta(channel); if (r) - goto err2; + goto err; - if (wait_for_completion_timeout(&completion, + if (wait_for_completion_timeout(&dsi.bta_completion, msecs_to_jiffies(500)) == 0) { DSSERR("Failed to receive BTA\n"); r = -EIO; - goto err2; + goto err; } err = dsi_get_errors(); if (err) { DSSERR("Error while sending BTA: %x\n", err); r = -EIO; - goto err2; + goto err; } -err2: - dsi_unregister_isr(dsi_completion_handler, &completion, - DSI_IRQ_ERROR_MASK); -err1: - dsi_unregister_isr_vc(channel, dsi_completion_handler, - &completion, DSI_VC_IRQ_BTA); -err0: +err: + dsi_vc_disable_bta_irq(channel); + return r; } EXPORT_SYMBOL(dsi_vc_send_bta_sync); @@ -2782,11 +2491,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */ r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ - if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { - r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */ - /* DCS_CMD_CODE, 1=start, 0=continue */ - r = FLD_MOD(r, 0, 25, 25); - } + r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */ + r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */ dsi_write_reg(DSI_CTRL, r); @@ -3105,20 +2811,19 @@ static void dsi_te_timeout(unsigned long arg) } #endif -static void dsi_framedone_bta_callback(void *data, u32 mask); - static void dsi_handle_framedone(int error) { const int channel = dsi.update_channel; - dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback, - NULL, DSI_VC_IRQ_BTA); - cancel_delayed_work(&dsi.framedone_timeout_work); + dsi_vc_disable_bta_irq(channel); + /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); + dsi.bta_callback = NULL; + if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ @@ -3152,7 +2857,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) dsi_handle_framedone(-ETIMEDOUT); } -static void dsi_framedone_bta_callback(void *data, u32 mask) +static void dsi_framedone_bta_callback(void) { dsi_handle_framedone(0); @@ -3192,19 +2897,15 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) * asynchronously. * */ - r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback, - NULL, DSI_VC_IRQ_BTA); - if (r) { - DSSERR("Failed to register BTA ISR\n"); - dsi_handle_framedone(-EIO); - return; - } + dsi.bta_callback = dsi_framedone_bta_callback; + + barrier(); + + dsi_vc_enable_bta_irq(channel); r = dsi_vc_send_bta(channel); if (r) { DSSERR("BTA after framedone failed\n"); - dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback, - NULL, DSI_VC_IRQ_BTA); dsi_handle_framedone(-EIO); } } @@ -3383,10 +3084,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { int r; - /* The SCPClk is required for both PLL and CIO registers on OMAP4 */ - /* CIO_CLK_ICG, enable L3 clk to CIO */ - REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14); - _dsi_print_reset_status(); r = dsi_pll_init(dssdev, true, true); @@ -3399,8 +3096,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC); dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI); - dss_select_lcd_clk_source(dssdev->manager->id, - DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC); DSSDBG("PLL OK\n"); @@ -3657,24 +3352,12 @@ void dsi_wait_pll_hsdiv_dsi_active(void) dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI)); } -static void dsi_calc_clock_param_ranges(void) -{ - dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN); - dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM); - dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC); - dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI); - dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT); - dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT); - dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); -} - static int dsi_init(struct platform_device *pdev) { u32 rev; int r, i; struct resource *dsi_mem; - spin_lock_init(&dsi.irq_lock); spin_lock_init(&dsi.errors_lock); dsi.errors = 0; @@ -3683,6 +3366,8 @@ static int dsi_init(struct platform_device *pdev) dsi.irq_stats.last_reset = jiffies; #endif + init_completion(&dsi.bta_completion); + mutex_init(&dsi.lock); sema_init(&dsi.bus_lock, 1); @@ -3731,8 +3416,6 @@ static int dsi_init(struct platform_device *pdev) dsi.vc[i].vc_id = 0; } - dsi_calc_clock_param_ranges(); - enable_clocks(1); rev = dsi_read_reg(DSI_REVISION); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 3f1fee63c67..7f846996dc3 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -82,10 +82,10 @@ static struct { u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; -static const char * const dss_generic_clk_source_names[] = { - [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", - [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", - [DSS_CLK_SRC_FCK] = "DSS_FCK", +static const struct dss_clk_source_name dss_generic_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI_PLL_HSDIV_DISPC" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI_PLL_HSDIV_DSI" }, + { DSS_CLK_SRC_FCK, "DSS_FCK" }, }; static void dss_clk_enable_all_no_ctx(void); @@ -232,47 +232,37 @@ void dss_sdi_disable(void) const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src) { - return dss_generic_clk_source_names[clk_src]; + return dss_generic_clk_source_names[clk_src].clksrc_name; } void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; unsigned long dpll4_m4_ck_rate; - const char *fclk_name, *fclk_real_name; - unsigned long fclk_rate; dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - seq_printf(s, "- DSS -\n"); - - fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK); - fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK); - fclk_rate = dss_clk_get_rate(DSS_CLK_FCK); + dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); - if (dss.dpll4_m4_ck) { - dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); + seq_printf(s, "- DSS -\n"); - seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); + seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - if (cpu_is_omap3630() || cpu_is_omap44xx()) - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); - else - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); - } else { - seq_printf(s, "%s (%s) = %lu\n", - fclk_name, fclk_real_name, - fclk_rate); - } + if (cpu_is_omap3630() || cpu_is_omap44xx()) + seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), + dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss_clk_get_rate(DSS_CLK_FCK)); + else + seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), + dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss_clk_get_rate(DSS_CLK_FCK)); dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } @@ -392,43 +382,34 @@ enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) /* calculate clock rates using dividers in cinfo */ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { - if (dss.dpll4_m4_ck) { - unsigned long prate; - u16 fck_div_max = 16; + unsigned long prate; + u16 fck_div_max = 16; - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; + if (cpu_is_omap3630() || cpu_is_omap44xx()) + fck_div_max = 32; - if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) - return -EINVAL; + if ((cinfo->fck_div > fck_div_max) || cinfo->fck_div == 0) + return -EINVAL; - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - cinfo->fck = prate / cinfo->fck_div; - } else { - if (cinfo->fck_div != 0) - return -EINVAL; - cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); - } + cinfo->fck = prate / cinfo->fck_div; return 0; } int dss_set_clock_div(struct dss_clock_info *cinfo) { - if (dss.dpll4_m4_ck) { - unsigned long prate; - int r; + unsigned long prate; + int r; + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); DSSDBG("dpll4_m4 = %ld\n", prate); r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); if (r) return r; - } else { - if (cinfo->fck_div != 0) - return -EINVAL; } DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); @@ -440,11 +421,9 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) { cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); - if (dss.dpll4_m4_ck) { + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { unsigned long prate; - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - if (cpu_is_omap3630() || cpu_is_omap44xx()) cinfo->fck_div = prate / (cinfo->fck); else @@ -458,7 +437,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) unsigned long dss_get_dpll4_rate(void) { - if (dss.dpll4_m4_ck) + if (cpu_is_omap34xx() || cpu_is_omap44xx()) return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); else return 0; @@ -481,7 +460,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, prate = dss_get_dpll4_rate(); - max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + max_dss_fck = dss_feat_get_max_dss_fck(); fck = dss_clk_get_rate(DSS_CLK_FCK); if (req_pck == dss.cache_req_pck && @@ -507,7 +486,7 @@ retry: memset(&best_dss, 0, sizeof(best_dss)); memset(&best_dispc, 0, sizeof(best_dispc)); - if (dss.dpll4_m4_ck == NULL) { + if (cpu_is_omap24xx()) { struct dispc_clock_info cur_dispc; /* XXX can we change the clock on omap2? */ fck = dss_clk_get_rate(DSS_CLK_FCK); @@ -522,7 +501,8 @@ retry: best_dispc = cur_dispc; goto found; - } else { + } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + if (cpu_is_omap3630() || cpu_is_omap44xx()) fck_div_max = 32; @@ -557,6 +537,8 @@ retry: goto found; } } + } else { + BUG(); } found: @@ -639,7 +621,6 @@ static int dss_init(void) int r; u32 rev; struct resource *dss_mem; - struct clk *dpll4_m4_ck; dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); if (!dss_mem) { @@ -680,26 +661,23 @@ static int dss_init(void) REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif + if (cpu_is_omap34xx()) { - dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(dpll4_m4_ck)) { + dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); + if (IS_ERR(dss.dpll4_m4_ck)) { DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(dpll4_m4_ck); + r = PTR_ERR(dss.dpll4_m4_ck); goto fail1; } } else if (cpu_is_omap44xx()) { - dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(dpll4_m4_ck)) { + dss.dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); + if (IS_ERR(dss.dpll4_m4_ck)) { DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(dpll4_m4_ck); + r = PTR_ERR(dss.dpll4_m4_ck); goto fail1; } - } else { /* omap24xx */ - dpll4_m4_ck = NULL; } - dss.dpll4_m4_ck = dpll4_m4_ck; - dss.dsi_clk_source = DSS_CLK_SRC_FCK; dss.dispc_clk_source = DSS_CLK_SRC_FCK; dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; @@ -721,7 +699,7 @@ fail0: static void dss_exit(void) { - if (dss.dpll4_m4_ck) + if (cpu_is_omap34xx() || cpu_is_omap44xx()) clk_put(dss.dpll4_m4_ck); iounmap(dss.base); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index c2f582bb19c..05ccd005e26 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -126,6 +126,12 @@ enum dss_clk_source { * OMAP4: DSS_FCLK */ }; +/* Correlates clock source name and dss_clk_source member */ +struct dss_clk_source_name { + enum dss_clk_source clksrc; + const char *clksrc_name; +}; + enum dss_hdmi_venc_clk_source_select { DSS_VENC_TV_CLK = 0, DSS_HDMI_M_PCLK = 1, diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 179a7a4f63b..86dc848fae2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -30,13 +30,10 @@ /* Defines a generic omap register field */ struct dss_reg_field { + enum dss_feat_reg_field id; u8 start, end; }; -struct dss_param_range { - int min, max; -}; - struct omap_dss_features { const struct dss_reg_field *reg_fields; const int num_reg_fields; @@ -45,58 +42,46 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; + const unsigned long max_dss_fck; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; - const char * const *clksrc_names; - const struct dss_param_range *dss_params; + const struct dss_clk_source_name *clksrc_names; }; /* This struct is assigned to one of the below during initialization */ static struct omap_dss_features *omap_current_dss_features; static const struct dss_reg_field omap2_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 11, 0 }, - [FEAT_REG_FIRVINC] = { 27, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 }, - [FEAT_REG_FIFOSIZE] = { 8, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, - [FEAT_REG_VERTICALACCU] = { 25, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, - [FEAT_REG_DSIPLL_REGN] = { 0, 0 }, - [FEAT_REG_DSIPLL_REGM] = { 0, 0 }, - [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 }, - [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 }, + { FEAT_REG_FIRHINC, 11, 0 }, + { FEAT_REG_FIRVINC, 27, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 }, + { FEAT_REG_FIFOSIZE, 8, 0 }, + { FEAT_REG_HORIZONTALACCU, 9, 0 }, + { FEAT_REG_VERTICALACCU, 25, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, }; static const struct dss_reg_field omap3_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 12, 0 }, - [FEAT_REG_FIRVINC] = { 28, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, - [FEAT_REG_FIFOSIZE] = { 10, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, - [FEAT_REG_VERTICALACCU] = { 25, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, - [FEAT_REG_DSIPLL_REGN] = { 7, 1 }, - [FEAT_REG_DSIPLL_REGM] = { 18, 8 }, - [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 }, - [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 }, + { FEAT_REG_FIRHINC, 12, 0 }, + { FEAT_REG_FIRVINC, 28, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 }, + { FEAT_REG_FIFOSIZE, 10, 0 }, + { FEAT_REG_HORIZONTALACCU, 9, 0 }, + { FEAT_REG_VERTICALACCU, 25, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, }; static const struct dss_reg_field omap4_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 12, 0 }, - [FEAT_REG_FIRVINC] = { 28, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, - [FEAT_REG_FIFOSIZE] = { 15, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, - [FEAT_REG_VERTICALACCU] = { 26, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, - [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, - [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, - [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, - [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, + { FEAT_REG_FIRHINC, 12, 0 }, + { FEAT_REG_FIRVINC, 28, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 15, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 31, 16 }, + { FEAT_REG_FIFOSIZE, 15, 0 }, + { FEAT_REG_HORIZONTALACCU, 10, 0 }, + { FEAT_REG_VERTICALACCU, 26, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 9, 8 }, }; static const enum omap_display_type omap2_dss_supported_displays[] = { @@ -177,52 +162,22 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = { OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32, }; -static const char * const omap2_dss_clk_source_names[] = { - [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A", - [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A", - [DSS_CLK_SRC_FCK] = "DSS_FCLK1", -}; - -static const char * const omap3_dss_clk_source_names[] = { - [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK", - [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK", - [DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK", -}; - -static const char * const omap4_dss_clk_source_names[] = { - [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1", - [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2", - [DSS_CLK_SRC_FCK] = "DSS_FCLK", +static const struct dss_clk_source_name omap2_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "N/A" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "N/A" }, + { DSS_CLK_SRC_FCK, "DSS_FCLK1" }, }; -static const struct dss_param_range omap2_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, - [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, - [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, - [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, - [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, - [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, - [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, +static const struct dss_clk_source_name omap3_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI1_PLL_FCLK" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI2_PLL_FCLK" }, + { DSS_CLK_SRC_FCK, "DSS1_ALWON_FCLK" }, }; -static const struct dss_param_range omap3_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, - [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, - [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, - [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, - [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, - [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, - [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, -}; - -static const struct dss_param_range omap4_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, - [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, - [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, - [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, - [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, - [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, - [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, +static const struct dss_clk_source_name omap4_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "PLL1_CLK1" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "PLL1_CLK2" }, + { DSS_CLK_SRC_FCK, "DSS_FCLK" }, }; /* OMAP2 DSS Features */ @@ -237,10 +192,10 @@ static struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap2_dss_supported_displays, .supported_color_modes = omap2_dss_supported_color_modes, .clksrc_names = omap2_dss_clk_source_names, - .dss_params = omap2_dss_param_range, }; /* OMAP3 DSS Features */ @@ -252,15 +207,14 @@ static struct omap_dss_features omap3430_dss_features = { FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | - FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | - FEAT_DSI_PLL_FREQSEL | FEAT_DSI_LDO_STATUS, + FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF, .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap3_dss_clk_source_names, - .dss_params = omap3_dss_param_range, }; static struct omap_dss_features omap3630_dss_features = { @@ -272,15 +226,14 @@ static struct omap_dss_features omap3630_dss_features = { FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | - FEAT_RESIZECONF | FEAT_DSI_PLL_FREQSEL | - FEAT_DSI_LDO_STATUS, + FEAT_RESIZECONF, .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap3_dss_clk_source_names, - .dss_params = omap3_dss_param_range, }; /* OMAP4 DSS Features */ @@ -291,15 +244,14 @@ static struct omap_dss_features omap4_dss_features = { .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | - FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | - FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH, + FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC, .num_mgrs = 3, .num_ovls = 3, + .max_dss_fck = 186000000, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap4_dss_clk_source_names, - .dss_params = omap4_dss_param_range, }; /* Functions returning values related to a DSS feature */ @@ -313,14 +265,10 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } -unsigned long dss_feat_get_param_min(enum dss_range_param param) -{ - return omap_current_dss_features->dss_params[param].min; -} - -unsigned long dss_feat_get_param_max(enum dss_range_param param) +/* Max supported DSS FCK in Hz */ +unsigned long dss_feat_get_max_dss_fck(void) { - return omap_current_dss_features->dss_params[param].max; + return omap_current_dss_features->max_dss_fck; } enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel) @@ -342,7 +290,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane, const char *dss_feat_get_clk_source_name(enum dss_clk_source id) { - return omap_current_dss_features->clksrc_names[id]; + return omap_current_dss_features->clksrc_names[id].clksrc_name; } /* DSS has_feature check */ diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index c5c0b4001ab..2601626519c 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -77,6 +77,8 @@ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); +/* HDMI from Seb comapat */ +unsigned long dss_feat_get_max_dss_fck(void); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0d44f070ef3..aa5b3dc5f44 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -30,6 +30,11 @@ #include <linux/delay.h> #include <linux/string.h> #include <plat/display.h> +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +#include <sound/soc.h> +#include <sound/pcm_params.h> +#endif #include "dss.h" #include "hdmi.h" @@ -1104,6 +1109,7 @@ static void hdmi_enable_clocks(int enable) static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; + int dirty = true; struct hdmi_pll_info pll_data; struct omap_video_timings *p; int clkin, n, phy; @@ -1119,8 +1125,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dssdev->panel.timings.y_res); if (!hdmi.custom_set) { + code = get_timings_index(); DSSDBG("Read EDID as no EDID is not set on poweron\n"); hdmi_read_edid(p); + dirty = get_timings_index() != code; } code = get_timings_index(); dssdev->panel.timings = cea_vesa_timings[code].timings; @@ -1134,7 +1142,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi_wp_video_start(0); - /* config the PLL and PHY first */ + if (dirty) { + omap_dss_notify(dssdev, OMAP_DSS_SIZE_CHANGE); + } + + /* config the PLL and PHY first */ r = hdmi_pll_program(&pll_data); if (r) { DSSDBG("Failed to lock PLL\n"); @@ -1275,11 +1287,392 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) mutex_unlock(&hdmi.lock); } +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +static void hdmi_wp_audio_config_format( + struct hdmi_audio_format *aud_fmt) +{ + u32 r; + + DSSDBG("Enter hdmi_wp_audio_config_format\n"); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CFG); + r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); + r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); + r = FLD_MOD(r, aud_fmt->sig_blk_strt_end, 5, 5); + r = FLD_MOD(r, aud_fmt->type, 4, 4); + r = FLD_MOD(r, aud_fmt->justif, 3, 3); + r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); + r = FLD_MOD(r, aud_fmt->samples_p_word, 1, 1); + r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CFG, r); +} + +static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma) +{ + u32 r; + + DSSDBG("Enter hdmi_wp_audio_config_dma\n"); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2); + r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); + r = FLD_MOD(r, aud_dma->block_size, 7, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL); + r = FLD_MOD(r, aud_dma->mode, 9, 9); + r = FLD_MOD(r, aud_dma->threshold, 8, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r); +} + +static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg) +{ + u32 r; + + /* audio clock recovery parameters */ + r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL); + r = FLD_MOD(r, cfg->use_mclk, 2, 2); + r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); + r = FLD_MOD(r, cfg->cts_mode, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r); + + REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); + + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, cfg->aud_par_busclk, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2, + (cfg->aud_par_busclk >> 8), 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3, + (cfg->aud_par_busclk >> 16), 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1); + + /* I2S parameters */ + REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0); + + r = FLD_MOD(r, cfg->i2s_cfg.en_high_br_aud, 7, 7); + r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); + r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); + r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); + r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); + r = FLD_MOD(r, cfg->i2s_cfg.justif, 2, 2); + r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); + r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r); + + r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5); + r = FLD_MOD(r, cfg->freq_sample, 7, 4); + r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); + r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r); + + REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0); + + /* audio channels and mode parameters */ + REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); + r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE); + r = FLD_MOD(r, 0, 7, 7); + r = FLD_MOD(r, 0, 6, 6); + r = FLD_MOD(r, 0, 5, 5); + r = FLD_MOD(r, 1, 4, 4); + r = FLD_MOD(r, cfg->en_direct_strm_dig_aud, 3, 3); + r = FLD_MOD(r, cfg->en_parallel_aud, 2, 2); + r = FLD_MOD(r, cfg->en_spdif, 1, 1); + hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r); +} + +static void hdmi_core_audio_infoframe_config( + struct hdmi_core_infoframe_audio *info_aud) +{ + u8 val; + u8 sum = 0, checksum = 0; + + sum += 0x84 + 0x001 + 0x00a; + hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84); + hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01); + hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a); + + val = (info_aud->db1_coding_type << 4) + | (info_aud->db1_channel_count - 1); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val); + sum += val; + + val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val); + sum += val; + + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00); + + val = info_aud->db4_channel_alloc; + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val); + sum += val; + + val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val); + sum += val; + + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00); + hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00); + + checksum = 0x100 - sum; + hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum); + + /* + * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing + * is available. + */ +} + +static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) +{ + u32 r; + u32 deep_color = 0; + u32 pclk = hdmi.cfg.timings.timings.pixel_clock; + + if (n == NULL || cts == NULL) + return -EINVAL; + if (omap_rev() == OMAP4430_REV_ES1_0) + deep_color = 100; + else { + r = hdmi_read_reg(HDMI_WP_VIDEO_CFG); + switch (r & 0x03) { + case 1: + deep_color = 100; + break; + case 2: + deep_color = 125; + break; + case 3: + deep_color = 150; + break; + default: + return -EINVAL; + } + } + + switch (sample_freq) { + case 32000: + if ((deep_color == 125) && ((pclk == 54054) + || (pclk == 74250))) + *n = 8192; + else + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + if ((deep_color == 125) && ((pclk == 54054) + || (pclk == 74250))) + *n = 8192; + else + *n = 6144; + break; + default: + *n = 0; + return -EINVAL; + } + + /* calculate CTS */ + *cts = pclk*(*n/128)*deep_color / (sample_freq/10); + + return 0; +} + +static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdmi_audio_format audio_format; + struct hdmi_audio_dma audio_dma; + struct hdmi_core_audio_config core_cfg; + struct hdmi_core_infoframe_audio aud_if_cfg; + int err, n, cts; + enum hdmi_core_audio_sample_freq sample_freq; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + core_cfg.i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_20BITS; + core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; + core_cfg.i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_16; + core_cfg.i2s_cfg.justif = HDMI_AUDIO_JUSTIFY_LEFT; + audio_format.samples_p_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; + audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; + audio_format.justif = HDMI_AUDIO_JUSTIFY_LEFT; + audio_dma.transfer_size = 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + core_cfg.i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_24BITS; + core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; + core_cfg.i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_24; + audio_format.samples_p_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; + audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; + audio_format.justif = HDMI_AUDIO_JUSTIFY_RIGHT; + core_cfg.i2s_cfg.justif = HDMI_AUDIO_JUSTIFY_RIGHT; + audio_dma.transfer_size = 0x20; + break; + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 32000: + sample_freq = HDMI_AUDIO_FS_32000; + break; + case 44100: + sample_freq = HDMI_AUDIO_FS_44100; + break; + case 48000: + sample_freq = HDMI_AUDIO_FS_48000; + break; + default: + return -EINVAL; + } + + err = hdmi_config_audio_acr(params_rate(params), &n, &cts); + if (err < 0) + return err; + + /* audio wrapper config */ + audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; + audio_format.active_chnnls_msk = 0x03; + audio_format.type = HDMI_AUDIO_TYPE_LPCM; + audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; + audio_format.sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; + + audio_dma.block_size = 0xC0; + audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; + audio_dma.threshold = 0x20; + + hdmi_wp_audio_config_dma(&audio_dma); + hdmi_wp_audio_config_format(&audio_format); + + /* I2S config */ + core_cfg.i2s_cfg.en_high_br_aud = false; + core_cfg.i2s_cfg.sck_edge_mode = + HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_RISING; + core_cfg.i2s_cfg.cbit_order = false; + core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_PCM; + core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; + core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; + core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; + + /* core audio config */ + core_cfg.freq_sample = sample_freq; + core_cfg.n = n; + core_cfg.cts = cts; + if (omap_rev() == OMAP4430_REV_ES1_0) { + core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); + core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; + } else { + core_cfg.aud_par_busclk = 0; + core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; + } + core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; + core_cfg.use_mclk = false; + core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; + core_cfg.fs_override = true; + core_cfg.en_acr_pkt = true; + core_cfg.en_direct_strm_dig_aud = false; + core_cfg.en_parallel_aud = true; + core_cfg.en_spdif = false; + + hdmi_core_audio_config(&core_cfg); + + /* + * configure packet + * info frame audio see doc CEA861-D page 74 + */ + aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; + aud_if_cfg.db1_channel_count = 2; + aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; + aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; + aud_if_cfg.db4_channel_alloc = 0x00; + aud_if_cfg.db5_downmix_inh = false; + aud_if_cfg.db5_lsv = 0; + + hdmi_core_audio_infoframe_config(&aud_if_cfg); + return 0; +} + +static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int err = 0; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0); + REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31); + REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0); + REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30); + REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31); + break; + default: + err = -EINVAL; + } + return err; +} + +static struct snd_soc_codec_driver hdmi_audio_codec_drv = { +}; + +static struct snd_soc_dai_ops hdmi_audio_codec_ops = { + .hw_params = hdmi_audio_hw_params, + .trigger = hdmi_audio_trigger, +}; + +static struct snd_soc_dai_driver hdmi_codec_dai_drv = { + .name = "omap4-hdmi-audio-codec", + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &hdmi_audio_codec_ops, +}; +#endif + + /* HDMI HW IP initialisation */ static int omapdss_hdmihw_probe(struct platform_device *pdev) { struct resource *hdmi_mem; +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + int ret; + + /* Register ASoC codec DAI */ + ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, + &hdmi_codec_dai_drv, 1); + if (ret) { + DSSERR("can't register ASoC HDMI audio codec\n"); + return ret; + } +#endif + hdmi.pdata = pdev->dev.platform_data; hdmi.pdev = pdev; @@ -1307,6 +1700,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) { hdmi_panel_exit(); +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + snd_soc_unregister_codec(&pdev->dev); +#endif + iounmap(hdmi.base_wp); return 0; diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h index 9887ab96da3..6c79a57500b 100644 --- a/drivers/video/omap2/dss/hdmi.h +++ b/drivers/video/omap2/dss/hdmi.h @@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; }; #define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68) #define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C) #define HDMI_WP_WP_CLK HDMI_WP_REG(0x70) +#define HDMI_WP_AUDIO_CFG HDMI_WP_REG(0x80) +#define HDMI_WP_AUDIO_CFG2 HDMI_WP_REG(0x84) +#define HDMI_WP_AUDIO_CTRL HDMI_WP_REG(0x88) +#define HDMI_WP_AUDIO_DATA HDMI_WP_REG(0x8C) /* HDMI IP Core System */ #define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx) @@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; }; #define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15) #define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190) #define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27) +#define HDMI_CORE_AV_AUD_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x210) +#define HDMI_CORE_AV_AUD_DBYTE_NELEMS HDMI_CORE_AV_REG(10) #define HDMI_CORE_AV_MPEG_DBYTE HDMI_CORE_AV_REG(0x290) #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27) #define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300) @@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; }; #define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184) #define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188) #define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C) +#define HDMI_CORE_AV_AUDIO_TYPE HDMI_CORE_AV_REG(0x200) +#define HDMI_CORE_AV_AUDIO_VERS HDMI_CORE_AV_REG(0x204) +#define HDMI_CORE_AV_AUDIO_LEN HDMI_CORE_AV_REG(0x208) +#define HDMI_CORE_AV_AUDIO_CHSUM HDMI_CORE_AV_REG(0x20C) #define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280) #define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284) #define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288) @@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl { HDMI_PACKETREPEATOFF = 0 }; -/* INFOFRAME_AVI_ definitions */ +/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */ enum hdmi_core_infoframe { HDMI_INFOFRAME_AVI_DB1Y_RGB = 0, HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1, @@ -317,7 +327,36 @@ enum hdmi_core_infoframe { HDMI_INFOFRAME_AVI_DB5PR_7 = 6, HDMI_INFOFRAME_AVI_DB5PR_8 = 7, HDMI_INFOFRAME_AVI_DB5PR_9 = 8, - HDMI_INFOFRAME_AVI_DB5PR_10 = 9 + HDMI_INFOFRAME_AVI_DB5PR_10 = 9, + HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1, + HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2, + HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3, + HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4, + HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5, + HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6, + HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7, + HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8, + HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9, + HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10, + HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11, + HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12, + HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13, + HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14, + HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1, + HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2, + HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3, + HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4, + HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5, + HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6, + HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7, + HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1, + HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2, + HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3, + HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0, + HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1 }; enum hdmi_packing_mode { @@ -327,6 +366,117 @@ enum hdmi_packing_mode { HDMI_PACK_ALREADYPACKED = 7 }; +enum hdmi_core_audio_sample_freq { + HDMI_AUDIO_FS_32000 = 0x3, + HDMI_AUDIO_FS_44100 = 0x0, + HDMI_AUDIO_FS_48000 = 0x2, + HDMI_AUDIO_FS_88200 = 0x8, + HDMI_AUDIO_FS_96000 = 0xA, + HDMI_AUDIO_FS_176400 = 0xC, + HDMI_AUDIO_FS_192000 = 0xE, + HDMI_AUDIO_FS_NOT_INDICATED = 0x1 +}; + +enum hdmi_core_audio_layout { + HDMI_AUDIO_LAYOUT_2CH = 0, + HDMI_AUDIO_LAYOUT_8CH = 1 +}; + +enum hdmi_core_cts_mode { + HDMI_AUDIO_CTS_MODE_HW = 0, + HDMI_AUDIO_CTS_MODE_SW = 1 +}; + +enum hdmi_stereo_channels { + HDMI_AUDIO_STEREO_NOCHANNELS = 0, + HDMI_AUDIO_STEREO_ONECHANNEL = 1, + HDMI_AUDIO_STEREO_TWOCHANNELS = 2, + HDMI_AUDIO_STEREO_THREECHANNELS = 3, + HDMI_AUDIO_STEREO_FOURCHANNELS = 4 +}; + +enum hdmi_audio_type { + HDMI_AUDIO_TYPE_LPCM = 0, + HDMI_AUDIO_TYPE_IEC = 1 +}; + +enum hdmi_audio_justif { + HDMI_AUDIO_JUSTIFY_LEFT = 0, + HDMI_AUDIO_JUSTIFY_RIGHT = 1 +}; + +enum hdmi_audio_sample_order { + HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0, + HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1 +}; + +enum hdmi_audio_samples_perword { + HDMI_AUDIO_ONEWORD_ONESAMPLE = 0, + HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1 +}; + +enum hdmi_audio_sample_size { + HDMI_AUDIO_SAMPLE_16BITS = 0, + HDMI_AUDIO_SAMPLE_24BITS = 1 +}; + +enum hdmi_audio_transf_mode { + HDMI_AUDIO_TRANSF_DMA = 0, + HDMI_AUDIO_TRANSF_IRQ = 1 +}; + +enum hdmi_audio_blk_strt_end_sig { + HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0, + HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1 +}; + +enum hdmi_audio_i2s_config { + HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0, + HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1, + HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, + HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, + HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0, + HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1, + HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0, + HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1, + HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6, + HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2, + HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4, + HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5, + HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1, + HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6, + HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2, + HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4, + HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5, + HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_FALLING = 0, + HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_RISING = 1, + HDMI_AUDIO_I2S_VBIT_PCM = 0, + HDMI_AUDIO_I2S_VBIT_COMPRESSED = 1, + HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0, + HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2, + HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12, + HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4, + HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8, + HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10, + HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13, + HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5, + HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9, + HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11, + HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, + HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1 +}; + +enum hdmi_audio_mclk_mode { + HDMI_AUDIO_MCLK_128FS = 0, + HDMI_AUDIO_MCLK_256FS = 1, + HDMI_AUDIO_MCLK_384FS = 2, + HDMI_AUDIO_MCLK_512FS = 3, + HDMI_AUDIO_MCLK_768FS = 4, + HDMI_AUDIO_MCLK_1024FS = 5, + HDMI_AUDIO_MCLK_1152FS = 6, + HDMI_AUDIO_MCLK_192FS = 7 +}; + struct hdmi_core_video_config { enum hdmi_core_inputbus_width ip_bus_width; enum hdmi_core_dither_trunc op_dither_truc; @@ -376,6 +526,26 @@ struct hdmi_core_infoframe_avi { u16 db12_13_pixel_sofright; /* Pixel number start of right bar */ }; +/* + * Refer to section 8.2 in HDMI 1.3 specification for + * details about infoframe databytes + */ +struct hdmi_core_infoframe_audio { + u8 db1_coding_type; + /* Audio coding type */ + u8 db1_channel_count; + /* Number of channels */ + u8 db2_sample_freq; + /* Sample frequency */ + u8 db2_sample_size; + /* Sample size */ + u8 db4_channel_alloc; + /* Channel allocation code */ + bool db5_downmix_inh; + /* Downmix inhibit flag */ + u8 db5_lsv; + /* Level shift values for downmix */ +}; struct hdmi_core_packet_enable_repeat { u32 audio_pkt; @@ -412,4 +582,52 @@ struct hdmi_config { struct hdmi_cm cm; }; +struct hdmi_audio_format { + enum hdmi_stereo_channels stereo_channels; + u8 active_chnnls_msk; + enum hdmi_audio_type type; + enum hdmi_audio_justif justif; + enum hdmi_audio_sample_order sample_order; + enum hdmi_audio_samples_perword samples_p_word; + enum hdmi_audio_sample_size sample_size; + enum hdmi_audio_blk_strt_end_sig sig_blk_strt_end; +}; + +struct hdmi_audio_dma { + u8 transfer_size; + u8 block_size; + enum hdmi_audio_transf_mode mode; + u16 threshold; +}; + +struct hdmi_core_audio_i2s_config { + u8 word_max_length; + u8 word_length; + u8 in_length_bits; + u8 justif; + u8 en_high_br_aud; + u8 sck_edge_mode; + u8 cbit_order; + u8 vbit; + u8 ws_polarity; + u8 direction; + u8 shift; +}; + +struct hdmi_core_audio_config { + struct hdmi_core_audio_i2s_config i2s_cfg; + enum hdmi_core_audio_sample_freq freq_sample; + bool fs_override; + u32 n; + u32 cts; + u32 aud_par_busclk; + enum hdmi_core_audio_layout layout; + enum hdmi_core_cts_mode cts_mode; + bool use_mclk; + enum hdmi_audio_mclk_mode mclk_mode; + bool en_acr_pkt; + bool en_direct_strm_dig_aud; + bool en_parallel_aud; + bool en_spdif; +}; #endif diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 8e35a5bae42..43009e57cd3 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -769,16 +769,10 @@ static struct platform_driver omap_venchw_driver = { int venc_init_platform_driver(void) { - if (cpu_is_omap44xx()) - return 0; - return platform_driver_register(&omap_venchw_driver); } void venc_uninit_platform_driver(void) { - if (cpu_is_omap44xx()) - return; - return platform_driver_unregister(&omap_venchw_driver); } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505ec667204..2bd90ca93d6 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -29,6 +29,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/omapfb.h> +#include <linux/console.h> #include <plat/display.h> #include <plat/vram.h> @@ -1902,6 +1903,94 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) kfree(fbdev); } +static void size_notify(struct fb_info *fbi, int w, int h) +{ + struct omapfb_info *ofbi = FB2OFB(fbi); + struct fb_var_screeninfo var = fbi->var; + struct fb_var_screeninfo saved_var = fbi->var; + int orig_flags; + int new_size = (w * var.bits_per_pixel >> 3) * h; + + DBG("size_notify: %dx%d\n", w, h); + + var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_ALL | FB_ACTIVATE_NOW; + var.xres = w; + var.yres = h; + var.xres_virtual = w; + var.yres_virtual = h; + + console_lock(); + + /* Try to increase memory allocated for FB, if needed */ + if (new_size > ofbi->region->size) { + DBG("re-allocating FB - old size: %ld - new size: %d\n", ofbi->region->size, new_size); + omapfb_get_mem_region(ofbi->region); + omapfb_realloc_fbmem(fbi, new_size, 0); + omapfb_put_mem_region(ofbi->region); + } + + /* this ensures fbdev clients, like the console driver, get notified about + * the change: + */ + orig_flags = fbi->flags; + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(fbi, &var); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + + /* now delete old mode: + */ + saved_var.activate |= FB_ACTIVATE_INV_MODE; + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(fbi, &saved_var); + fbi->flags = orig_flags; + + console_unlock(); +} + +struct omapfb_notifier_block { + struct notifier_block notifier; + struct omapfb2_device *fbdev; +}; + +static int omapfb_notifier(struct notifier_block *nb, + unsigned long evt, void *arg) +{ + struct omapfb_notifier_block *notifier = + container_of(nb, struct omapfb_notifier_block, notifier); + struct omap_dss_device *dssdev = arg; + struct omapfb2_device *fbdev = notifier->fbdev; + int keep = false; + int i; + + /* figure out if this event pertains to this omapfb device: + */ + for (i = 0; i < fbdev->num_managers; i++) { + if (fbdev->managers[i]->device == dssdev) { + keep = true; + break; + } + } + + if (!keep) + return NOTIFY_DONE; + + /* the event pertains to us.. see if we care: + */ + switch (evt) { + case OMAP_DSS_SIZE_CHANGE: { + u16 w, h; + dssdev->driver->get_resolution(dssdev, &w, &h); + for (i = 0; i < fbdev->num_fbs; i++) + size_notify(fbdev->fbs[i], w, h); + break; + } + default: /* don't care about other events for now */ + break; + } + + return NOTIFY_OK; +} + static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) { int r, i; @@ -2227,6 +2316,7 @@ static int omapfb_probe(struct platform_device *pdev) fbdev->num_displays = 0; dssdev = NULL; for_each_dss_dev(dssdev) { + struct omapfb_notifier_block *notifier; omap_dss_get_device(dssdev); if (!dssdev->driver) { @@ -2235,7 +2325,12 @@ static int omapfb_probe(struct platform_device *pdev) } fbdev->displays[fbdev->num_displays++] = dssdev; - } + + notifier = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL); + notifier->notifier.notifier_call = omapfb_notifier; + notifier->fbdev = fbdev; + omap_dss_add_notify(dssdev, ¬ifier->notifier); + } if (r) goto cleanup; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 348843b8015..5edb34458d7 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -896,7 +896,7 @@ struct drm_driver { int num_ioctls; struct file_operations fops; struct pci_driver pci_driver; - struct platform_device *platform_device; + struct platform_driver platform_driver; /* List of devices hanging off this driver */ struct list_head device_list; }; @@ -1656,6 +1656,8 @@ static inline void *drm_get_device(struct drm_device *dev) extern int drm_platform_init(struct drm_driver *driver); extern int drm_pci_init(struct drm_driver *driver); +extern void drm_platform_exit(struct drm_driver *driver); +extern void drm_pci_exit(struct drm_driver *driver); extern int drm_fill_in_dev(struct drm_device *dev, const struct pci_device_id *ent, struct drm_driver *driver); diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a088db6d509..ab12c5e7511 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -107,6 +107,15 @@ config SND_OMAP_SOC_SDP4430 Say Y if you want to add support for SoC audio on Texas Instruments SDP4430. +config SND_OMAP_SOC_OMAP4_HDMI + tristate "SoC Audio support for Texas Instruments SDP4430 or Panda HDMI port" + depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS + depends on (MACH_OMAP_4430SDP || MACH_OMAP4_PANDA) + select SND_OMAP_SOC_HDMI + help + Say Y if you want to add support for SoC HDMI audio on Texas Instruments + SDP4430 or Panda + config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index ba9fc650db2..de364aeac17 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -22,6 +22,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o snd-soc-igep0020-objs := igep0020.o +snd-soc-omap4-hdmi-objs := omap-hdmi.o omap4-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o @@ -37,3 +38,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c new file mode 100644 index 00000000000..e19f062788c --- /dev/null +++ b/sound/soc/omap/omap-hdmi.c @@ -0,0 +1,150 @@ +/* + * omap-hdmi.c + * + * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Jorge Candelaria <jorge.candelaria@gmail.com> + * Ricardo Neri <ricardo.neri@ti.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. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <plat/dma.h> +#include <plat/display.h> +#include <plat/omap44xx.h> +#include "omap-pcm.h" +#include "omap-hdmi.h" + +static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { + .name = "HDMI playback", + .dma_req = OMAP44XX_DMA_DSS_HDMI_REQ, + .port_addr = OMAP44XX_DSS_HDMI_L3_BASE + OMAP44XX_HDMI_AUDIO_DMA_PORT, + .sync_mode = OMAP_DMA_SYNC_PACKET, +}; + +static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int err = 0, i; + struct omap_overlay *ovl = NULL; + + /* + * Make sure that the period bytes are multiple of the DMA packet size. + * Largest packet size we use is 32 32-bit words = 128 bytes + */ + err = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); + if (err < 0) + return err; + + /* find DSS HDMI device */ + for (i = 0; i < omap_dss_get_num_overlays(); i++) { + ovl = omap_dss_get_overlay(i); + if (strcmp(ovl->manager->device->name, "hdmi") == 0) + break; + } + if (ovl->manager->device->state != OMAP_DSS_DISPLAY_ACTIVE) { + printk(KERN_ERR "HDMI display is not active!"); + return -EIO; + } + return err; +} + +static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int err = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; + omap_hdmi_dai_dma_params.packet_size = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; + omap_hdmi_dai_dma_params.packet_size = 32; + break; + default: + err = -EINVAL; + } + + snd_soc_dai_set_dma_data(dai, substream, + &omap_hdmi_dai_dma_params); + + return err; +} + +static struct snd_soc_dai_ops omap_hdmi_dai_ops = { + .startup = omap_hdmi_dai_startup, + .hw_params = omap_hdmi_dai_hw_params, +}; + +static struct snd_soc_dai_driver omap_hdmi_dai = { + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = OMAP_HDMI_RATES, + .formats = OMAP_HDMI_FORMATS, + }, + .ops = &omap_hdmi_dai_ops, +}; + +static __devinit int omap_hdmi_probe(struct platform_device *pdev) +{ + return snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); +} + +static int __devexit omap_hdmi_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dai(&pdev->dev); + return 0; +} + +static struct platform_driver hdmi_dai_driver = { + .driver = { + .name = "hdmi-audio-dai", + .owner = THIS_MODULE, + }, + .probe = omap_hdmi_probe, + .remove = __devexit_p(omap_hdmi_remove), +}; + +static int __init hdmi_dai_init(void) +{ + return platform_driver_register(&hdmi_dai_driver); +} +module_init(hdmi_dai_init); + +static void __exit hdmi_dai_exit(void) +{ + platform_driver_unregister(&hdmi_dai_driver); +} +module_exit(hdmi_dai_exit); + +MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@gmail.com>"); +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); +MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h new file mode 100644 index 00000000000..77bc7851f37 --- /dev/null +++ b/sound/soc/omap/omap-hdmi.h @@ -0,0 +1,36 @@ +/* + * omap-hdmi.h + * + * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Autors: Jorge Candelaria <jorge.candelaria@gmail.com> + * Ricardo Neri <ricardo.neri@ti.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. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __OMAP_HDMI_H__ +#define __OMAP_HDMI_H__ + +#define OMAP44XX_HDMI_AUDIO_DMA_PORT 0x8c + +#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#endif diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c new file mode 100644 index 00000000000..b5cf1502bf8 --- /dev/null +++ b/sound/soc/omap/omap4-hdmi-card.c @@ -0,0 +1,89 @@ +/* + * sdp4430-hdmi.c + * + * OMAP ALSA SoC machine driver for TI OMAP4 HDMI + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Ricardo Neri <ricardo.neri@ti.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. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <sound/pcm.h> +#include <sound/soc.h> +#include <asm/mach-types.h> + +#define OMAP4_HDMI_SND_DEV_ID 0 + +static struct snd_soc_dai_link omap4_hdmi_dai = { + .name = "HDMI", + .stream_name = "HDMI", + .cpu_dai_name = "hdmi-audio-dai", + .platform_name = "omap-pcm-audio", + .codec_name = "omapdss_hdmi", + .codec_dai_name = "omap4-hdmi-audio-codec" +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_omap4_hdmi = { + .name = "SDP4430HDMI", + /* .long_name = "TI OMAP4 HDMI Board", */ + .dai_link = &omap4_hdmi_dai, + .num_links = 1, +}; + +static struct platform_device *omap4_hdmi_snd_device; + +static int __init omap4_hdmi_soc_init(void) +{ + int ret; + + if (!(machine_is_omap_4430sdp() || machine_is_omap4_panda())) + return -ENODEV; + printk(KERN_INFO "OMAP4 HDMI audio SoC init\n"); + + if (machine_is_omap4_panda()) + snd_soc_omap4_hdmi.name = "PandaHDMI"; + + omap4_hdmi_snd_device = platform_device_alloc("soc-audio", + OMAP4_HDMI_SND_DEV_ID); + if (!omap4_hdmi_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap4_hdmi_snd_device, &snd_soc_omap4_hdmi); + + ret = platform_device_add(omap4_hdmi_snd_device); + if (ret) + goto err; + + return 0; +err: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap4_hdmi_snd_device); + return ret; +} +module_init(omap4_hdmi_soc_init); + +static void __exit omap4_hdmi_soc_exit(void) +{ + platform_device_unregister(omap4_hdmi_snd_device); +} +module_exit(omap4_hdmi_soc_exit); + +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); +MODULE_DESCRIPTION("ALSA SoC OMAP4 HDMI AUDIO"); +MODULE_LICENSE("GPL"); |