From f31105347cc56c13d552b844ada04418769d875d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Apr 2015 12:17:50 +0200 Subject: irqchip: irqc: Remove platform data support As of commit 914d7d148411997c ("ARM: shmobile: r8a73a4: Remove legacy code"), the Renesas R-Mobile/R-Car interrupt controller is used with DT only, and interrupt numbers are thus always assigned automatically. Drop the platform data declaration and all related support code. Signed-off-by: Geert Uytterhoeven Cc: Magnus Damm Cc: Jason Cooper Link: http://lkml.kernel.org/r/1430216270-31929-1-git-send-email-geert%2Brenesas@glider.be Signed-off-by: Thomas Gleixner --- include/linux/platform_data/irq-renesas-irqc.h | 27 -------------------------- 1 file changed, 27 deletions(-) delete mode 100644 include/linux/platform_data/irq-renesas-irqc.h (limited to 'include/linux/platform_data') diff --git a/include/linux/platform_data/irq-renesas-irqc.h b/include/linux/platform_data/irq-renesas-irqc.h deleted file mode 100644 index 3ae17b3e00ed..000000000000 --- a/include/linux/platform_data/irq-renesas-irqc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Renesas IRQC Driver - * - * Copyright (C) 2013 Magnus Damm - * - * 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 - * - * 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 __IRQ_RENESAS_IRQC_H__ -#define __IRQ_RENESAS_IRQC_H__ - -struct renesas_irqc_config { - unsigned int irq_base; -}; - -#endif /* __IRQ_RENESAS_IRQC_H__ */ -- cgit v1.2.3-71-gd317 From cac089f9026e9ddb3481daf08f0fc4e5949fa1af Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 23 Apr 2015 16:56:22 -0700 Subject: gpio: omap: Allow building as a loadable module We currently get all kinds of errors building the omap gpio driver as a module starting with: undefined reference to `omap2_gpio_resume_after_idle' undefined reference to `omap2_gpio_prepare_for_idle' ... Let's fix the issue by adding inline functions to the header. Note that we can now also remove the two unused functions for omap_set_gpio_debounce and omap_set_gpio_debounce_time. Then doing rmmod on the module produces further warnings because of missing exit related functions. Let's add those. And finally, we can make the Kconfig entry just a tristate option that's selected for omaps. Cc: Javier Martinez Canillas Cc: Kevin Hilman Cc: Nishanth Menon Signed-off-by: Tony Lindgren Reviewed-by: Grygorii Strashko Acked-by: Santosh Shilimkar Reviewed-by: Felipe Balbi Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-omap.c | 24 ++++++++++++++++++++++++ include/linux/platform_data/gpio-omap.h | 12 ++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) (limited to 'include/linux/platform_data') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c2211258231b..4c4dba075277 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -316,7 +316,7 @@ config GPIO_OCTEON family of SOCs. config GPIO_OMAP - bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS + tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST default y if ARCH_OMAP depends on ARM select GENERIC_IRQ_CHIP diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index cd1d5bf48f36..38c268fb7ba8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1263,6 +1263,17 @@ static int omap_gpio_probe(struct platform_device *pdev) return 0; } +static int omap_gpio_remove(struct platform_device *pdev) +{ + struct gpio_bank *bank = platform_get_drvdata(pdev); + + list_del(&bank->node); + gpiochip_remove(&bank->chip); + pm_runtime_disable(bank->dev); + + return 0; +} + #ifdef CONFIG_ARCH_OMAP2PLUS #if defined(CONFIG_PM) @@ -1448,6 +1459,7 @@ static int omap_gpio_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +#if IS_BUILTIN(CONFIG_GPIO_OMAP) void omap2_gpio_prepare_for_idle(int pwr_mode) { struct gpio_bank *bank; @@ -1473,6 +1485,7 @@ void omap2_gpio_resume_after_idle(void) pm_runtime_get_sync(bank->dev); } } +#endif #if defined(CONFIG_PM) static void omap_gpio_init_context(struct gpio_bank *p) @@ -1628,6 +1641,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match); static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, + .remove = omap_gpio_remove, .driver = { .name = "omap_gpio", .pm = &gpio_pm_ops, @@ -1645,3 +1659,13 @@ static int __init omap_gpio_drv_reg(void) return platform_driver_register(&omap_gpio_driver); } postcore_initcall(omap_gpio_drv_reg); + +static void __exit omap_gpio_exit(void) +{ + platform_driver_unregister(&omap_gpio_driver); +} +module_exit(omap_gpio_exit); + +MODULE_DESCRIPTION("omap gpio driver"); +MODULE_ALIAS("platform:gpio-omap"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h index 5d50b25a73d7..cb2618147c34 100644 --- a/include/linux/platform_data/gpio-omap.h +++ b/include/linux/platform_data/gpio-omap.h @@ -208,9 +208,17 @@ struct omap_gpio_platform_data { int (*get_context_loss_count)(struct device *dev); }; +#if IS_BUILTIN(CONFIG_GPIO_OMAP) extern void omap2_gpio_prepare_for_idle(int off_mode); extern void omap2_gpio_resume_after_idle(void); -extern void omap_set_gpio_debounce(int gpio, int enable); -extern void omap_set_gpio_debounce_time(int gpio, int enable); +#else +static inline void omap2_gpio_prepare_for_idle(int off_mode) +{ +} + +static inline void omap2_gpio_resume_after_idle(void) +{ +} +#endif #endif -- cgit v1.2.3-71-gd317 From 385f83f85cd9428db82cae5e6f6f786be113b24c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Apr 2015 12:21:40 +0200 Subject: dmaengine: Remove Renesas Audio DMAC peri peri platform data Commit 3cd44dcd35a6 ("dmaengine: remove Renesas Audio DMAC peri peri") forgot to remove the header file with the platform data definitions. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Vinod Koul --- include/linux/platform_data/dma-rcar-audmapp.h | 34 -------------------------- 1 file changed, 34 deletions(-) delete mode 100644 include/linux/platform_data/dma-rcar-audmapp.h (limited to 'include/linux/platform_data') diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h deleted file mode 100644 index 471fffebbeb4..000000000000 --- a/include/linux/platform_data/dma-rcar-audmapp.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This is for Renesas R-Car Audio-DMAC-peri-peri. - * - * Copyright (C) 2014 Renesas Electronics Corporation - * Copyright (C) 2014 Kuninori Morimoto - * - * This file is based on the include/linux/sh_dma.h - * - * Header for the new SH dmaengine driver - * - * Copyright (C) 2010 Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef SH_AUDMAPP_H -#define SH_AUDMAPP_H - -#include - -struct audmapp_slave_config { - int slave_id; - dma_addr_t src; - dma_addr_t dst; - u32 chcr; -}; - -struct audmapp_pdata { - struct audmapp_slave_config *slave; - int slave_num; -}; - -#endif /* SH_AUDMAPP_H */ -- cgit v1.2.3-71-gd317 From 34ef33f7da6b00900d3a896d33522a035a930245 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Apr 2015 14:04:07 +0200 Subject: usb: phy: Remove the phy-rcar-gen2-usb driver The phy-rcar-gen2-usb driver, which supports legacy platform data only, is no longer used since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"). This driver was superseded by the DT-only phy-rcar-gen2 driver, which was introduced in commit 1233f59f745b237d ("phy: Renesas R-Car Gen2 PHY driver"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/Kconfig | 13 -- drivers/usb/phy/Makefile | 1 - drivers/usb/phy/phy-rcar-gen2-usb.c | 246 ------------------------ include/linux/platform_data/usb-rcar-gen2-phy.h | 22 --- 4 files changed, 282 deletions(-) delete mode 100644 drivers/usb/phy/phy-rcar-gen2-usb.c delete mode 100644 include/linux/platform_data/usb-rcar-gen2-phy.h (limited to 'include/linux/platform_data') diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 2175678e674e..3cd3bee54ca6 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -186,19 +186,6 @@ config USB_RCAR_PHY To compile this driver as a module, choose M here: the module will be called phy-rcar-usb. -config USB_RCAR_GEN2_PHY - tristate "Renesas R-Car Gen2 USB PHY support" - depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST - select USB_PHY - help - Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver. - It is typically used to control internal USB PHY for USBHS, - and to configure shared USB channels 0 and 2. - This driver supports R8A7790 and R8A7791. - - To compile this driver as a module, choose M here: the - module will be called phy-rcar-gen2-usb. - config USB_ULPI bool "Generic ULPI Transceiver Driver" depends on ARM || ARM64 diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 75f2bba58c84..e36ab1d46d8b 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o -obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c deleted file mode 100644 index f81800b6562a..000000000000 --- a/drivers/usb/phy/phy-rcar-gen2-usb.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Renesas R-Car Gen2 USB phy driver - * - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct rcar_gen2_usb_phy_priv { - struct usb_phy phy; - void __iomem *base; - struct clk *clk; - spinlock_t lock; - int usecount; - u32 ugctrl2; -}; - -#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy) - -/* Low Power Status register */ -#define USBHS_LPSTS_REG 0x02 -#define USBHS_LPSTS_SUSPM (1 << 14) - -/* USB General control register */ -#define USBHS_UGCTRL_REG 0x80 -#define USBHS_UGCTRL_CONNECT (1 << 2) -#define USBHS_UGCTRL_PLLRESET (1 << 0) - -/* USB General control register 2 */ -#define USBHS_UGCTRL2_REG 0x84 -#define USBHS_UGCTRL2_USB0_PCI (1 << 4) -#define USBHS_UGCTRL2_USB0_HS (3 << 4) -#define USBHS_UGCTRL2_USB2_PCI (0 << 31) -#define USBHS_UGCTRL2_USB2_SS (1 << 31) - -/* USB General status register */ -#define USBHS_UGSTS_REG 0x88 -#define USBHS_UGSTS_LOCK (1 << 8) - -/* Enable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_enable(void __iomem *base) -{ - u32 val; - int i; - - /* USBHS PHY power on */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val |= USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - for (i = 0; i < 20; i++) { - val = ioread32(base + USBHS_UGSTS_REG); - if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; - } - udelay(1); - } - - /* Timed out waiting for the PLL lock */ - return -ETIMEDOUT; -} - -/* Disable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_disable(void __iomem *base) -{ - u32 val; - - /* USBHS PHY power off */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val &= ~USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; -} - -/* Setup USB channels */ -static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) -{ - u32 val; - - clk_prepare_enable(priv->clk); - - /* Set USB channels in the USBHS UGCTRL2 register */ - val = ioread32(priv->base + USBHS_UGCTRL2_REG); - val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); - val |= priv->ugctrl2; - iowrite32(val, priv->base + USBHS_UGCTRL2_REG); -} - -/* Shutdown USB channels */ -static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv) -{ - __rcar_gen2_usbhs_phy_disable(priv->base); - clk_disable_unprepare(priv->clk); -} - -static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - int retval; - - spin_lock_irqsave(&priv->lock, flags); - retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) : - __rcar_gen2_usbhs_phy_enable(priv->base); - spin_unlock_irqrestore(&priv->lock, flags); - return retval; -} - -static int rcar_gen2_usb_phy_init(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - /* - * Enable the clock and setup USB channels - * if it's the first user - */ - if (!priv->usecount++) - __rcar_gen2_usb_phy_init(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; -} - -static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!priv->usecount) { - dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n"); - goto out; - } - - /* Disable everything if it's the last user */ - if (!--priv->usecount) - __rcar_gen2_usb_phy_shutdown(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct rcar_gen2_phy_platform_data *pdata; - struct rcar_gen2_usb_phy_priv *priv; - struct resource *res; - void __iomem *base; - struct clk *clk; - int retval; - - pdata = dev_get_platdata(dev); - if (!pdata) { - dev_err(dev, "No platform data\n"); - return -EINVAL; - } - - clk = devm_clk_get(dev, "usbhs"); - if (IS_ERR(clk)) { - dev_err(dev, "Can't get the clock\n"); - return PTR_ERR(clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - spin_lock_init(&priv->lock); - priv->clk = clk; - priv->base = base; - priv->ugctrl2 = pdata->chan0_pci ? - USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS; - priv->ugctrl2 |= pdata->chan2_pci ? - USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS; - priv->phy.dev = dev; - priv->phy.label = dev_name(dev); - priv->phy.init = rcar_gen2_usb_phy_init; - priv->phy.shutdown = rcar_gen2_usb_phy_shutdown; - priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend; - - retval = usb_add_phy_dev(&priv->phy); - if (retval < 0) { - dev_err(dev, "Failed to add USB phy\n"); - return retval; - } - - platform_set_drvdata(pdev, priv); - - return retval; -} - -static int rcar_gen2_usb_phy_remove(struct platform_device *pdev) -{ - struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev); - - usb_remove_phy(&priv->phy); - - return 0; -} - -static struct platform_driver rcar_gen2_usb_phy_driver = { - .driver = { - .name = "usb_phy_rcar_gen2", - }, - .probe = rcar_gen2_usb_phy_probe, - .remove = rcar_gen2_usb_phy_remove, -}; - -module_platform_driver(rcar_gen2_usb_phy_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy"); -MODULE_AUTHOR("Valentine Barshak "); diff --git a/include/linux/platform_data/usb-rcar-gen2-phy.h b/include/linux/platform_data/usb-rcar-gen2-phy.h deleted file mode 100644 index dd3ba46c0d90..000000000000 --- a/include/linux/platform_data/usb-rcar-gen2-phy.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __USB_RCAR_GEN2_PHY_H -#define __USB_RCAR_GEN2_PHY_H - -#include - -struct rcar_gen2_phy_platform_data { - /* USB channel 0 configuration */ - bool chan0_pci:1; /* true: PCI USB host 0, false: USBHS */ - /* USB channel 2 configuration */ - bool chan2_pci:1; /* true: PCI USB host 2, false: USBSS */ -}; - -#endif -- cgit v1.2.3-71-gd317 From 25d238b2260973bfca0b82181824340c7aeae45a Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Fri, 22 May 2015 09:58:30 -0700 Subject: Input: update email-id of Rajeev Kumar rajeev-dlh.kumar@st.com email-id doesn't exist anymore as I have left the company. Signed-off-by: Rajeev Kumar Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spear-keyboard.c | 2 +- include/linux/platform_data/keyboard-spear.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux/platform_data') diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index f42a543db043..623d451767e3 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -3,7 +3,7 @@ * Based on omap-keypad driver * * Copyright (C) 2010 ST Microelectronics - * Rajeev Kumar + * Rajeev Kumar * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any diff --git a/include/linux/platform_data/keyboard-spear.h b/include/linux/platform_data/keyboard-spear.h index 9248e3a7e333..5e3ff653900c 100644 --- a/include/linux/platform_data/keyboard-spear.h +++ b/include/linux/platform_data/keyboard-spear.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 ST Microelectronics - * Rajeev Kumar + * Rajeev Kumar * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any -- cgit v1.2.3-71-gd317 From 887ee43477e4e327dbcd2aabc2d78a5116ed8a33 Mon Sep 17 00:00:00 2001 From: Beomho Seo Date: Thu, 30 Apr 2015 13:07:43 +0900 Subject: hwmon: (ntc_thermistor) Add support for ncpXXwf104 This patch adds support for the ntc thermistor NCPXXWF104 series. Cc: Jean Delvare Cc: Guenter Roeck Signed-off-by: Beomho Seo Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ntc_thermistor.txt | 1 + Documentation/hwmon/ntc_thermistor | 6 ++- drivers/hwmon/Kconfig | 4 +- drivers/hwmon/ntc_thermistor.c | 44 ++++++++++++++++++++++ include/linux/platform_data/ntc_thermistor.h | 1 + 5 files changed, 52 insertions(+), 4 deletions(-) (limited to 'include/linux/platform_data') diff --git a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt index fcca8e744f41..a04a80f9cc70 100644 --- a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt +++ b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt @@ -9,6 +9,7 @@ Requires node properties: "murata,ncp21wb473" "murata,ncp03wb473" "murata,ncp15wl333" + "murata,ncp03wf104" /* Usage of vendor name "ntc" is deprecated */ "ntc,ncp15wb473" diff --git a/Documentation/hwmon/ntc_thermistor b/Documentation/hwmon/ntc_thermistor index c5e05e2900a3..1d4cc847c6fe 100644 --- a/Documentation/hwmon/ntc_thermistor +++ b/Documentation/hwmon/ntc_thermistor @@ -2,8 +2,10 @@ Kernel driver ntc_thermistor ================= Supported thermistors from Murata: -* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333 - Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', 'ncp15wl333' +* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, + NCP15WL333, NCP03WF104 + Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', + 'ncp15wl333', 'ncp03wf104' Datasheet: Publicly available at Murata Supported thermistors from EPCOS: diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 25d9e72627e9..4542ffc5468a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1106,8 +1106,8 @@ config SENSORS_NTC_THERMISTOR send notifications about the temperature. Currently, this driver supports - NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333 - from Murata and B57330V2103 from EPCOS. + NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333, + and NCP03WF104 from Murata and B57330V2103 from EPCOS. This driver can also be built as a module. If so, the module will be called ntc-thermistor. diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 68800115876b..fca92912269e 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -53,6 +53,7 @@ static const struct platform_device_id ntc_thermistor_id[] = { { "ncp03wb473", TYPE_NCPXXWB473 }, { "ncp15wl333", TYPE_NCPXXWL333 }, { "b57330v2103", TYPE_B57330V2103}, + { "ncp03wf104", TYPE_NCPXXWF104 }, { }, }; @@ -135,6 +136,43 @@ static const struct ntc_compensation ncpXXwl333[] = { { .temp_c = 125, .ohm = 707 }, }; +static const struct ntc_compensation ncpXXwf104[] = { + { .temp_c = -40, .ohm = 4397119 }, + { .temp_c = -35, .ohm = 3088599 }, + { .temp_c = -30, .ohm = 2197225 }, + { .temp_c = -25, .ohm = 1581881 }, + { .temp_c = -20, .ohm = 1151037 }, + { .temp_c = -15, .ohm = 846579 }, + { .temp_c = -10, .ohm = 628988 }, + { .temp_c = -5, .ohm = 471632 }, + { .temp_c = 0, .ohm = 357012 }, + { .temp_c = 5, .ohm = 272500 }, + { .temp_c = 10, .ohm = 209710 }, + { .temp_c = 15, .ohm = 162651 }, + { .temp_c = 20, .ohm = 127080 }, + { .temp_c = 25, .ohm = 100000 }, + { .temp_c = 30, .ohm = 79222 }, + { .temp_c = 35, .ohm = 63167 }, + { .temp_c = 40, .ohm = 50677 }, + { .temp_c = 45, .ohm = 40904 }, + { .temp_c = 50, .ohm = 33195 }, + { .temp_c = 55, .ohm = 27091 }, + { .temp_c = 60, .ohm = 22224 }, + { .temp_c = 65, .ohm = 18323 }, + { .temp_c = 70, .ohm = 15184 }, + { .temp_c = 75, .ohm = 12635 }, + { .temp_c = 80, .ohm = 10566 }, + { .temp_c = 85, .ohm = 8873 }, + { .temp_c = 90, .ohm = 7481 }, + { .temp_c = 95, .ohm = 6337 }, + { .temp_c = 100, .ohm = 5384 }, + { .temp_c = 105, .ohm = 4594 }, + { .temp_c = 110, .ohm = 3934 }, + { .temp_c = 115, .ohm = 3380 }, + { .temp_c = 120, .ohm = 2916 }, + { .temp_c = 125, .ohm = 2522 }, +}; + /* * The following compensation table is from the specification of EPCOS NTC * Thermistors Datasheet @@ -219,6 +257,8 @@ static const struct of_device_id ntc_match[] = { .data = &ntc_thermistor_id[4] }, { .compatible = "epcos,b57330v2103", .data = &ntc_thermistor_id[5]}, + { .compatible = "murata,ncp03wf104", + .data = &ntc_thermistor_id[6] }, /* Usage of vendor name "ntc" is deprecated */ { .compatible = "ntc,ncp15wb473", @@ -567,6 +607,10 @@ static int ntc_thermistor_probe(struct platform_device *pdev) data->comp = b57330v2103; data->n_comp = ARRAY_SIZE(b57330v2103); break; + case TYPE_NCPXXWF104: + data->comp = ncpXXwf104; + data->n_comp = ARRAY_SIZE(ncpXXwf104); + break; default: dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n", pdev_id->driver_data, pdev_id->name); diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h index 0a6de4ca4930..aed170588b74 100644 --- a/include/linux/platform_data/ntc_thermistor.h +++ b/include/linux/platform_data/ntc_thermistor.h @@ -27,6 +27,7 @@ enum ntc_thermistor_type { TYPE_NCPXXWB473, TYPE_NCPXXWL333, TYPE_B57330V2103, + TYPE_NCPXXWF104, }; struct ntc_thermistor_platform_data { -- cgit v1.2.3-71-gd317 From ed06aeefdac348cfb91a3db5fe1067e3202afd70 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 9 Jun 2015 22:26:05 +0200 Subject: nfc: st-nci: Rename st21nfcb to st-nci STMicroelectronics NFC NCI chips family is extending with the new ST21NFCC using the AMS AS39230 RF booster. The st21nfcb driver is relevant for this solution and might be with future products. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/st-nci.txt | 33 + .../devicetree/bindings/net/nfc/st21nfcb.txt | 33 - drivers/nfc/Kconfig | 2 +- drivers/nfc/Makefile | 2 +- drivers/nfc/st-nci/Kconfig | 23 + drivers/nfc/st-nci/Makefile | 9 + drivers/nfc/st-nci/core.c | 179 ++++++ drivers/nfc/st-nci/i2c.c | 385 +++++++++++ drivers/nfc/st-nci/ndlc.c | 313 +++++++++ drivers/nfc/st-nci/ndlc.h | 60 ++ drivers/nfc/st-nci/st-nci.h | 50 ++ drivers/nfc/st-nci/st-nci_se.c | 714 +++++++++++++++++++++ drivers/nfc/st-nci/st-nci_se.h | 61 ++ drivers/nfc/st21nfcb/Kconfig | 22 - drivers/nfc/st21nfcb/Makefile | 9 - drivers/nfc/st21nfcb/i2c.c | 384 ----------- drivers/nfc/st21nfcb/ndlc.c | 313 --------- drivers/nfc/st21nfcb/ndlc.h | 60 -- drivers/nfc/st21nfcb/st21nfcb.c | 179 ------ drivers/nfc/st21nfcb/st21nfcb.h | 50 -- drivers/nfc/st21nfcb/st21nfcb_se.c | 713 -------------------- drivers/nfc/st21nfcb/st21nfcb_se.h | 61 -- include/linux/platform_data/st-nci.h | 29 + include/linux/platform_data/st21nfcb.h | 29 - include/linux/platform_data/st_nci.h | 29 + 25 files changed, 1887 insertions(+), 1855 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/nfc/st-nci.txt delete mode 100644 Documentation/devicetree/bindings/net/nfc/st21nfcb.txt create mode 100644 drivers/nfc/st-nci/Kconfig create mode 100644 drivers/nfc/st-nci/Makefile create mode 100644 drivers/nfc/st-nci/core.c create mode 100644 drivers/nfc/st-nci/i2c.c create mode 100644 drivers/nfc/st-nci/ndlc.c create mode 100644 drivers/nfc/st-nci/ndlc.h create mode 100644 drivers/nfc/st-nci/st-nci.h create mode 100644 drivers/nfc/st-nci/st-nci_se.c create mode 100644 drivers/nfc/st-nci/st-nci_se.h delete mode 100644 drivers/nfc/st21nfcb/Kconfig delete mode 100644 drivers/nfc/st21nfcb/Makefile delete mode 100644 drivers/nfc/st21nfcb/i2c.c delete mode 100644 drivers/nfc/st21nfcb/ndlc.c delete mode 100644 drivers/nfc/st21nfcb/ndlc.h delete mode 100644 drivers/nfc/st21nfcb/st21nfcb.c delete mode 100644 drivers/nfc/st21nfcb/st21nfcb.h delete mode 100644 drivers/nfc/st21nfcb/st21nfcb_se.c delete mode 100644 drivers/nfc/st21nfcb/st21nfcb_se.h create mode 100644 include/linux/platform_data/st-nci.h delete mode 100644 include/linux/platform_data/st21nfcb.h create mode 100644 include/linux/platform_data/st_nci.h (limited to 'include/linux/platform_data') diff --git a/Documentation/devicetree/bindings/net/nfc/st-nci.txt b/Documentation/devicetree/bindings/net/nfc/st-nci.txt new file mode 100644 index 000000000000..d707588ed734 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/st-nci.txt @@ -0,0 +1,33 @@ +* STMicroelectronics SAS. ST NCI NFC Controller + +Required properties: +- compatible: Should be "st,st21nfcb-i2c" or "st,st21nfcc-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- reset-gpios: Output GPIO pin used to reset the ST21NFCB + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): + +&i2c2 { + + status = "okay"; + + st21nfcb: st21nfcb@8 { + + compatible = "st,st21nfcb-i2c"; + + reg = <0x08>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + + reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt deleted file mode 100644 index bb237072dbe9..000000000000 --- a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt +++ /dev/null @@ -1,33 +0,0 @@ -* STMicroelectronics SAS. ST21NFCB NFC Controller - -Required properties: -- compatible: Should be "st,st21nfcb-i2c". -- clock-frequency: I²C work frequency. -- reg: address on the bus -- interrupt-parent: phandle for the interrupt gpio controller -- interrupts: GPIO interrupt to which the chip is connected -- reset-gpios: Output GPIO pin used to reset the ST21NFCB - -Optional SoC Specific Properties: -- pinctrl-names: Contains only one value - "default". -- pintctrl-0: Specifies the pin control groups used for this controller. - -Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): - -&i2c2 { - - status = "okay"; - - st21nfcb: st21nfcb@8 { - - compatible = "st,st21nfcb-i2c"; - - reg = <0x08>; - clock-frequency = <400000>; - - interrupt-parent = <&gpio5>; - interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; - - reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; - }; -}; diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 107714e4405f..722673cb785b 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -72,6 +72,6 @@ source "drivers/nfc/pn544/Kconfig" source "drivers/nfc/microread/Kconfig" source "drivers/nfc/nfcmrvl/Kconfig" source "drivers/nfc/st21nfca/Kconfig" -source "drivers/nfc/st21nfcb/Kconfig" +source "drivers/nfc/st-nci/Kconfig" source "drivers/nfc/nxp-nci/Kconfig" endmenu diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 13b648baf175..368b6dfe71b3 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -12,5 +12,5 @@ obj-$(CONFIG_NFC_PORT100) += port100.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ -obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/ +obj-$(CONFIG_NFC_ST_NCI) += st-nci/ obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ diff --git a/drivers/nfc/st-nci/Kconfig b/drivers/nfc/st-nci/Kconfig new file mode 100644 index 000000000000..fc3904c946ee --- /dev/null +++ b/drivers/nfc/st-nci/Kconfig @@ -0,0 +1,23 @@ +config NFC_ST_NCI + tristate "STMicroelectronics ST NCI NFC driver" + depends on NFC_NCI + default n + ---help--- + STMicroelectronics NFC NCI chips core driver. It implements the chipset + NCI logic and hooks into the NFC kernel APIs. Physical layers will + register against it. + + To compile this driver as a module, choose m here. The module will + be called st-nci. + Say N if unsure. + +config NFC_ST_NCI_I2C + tristate "NFC ST NCI i2c support" + depends on NFC_ST_NCI && I2C + ---help--- + This module adds support for an I2C interface to the + STMicroelectronics NFC NCI chips familly. + Select this if your platform is using the i2c bus. + + If you choose to build a module, it'll be called st-nci_i2c. + Say N if unsure. diff --git a/drivers/nfc/st-nci/Makefile b/drivers/nfc/st-nci/Makefile new file mode 100644 index 000000000000..0df157df3a94 --- /dev/null +++ b/drivers/nfc/st-nci/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for ST21NFCB NCI based NFC driver +# + +st-nci-objs = ndlc.o core.o st-nci_se.o +obj-$(CONFIG_NFC_ST_NCI) += st-nci.o + +st-nci_i2c-objs = i2c.o +obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c new file mode 100644 index 000000000000..c419d3943973 --- /dev/null +++ b/drivers/nfc/st-nci/core.c @@ -0,0 +1,179 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "st-nci.h" +#include "st-nci_se.h" + +#define DRIVER_DESC "NCI NFC driver for ST_NCI" + +#define ST_NCI1_X_PROPRIETARY_ISO15693 0x83 + +static int st_nci_init(struct nci_dev *ndev) +{ + struct nci_mode_set_cmd cmd; + + cmd.cmd_type = ST_NCI_SET_NFC_MODE; + cmd.mode = 1; + + return nci_prop_cmd(ndev, ST_NCI_CORE_PROP, + sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); +} + +static int st_nci_open(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + int r; + + if (test_and_set_bit(ST_NCI_RUNNING, &info->flags)) + return 0; + + r = ndlc_open(info->ndlc); + if (r) + clear_bit(ST_NCI_RUNNING, &info->flags); + + return r; +} + +static int st_nci_close(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + if (!test_bit(ST_NCI_RUNNING, &info->flags)) + return 0; + + ndlc_close(info->ndlc); + + clear_bit(ST_NCI_RUNNING, &info->flags); + + return 0; +} + +static int st_nci_send(struct nci_dev *ndev, struct sk_buff *skb) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + skb->dev = (void *)ndev; + + if (!test_bit(ST_NCI_RUNNING, &info->flags)) + return -EBUSY; + + return ndlc_send(info->ndlc, skb); +} + +static __u32 st_nci_get_rfprotocol(struct nci_dev *ndev, + __u8 rf_protocol) +{ + return rf_protocol == ST_NCI1_X_PROPRIETARY_ISO15693 ? + NFC_PROTO_ISO15693_MASK : 0; +} + +static int st_nci_prop_rsp_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + __u8 status = skb->data[0]; + + nci_req_complete(ndev, status); + return 0; +} + +static struct nci_prop_ops st_nci_prop_ops[] = { + { + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, + ST_NCI_CORE_PROP), + .rsp = st_nci_prop_rsp_packet, + }, +}; + +static struct nci_ops st_nci_ops = { + .init = st_nci_init, + .open = st_nci_open, + .close = st_nci_close, + .send = st_nci_send, + .get_rfprotocol = st_nci_get_rfprotocol, + .discover_se = st_nci_discover_se, + .enable_se = st_nci_enable_se, + .disable_se = st_nci_disable_se, + .se_io = st_nci_se_io, + .hci_load_session = st_nci_hci_load_session, + .hci_event_received = st_nci_hci_event_received, + .hci_cmd_received = st_nci_hci_cmd_received, + .prop_ops = st_nci_prop_ops, + .n_prop_ops = ARRAY_SIZE(st_nci_prop_ops), +}; + +int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, + int phy_tailroom) +{ + struct st_nci_info *info; + int r; + u32 protocols; + + info = devm_kzalloc(ndlc->dev, + sizeof(struct st_nci_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + protocols = NFC_PROTO_JEWEL_MASK + | NFC_PROTO_MIFARE_MASK + | NFC_PROTO_FELICA_MASK + | NFC_PROTO_ISO14443_MASK + | NFC_PROTO_ISO14443_B_MASK + | NFC_PROTO_ISO15693_MASK + | NFC_PROTO_NFC_DEP_MASK; + + ndlc->ndev = nci_allocate_device(&st_nci_ops, protocols, + phy_headroom, phy_tailroom); + if (!ndlc->ndev) { + pr_err("Cannot allocate nfc ndev\n"); + return -ENOMEM; + } + info->ndlc = ndlc; + + nci_set_drvdata(ndlc->ndev, info); + + r = nci_register_device(ndlc->ndev); + if (r) { + pr_err("Cannot register nfc device to nci core\n"); + nci_free_device(ndlc->ndev); + return r; + } + + return st_nci_se_init(ndlc->ndev); +} +EXPORT_SYMBOL_GPL(st_nci_probe); + +void st_nci_remove(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + ndlc_close(info->ndlc); + + nci_unregister_device(ndev); + nci_free_device(ndev); +} +EXPORT_SYMBOL_GPL(st_nci_remove); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c new file mode 100644 index 000000000000..06175ce769bb --- /dev/null +++ b/drivers/nfc/st-nci/i2c.c @@ -0,0 +1,385 @@ +/* + * I2C Link Layer for ST NCI NFC controller familly based Driver + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ndlc.h" + +#define DRIVER_DESC "NCI NFC driver for ST21NFCB" + +/* ndlc header */ +#define ST21NFCB_FRAME_HEADROOM 1 +#define ST21NFCB_FRAME_TAILROOM 0 + +#define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ +#define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ + +#define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c" + +static struct i2c_device_id st_nci_i2c_id_table[] = { + {ST_NCI_DRIVER_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table); + +struct st_nci_i2c_phy { + struct i2c_client *i2c_dev; + struct llt_ndlc *ndlc; + + unsigned int gpio_reset; + unsigned int irq_polarity; +}; + +#define I2C_DUMP_SKB(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ + 16, 1, (skb)->data, (skb)->len, 0); \ +} while (0) + +static int st_nci_i2c_enable(void *phy_id) +{ + struct st_nci_i2c_phy *phy = phy_id; + + gpio_set_value(phy->gpio_reset, 0); + usleep_range(10000, 15000); + gpio_set_value(phy->gpio_reset, 1); + usleep_range(80000, 85000); + + if (phy->ndlc->powered == 0) + enable_irq(phy->i2c_dev->irq); + + return 0; +} + +static void st_nci_i2c_disable(void *phy_id) +{ + struct st_nci_i2c_phy *phy = phy_id; + + disable_irq_nosync(phy->i2c_dev->irq); +} + +/* + * Writing a frame must not return the number of written bytes. + * It must return either zero for success, or <0 for error. + * In addition, it must not alter the skb + */ +static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb) +{ + int r = -1; + struct st_nci_i2c_phy *phy = phy_id; + struct i2c_client *client = phy->i2c_dev; + + I2C_DUMP_SKB("st_nci_i2c_write", skb); + + if (phy->ndlc->hard_fault != 0) + return phy->ndlc->hard_fault; + + r = i2c_master_send(client, skb->data, skb->len); + if (r < 0) { /* Retry, chip was in standby */ + usleep_range(1000, 4000); + r = i2c_master_send(client, skb->data, skb->len); + } + + if (r >= 0) { + if (r != skb->len) + r = -EREMOTEIO; + else + r = 0; + } + + return r; +} + +/* + * Reads an ndlc frame and returns it in a newly allocated sk_buff. + * returns: + * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at + * end of read) + * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF + * at end of read) + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * (value returned from st_nci_i2c_repack) + * -EIO : if no ST21NFCB_SOF_EOF is found after reaching + * the read length end sequence + */ +static int st_nci_i2c_read(struct st_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + int r; + u8 len; + u8 buf[ST_NCI_I2C_MAX_SIZE]; + struct i2c_client *client = phy->i2c_dev; + + r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE); + if (r < 0) { /* Retry, chip was in standby */ + usleep_range(1000, 4000); + r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE); + } + + if (r != ST_NCI_I2C_MIN_SIZE) + return -EREMOTEIO; + + len = be16_to_cpu(*(__be16 *) (buf + 2)); + if (len > ST_NCI_I2C_MAX_SIZE) { + nfc_err(&client->dev, "invalid frame len\n"); + return -EBADMSG; + } + + *skb = alloc_skb(ST_NCI_I2C_MIN_SIZE + len, GFP_KERNEL); + if (*skb == NULL) + return -ENOMEM; + + skb_reserve(*skb, ST_NCI_I2C_MIN_SIZE); + skb_put(*skb, ST_NCI_I2C_MIN_SIZE); + memcpy((*skb)->data, buf, ST_NCI_I2C_MIN_SIZE); + + if (!len) + return 0; + + r = i2c_master_recv(client, buf, len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + skb_put(*skb, len); + memcpy((*skb)->data + ST_NCI_I2C_MIN_SIZE, buf, len); + + I2C_DUMP_SKB("i2c frame read", *skb); + + return 0; +} + +/* + * Reads an ndlc frame from the chip. + * + * On ST21NFCB, IRQ goes in idle state when read starts. + */ +static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id) +{ + struct st_nci_i2c_phy *phy = phy_id; + struct i2c_client *client; + struct sk_buff *skb = NULL; + int r; + + if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) { + WARN_ON_ONCE(1); + return IRQ_NONE; + } + + client = phy->i2c_dev; + dev_dbg(&client->dev, "IRQ\n"); + + if (phy->ndlc->hard_fault) + return IRQ_HANDLED; + + if (!phy->ndlc->powered) { + st_nci_i2c_disable(phy); + return IRQ_HANDLED; + } + + r = st_nci_i2c_read(phy, &skb); + if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG) + return IRQ_HANDLED; + + ndlc_recv(phy->ndlc, skb); + + return IRQ_HANDLED; +} + +static struct nfc_phy_ops i2c_phy_ops = { + .write = st_nci_i2c_write, + .enable = st_nci_i2c_enable, + .disable = st_nci_i2c_disable, +}; + +#ifdef CONFIG_OF +static int st_nci_i2c_of_request_resources(struct i2c_client *client) +{ + struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); + struct device_node *pp; + int gpio; + int r; + + pp = client->dev.of_node; + if (!pp) + return -ENODEV; + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "reset-gpios", 0); + if (gpio < 0) { + nfc_err(&client->dev, + "Failed to retrieve reset-gpios from device tree\n"); + return gpio; + } + + /* GPIO request and configuration */ + r = devm_gpio_request_one(&client->dev, gpio, + GPIOF_OUT_INIT_HIGH, "clf_reset"); + if (r) { + nfc_err(&client->dev, "Failed to request reset pin\n"); + return r; + } + phy->gpio_reset = gpio; + + phy->irq_polarity = irq_get_trigger_type(client->irq); + + return 0; +} +#else +static int st_nci_i2c_of_request_resources(struct i2c_client *client) +{ + return -ENODEV; +} +#endif + +static int st_nci_i2c_request_resources(struct i2c_client *client) +{ + struct st_nci_nfc_platform_data *pdata; + struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); + int r; + + pdata = client->dev.platform_data; + if (pdata == NULL) { + nfc_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + + /* store for later use */ + phy->gpio_reset = pdata->gpio_reset; + phy->irq_polarity = pdata->irq_polarity; + + r = devm_gpio_request_one(&client->dev, + phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset"); + if (r) { + pr_err("%s : reset gpio_request failed\n", __FILE__); + return r; + } + + return 0; +} + +static int st_nci_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct st_nci_i2c_phy *phy; + struct st_nci_nfc_platform_data *pdata; + int r; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct st_nci_i2c_phy), + GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->i2c_dev = client; + + i2c_set_clientdata(client, phy); + + pdata = client->dev.platform_data; + if (!pdata && client->dev.of_node) { + r = st_nci_i2c_of_request_resources(client); + if (r) { + nfc_err(&client->dev, "No platform data\n"); + return r; + } + } else if (pdata) { + r = st_nci_i2c_request_resources(client); + if (r) { + nfc_err(&client->dev, + "Cannot get platform resources\n"); + return r; + } + } else { + nfc_err(&client->dev, + "st21nfcb platform resources not available\n"); + return -ENODEV; + } + + r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, + ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, + &phy->ndlc); + if (r < 0) { + nfc_err(&client->dev, "Unable to register ndlc layer\n"); + return r; + } + + r = devm_request_threaded_irq(&client->dev, client->irq, NULL, + st_nci_irq_thread_fn, + phy->irq_polarity | IRQF_ONESHOT, + ST_NCI_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + + return r; +} + +static int st_nci_i2c_remove(struct i2c_client *client) +{ + struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s\n", __func__); + + ndlc_remove(phy->ndlc); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id of_st_nci_i2c_match[] = { + { .compatible = "st,st21nfcb-i2c", }, + { .compatible = "st,st21nfcb_i2c", }, + { .compatible = "st,st21nfcc-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match); +#endif + +static struct i2c_driver st_nci_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ST_NCI_I2C_DRIVER_NAME, + .of_match_table = of_match_ptr(of_st_nci_i2c_match), + }, + .probe = st_nci_i2c_probe, + .id_table = st_nci_i2c_id_table, + .remove = st_nci_i2c_remove, +}; + +module_i2c_driver(st_nci_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c new file mode 100644 index 000000000000..56c6a4cb4c96 --- /dev/null +++ b/drivers/nfc/st-nci/ndlc.c @@ -0,0 +1,313 @@ +/* + * Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#include +#include + +#include "ndlc.h" +#include "st-nci.h" + +#define NDLC_TIMER_T1 100 +#define NDLC_TIMER_T1_WAIT 400 +#define NDLC_TIMER_T2 1200 + +#define PCB_TYPE_DATAFRAME 0x80 +#define PCB_TYPE_SUPERVISOR 0xc0 +#define PCB_TYPE_MASK PCB_TYPE_SUPERVISOR + +#define PCB_SYNC_ACK 0x20 +#define PCB_SYNC_NACK 0x10 +#define PCB_SYNC_WAIT 0x30 +#define PCB_SYNC_NOINFO 0x00 +#define PCB_SYNC_MASK PCB_SYNC_WAIT + +#define PCB_DATAFRAME_RETRANSMIT_YES 0x00 +#define PCB_DATAFRAME_RETRANSMIT_NO 0x04 +#define PCB_DATAFRAME_RETRANSMIT_MASK PCB_DATAFRAME_RETRANSMIT_NO + +#define PCB_SUPERVISOR_RETRANSMIT_YES 0x00 +#define PCB_SUPERVISOR_RETRANSMIT_NO 0x02 +#define PCB_SUPERVISOR_RETRANSMIT_MASK PCB_SUPERVISOR_RETRANSMIT_NO + +#define PCB_FRAME_CRC_INFO_PRESENT 0x08 +#define PCB_FRAME_CRC_INFO_NOTPRESENT 0x00 +#define PCB_FRAME_CRC_INFO_MASK PCB_FRAME_CRC_INFO_PRESENT + +#define NDLC_DUMP_SKB(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \ + 16, 1, skb->data, skb->len, 0); \ +} while (0) + +int ndlc_open(struct llt_ndlc *ndlc) +{ + /* toggle reset pin */ + ndlc->ops->enable(ndlc->phy_id); + ndlc->powered = 1; + return 0; +} +EXPORT_SYMBOL(ndlc_open); + +void ndlc_close(struct llt_ndlc *ndlc) +{ + struct nci_mode_set_cmd cmd; + + cmd.cmd_type = ST_NCI_SET_NFC_MODE; + cmd.mode = 0; + + /* toggle reset pin */ + ndlc->ops->enable(ndlc->phy_id); + + nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP, + sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); + + ndlc->powered = 0; + ndlc->ops->disable(ndlc->phy_id); +} +EXPORT_SYMBOL(ndlc_close); + +int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb) +{ + /* add ndlc header */ + u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | + PCB_FRAME_CRC_INFO_NOTPRESENT; + + *skb_push(skb, 1) = pcb; + skb_queue_tail(&ndlc->send_q, skb); + + schedule_work(&ndlc->sm_work); + + return 0; +} +EXPORT_SYMBOL(ndlc_send); + +static void llt_ndlc_send_queue(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + int r; + unsigned long time_sent; + + if (ndlc->send_q.qlen) + pr_debug("sendQlen=%d unackQlen=%d\n", + ndlc->send_q.qlen, ndlc->ack_pending_q.qlen); + + while (ndlc->send_q.qlen) { + skb = skb_dequeue(&ndlc->send_q); + NDLC_DUMP_SKB("ndlc frame written", skb); + r = ndlc->ops->write(ndlc->phy_id, skb); + if (r < 0) { + ndlc->hard_fault = r; + break; + } + time_sent = jiffies; + *(unsigned long *)skb->cb = time_sent; + + skb_queue_tail(&ndlc->ack_pending_q, skb); + + /* start timer t1 for ndlc aknowledge */ + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1)); + /* start timer t2 for chip availability */ + ndlc->t2_active = true; + mod_timer(&ndlc->t2_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T2)); + } +} + +static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + u8 pcb; + + while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) { + pcb = skb->data[0]; + switch (pcb & PCB_TYPE_MASK) { + case PCB_TYPE_SUPERVISOR: + skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) | + PCB_SUPERVISOR_RETRANSMIT_YES; + break; + case PCB_TYPE_DATAFRAME: + skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) | + PCB_DATAFRAME_RETRANSMIT_YES; + break; + default: + pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); + kfree_skb(skb); + continue; + } + skb_queue_head(&ndlc->send_q, skb); + } +} + +static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + u8 pcb; + unsigned long time_sent; + + if (ndlc->rcv_q.qlen) + pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen); + + while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) { + pcb = skb->data[0]; + skb_pull(skb, 1); + if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { + switch (pcb & PCB_SYNC_MASK) { + case PCB_SYNC_ACK: + del_timer_sync(&ndlc->t1_timer); + del_timer_sync(&ndlc->t2_timer); + ndlc->t2_active = false; + ndlc->t1_active = false; + break; + case PCB_SYNC_NACK: + llt_ndlc_requeue_data_pending(ndlc); + llt_ndlc_send_queue(ndlc); + /* start timer t1 for ndlc aknowledge */ + time_sent = jiffies; + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1)); + break; + case PCB_SYNC_WAIT: + time_sent = jiffies; + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1_WAIT)); + break; + default: + pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); + kfree_skb(skb); + break; + } + } else { + nci_recv_frame(ndlc->ndev, skb); + } + } +} + +static void llt_ndlc_sm_work(struct work_struct *work) +{ + struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work); + + llt_ndlc_send_queue(ndlc); + llt_ndlc_rcv_queue(ndlc); + + if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) { + pr_debug + ("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n"); + ndlc->t1_active = false; + + llt_ndlc_requeue_data_pending(ndlc); + llt_ndlc_send_queue(ndlc); + } + + if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) { + pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n"); + ndlc->t2_active = false; + ndlc->t1_active = false; + del_timer_sync(&ndlc->t1_timer); + del_timer_sync(&ndlc->t2_timer); + ndlc_close(ndlc); + ndlc->hard_fault = -EREMOTEIO; + } +} + +void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb) +{ + if (skb == NULL) { + pr_err("NULL Frame -> link is dead\n"); + ndlc->hard_fault = -EREMOTEIO; + ndlc_close(ndlc); + } else { + NDLC_DUMP_SKB("incoming frame", skb); + skb_queue_tail(&ndlc->rcv_q, skb); + } + + schedule_work(&ndlc->sm_work); +} +EXPORT_SYMBOL(ndlc_recv); + +static void ndlc_t1_timeout(unsigned long data) +{ + struct llt_ndlc *ndlc = (struct llt_ndlc *)data; + + pr_debug("\n"); + + schedule_work(&ndlc->sm_work); +} + +static void ndlc_t2_timeout(unsigned long data) +{ + struct llt_ndlc *ndlc = (struct llt_ndlc *)data; + + pr_debug("\n"); + + schedule_work(&ndlc->sm_work); +} + +int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, + int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id) +{ + struct llt_ndlc *ndlc; + + ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL); + if (!ndlc) + return -ENOMEM; + + ndlc->ops = phy_ops; + ndlc->phy_id = phy_id; + ndlc->dev = dev; + ndlc->powered = 0; + + *ndlc_id = ndlc; + + /* initialize timers */ + init_timer(&ndlc->t1_timer); + ndlc->t1_timer.data = (unsigned long)ndlc; + ndlc->t1_timer.function = ndlc_t1_timeout; + + init_timer(&ndlc->t2_timer); + ndlc->t2_timer.data = (unsigned long)ndlc; + ndlc->t2_timer.function = ndlc_t2_timeout; + + skb_queue_head_init(&ndlc->rcv_q); + skb_queue_head_init(&ndlc->send_q); + skb_queue_head_init(&ndlc->ack_pending_q); + + INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work); + + return st_nci_probe(ndlc, phy_headroom, phy_tailroom); +} +EXPORT_SYMBOL(ndlc_probe); + +void ndlc_remove(struct llt_ndlc *ndlc) +{ + st_nci_remove(ndlc->ndev); + + /* cancel timers */ + del_timer_sync(&ndlc->t1_timer); + del_timer_sync(&ndlc->t2_timer); + ndlc->t2_active = false; + ndlc->t1_active = false; + + skb_queue_purge(&ndlc->rcv_q); + skb_queue_purge(&ndlc->send_q); +} +EXPORT_SYMBOL(ndlc_remove); diff --git a/drivers/nfc/st-nci/ndlc.h b/drivers/nfc/st-nci/ndlc.h new file mode 100644 index 000000000000..6361005ef003 --- /dev/null +++ b/drivers/nfc/st-nci/ndlc.h @@ -0,0 +1,60 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#ifndef __LOCAL_NDLC_H_ +#define __LOCAL_NDLC_H_ + +#include +#include + +/* Low Level Transport description */ +struct llt_ndlc { + struct nci_dev *ndev; + struct nfc_phy_ops *ops; + void *phy_id; + + struct timer_list t1_timer; + bool t1_active; + + struct timer_list t2_timer; + bool t2_active; + + struct sk_buff_head rcv_q; + struct sk_buff_head send_q; + struct sk_buff_head ack_pending_q; + + struct work_struct sm_work; + + struct device *dev; + + /* + * < 0 if hardware error occurred + * and prevents normal operation. + */ + int hard_fault; + int powered; +}; + +int ndlc_open(struct llt_ndlc *ndlc); +void ndlc_close(struct llt_ndlc *ndlc); +int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb); +void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb); +int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, + int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id); +void ndlc_remove(struct llt_ndlc *ndlc); +#endif /* __LOCAL_NDLC_H__ */ diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h new file mode 100644 index 000000000000..850a2395deb7 --- /dev/null +++ b/drivers/nfc/st-nci/st-nci.h @@ -0,0 +1,50 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#ifndef __LOCAL_ST_NCI_H_ +#define __LOCAL_ST_NCI_H_ + +#include "st-nci_se.h" +#include "ndlc.h" + +/* Define private flags: */ +#define ST_NCI_RUNNING 1 + +#define ST_NCI_CORE_PROP 0x01 +#define ST_NCI_SET_NFC_MODE 0x02 + +struct nci_mode_set_cmd { + u8 cmd_type; + u8 mode; +} __packed; + +struct nci_mode_set_rsp { + u8 status; +} __packed; + +struct st_nci_info { + struct llt_ndlc *ndlc; + unsigned long flags; + struct st_nci_se_info se_info; +}; + +void st_nci_remove(struct nci_dev *ndev); +int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, + int phy_tailroom); + +#endif /* __LOCAL_ST_NCI_H_ */ diff --git a/drivers/nfc/st-nci/st-nci_se.c b/drivers/nfc/st-nci/st-nci_se.c new file mode 100644 index 000000000000..97addfa96c6f --- /dev/null +++ b/drivers/nfc/st-nci/st-nci_se.c @@ -0,0 +1,714 @@ +/* + * Secure Element driver for STMicroelectronics NFC NCI chip + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#include +#include +#include +#include +#include + +#include "st-nci.h" +#include "st-nci_se.h" + +struct st_nci_pipe_info { + u8 pipe_state; + u8 src_host_id; + u8 src_gate_id; + u8 dst_host_id; + u8 dst_gate_id; +} __packed; + +/* Hosts */ +#define ST_NCI_HOST_CONTROLLER_ID 0x00 +#define ST_NCI_TERMINAL_HOST_ID 0x01 +#define ST_NCI_UICC_HOST_ID 0x02 +#define ST_NCI_ESE_HOST_ID 0xc0 + +/* Gates */ +#define ST_NCI_DEVICE_MGNT_GATE 0x01 +#define ST_NCI_APDU_READER_GATE 0xf0 +#define ST_NCI_CONNECTIVITY_GATE 0x41 + +/* Pipes */ +#define ST_NCI_DEVICE_MGNT_PIPE 0x02 + +/* Connectivity pipe only */ +#define ST_NCI_SE_COUNT_PIPE_UICC 0x01 +/* Connectivity + APDU Reader pipe */ +#define ST_NCI_SE_COUNT_PIPE_EMBEDDED 0x02 + +#define ST_NCI_SE_TO_HOT_PLUG 1000 /* msecs */ +#define ST_NCI_SE_TO_PIPES 2000 + +#define ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80) + +#define NCI_HCI_APDU_PARAM_ATR 0x01 +#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01 +#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03 +#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04 + +#define ST_NCI_EVT_SE_HARD_RESET 0x20 +#define ST_NCI_EVT_TRANSMIT_DATA 0x10 +#define ST_NCI_EVT_WTX_REQUEST 0x11 +#define ST_NCI_EVT_SE_SOFT_RESET 0x11 +#define ST_NCI_EVT_SE_END_OF_APDU_TRANSFER 0x21 +#define ST_NCI_EVT_HOT_PLUG 0x03 + +#define ST_NCI_SE_MODE_OFF 0x00 +#define ST_NCI_SE_MODE_ON 0x01 + +#define ST_NCI_EVT_CONNECTIVITY 0x10 +#define ST_NCI_EVT_TRANSACTION 0x12 + +#define ST_NCI_DM_GETINFO 0x13 +#define ST_NCI_DM_GETINFO_PIPE_LIST 0x02 +#define ST_NCI_DM_GETINFO_PIPE_INFO 0x01 +#define ST_NCI_DM_PIPE_CREATED 0x02 +#define ST_NCI_DM_PIPE_OPEN 0x04 +#define ST_NCI_DM_RF_ACTIVE 0x80 +#define ST_NCI_DM_DISCONNECT 0x30 + +#define ST_NCI_DM_IS_PIPE_OPEN(p) \ + ((p & 0x0f) == (ST_NCI_DM_PIPE_CREATED | ST_NCI_DM_PIPE_OPEN)) + +#define ST_NCI_ATR_DEFAULT_BWI 0x04 + +/* + * WT = 2^BWI/10[s], convert into msecs and add a secure + * room by increasing by 2 this timeout + */ +#define ST_NCI_BWI_TO_TIMEOUT(x) ((1 << x) * 200) +#define ST_NCI_ATR_GET_Y_FROM_TD(x) (x >> 4) + +/* If TA is present bit 0 is set */ +#define ST_NCI_ATR_TA_PRESENT(x) (x & 0x01) +/* If TB is present bit 1 is set */ +#define ST_NCI_ATR_TB_PRESENT(x) (x & 0x02) + +#define ST_NCI_NUM_DEVICES 256 + +static DECLARE_BITMAP(dev_mask, ST_NCI_NUM_DEVICES); + +/* Here are the mandatory pipe for st_nci */ +static struct nci_hci_gate st_nci_gates[] = { + {NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE, + ST_NCI_HOST_CONTROLLER_ID}, + {NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE, + ST_NCI_HOST_CONTROLLER_ID}, + {ST_NCI_DEVICE_MGNT_GATE, ST_NCI_DEVICE_MGNT_PIPE, + ST_NCI_HOST_CONTROLLER_ID}, + + /* Secure element pipes are created by secure element host */ + {ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, + ST_NCI_HOST_CONTROLLER_ID}, + {ST_NCI_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, + ST_NCI_HOST_CONTROLLER_ID}, +}; + +static u8 st_nci_se_get_bwi(struct nci_dev *ndev) +{ + int i; + u8 td; + struct st_nci_info *info = nci_get_drvdata(ndev); + + /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */ + for (i = 1; i < ST_NCI_ESE_MAX_LENGTH; i++) { + td = ST_NCI_ATR_GET_Y_FROM_TD(info->se_info.atr[i]); + if (ST_NCI_ATR_TA_PRESENT(td)) + i++; + if (ST_NCI_ATR_TB_PRESENT(td)) { + i++; + return info->se_info.atr[i] >> 4; + } + } + return ST_NCI_ATR_DEFAULT_BWI; +} + +static void st_nci_se_get_atr(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + int r; + struct sk_buff *skb; + + r = nci_hci_get_param(ndev, ST_NCI_APDU_READER_GATE, + NCI_HCI_APDU_PARAM_ATR, &skb); + if (r < 0) + return; + + if (skb->len <= ST_NCI_ESE_MAX_LENGTH) { + memcpy(info->se_info.atr, skb->data, skb->len); + + info->se_info.wt_timeout = + ST_NCI_BWI_TO_TIMEOUT(st_nci_se_get_bwi(ndev)); + } + kfree_skb(skb); +} + +int st_nci_hci_load_session(struct nci_dev *ndev) +{ + int i, j, r; + struct sk_buff *skb_pipe_list, *skb_pipe_info; + struct st_nci_pipe_info *dm_pipe_info; + u8 pipe_list[] = { ST_NCI_DM_GETINFO_PIPE_LIST, + ST_NCI_TERMINAL_HOST_ID}; + u8 pipe_info[] = { ST_NCI_DM_GETINFO_PIPE_INFO, + ST_NCI_TERMINAL_HOST_ID, 0}; + + /* On ST_NCI device pipes number are dynamics + * If pipes are already created, hci_dev_up will fail. + * Doing a clear all pipe is a bad idea because: + * - It does useless EEPROM cycling + * - It might cause issue for secure elements support + * (such as removing connectivity or APDU reader pipe) + * A better approach on ST_NCI is to: + * - get a pipe list for each host. + * (eg: ST_NCI_HOST_CONTROLLER_ID for now). + * (TODO Later on UICC HOST and eSE HOST) + * - get pipe information + * - match retrieved pipe list in st_nci_gates + * ST_NCI_DEVICE_MGNT_GATE is a proprietary gate + * with ST_NCI_DEVICE_MGNT_PIPE. + * Pipe can be closed and need to be open. + */ + r = nci_hci_connect_gate(ndev, ST_NCI_HOST_CONTROLLER_ID, + ST_NCI_DEVICE_MGNT_GATE, + ST_NCI_DEVICE_MGNT_PIPE); + if (r < 0) + goto free_info; + + /* Get pipe list */ + r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, + ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list), + &skb_pipe_list); + if (r < 0) + goto free_info; + + /* Complete the existing gate_pipe table */ + for (i = 0; i < skb_pipe_list->len; i++) { + pipe_info[2] = skb_pipe_list->data[i]; + r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, + ST_NCI_DM_GETINFO, pipe_info, + sizeof(pipe_info), &skb_pipe_info); + + if (r) + continue; + + /* + * Match pipe ID and gate ID + * Output format from ST21NFC_DM_GETINFO is: + * - pipe state (1byte) + * - source hid (1byte) + * - source gid (1byte) + * - destination hid (1byte) + * - destination gid (1byte) + */ + dm_pipe_info = (struct st_nci_pipe_info *)skb_pipe_info->data; + if (dm_pipe_info->dst_gate_id == ST_NCI_APDU_READER_GATE && + dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) { + pr_err("Unexpected apdu_reader pipe on host %x\n", + dm_pipe_info->src_host_id); + continue; + } + + for (j = 0; (j < ARRAY_SIZE(st_nci_gates)) && + (st_nci_gates[j].gate != dm_pipe_info->dst_gate_id); j++) + ; + + if (j < ARRAY_SIZE(st_nci_gates) && + st_nci_gates[j].gate == dm_pipe_info->dst_gate_id && + ST_NCI_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) { + st_nci_gates[j].pipe = pipe_info[2]; + + ndev->hci_dev->gate2pipe[st_nci_gates[j].gate] = + st_nci_gates[j].pipe; + ndev->hci_dev->pipes[st_nci_gates[j].pipe].gate = + st_nci_gates[j].gate; + ndev->hci_dev->pipes[st_nci_gates[j].pipe].host = + dm_pipe_info->src_host_id; + } + } + + memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, + sizeof(st_nci_gates)); + +free_info: + kfree_skb(skb_pipe_info); + kfree_skb(skb_pipe_list); + return r; +} +EXPORT_SYMBOL_GPL(st_nci_hci_load_session); + +static void st_nci_hci_admin_event_received(struct nci_dev *ndev, + u8 event, struct sk_buff *skb) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + switch (event) { + case ST_NCI_EVT_HOT_PLUG: + if (info->se_info.se_active) { + if (!ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(skb)) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + complete(&info->se_info.req_completion); + } else { + mod_timer(&info->se_info.se_active_timer, + jiffies + + msecs_to_jiffies(ST_NCI_SE_TO_PIPES)); + } + } + break; + } +} + +static int st_nci_hci_apdu_reader_event_received(struct nci_dev *ndev, + u8 event, + struct sk_buff *skb) +{ + int r = 0; + struct st_nci_info *info = nci_get_drvdata(ndev); + + pr_debug("apdu reader gate event: %x\n", event); + + switch (event) { + case ST_NCI_EVT_TRANSMIT_DATA: + del_timer_sync(&info->se_info.bwi_timer); + info->se_info.bwi_active = false; + info->se_info.cb(info->se_info.cb_context, + skb->data, skb->len, 0); + break; + case ST_NCI_EVT_WTX_REQUEST: + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + break; + } + + kfree_skb(skb); + return r; +} + +/* + * Returns: + * <= 0: driver handled the event, skb consumed + * 1: driver does not handle the event, please do standard processing + */ +static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev, + u8 host, u8 event, + struct sk_buff *skb) +{ + int r = 0; + struct device *dev = &ndev->nfc_dev->dev; + struct nfc_evt_transaction *transaction; + + pr_debug("connectivity gate event: %x\n", event); + + switch (event) { + case ST_NCI_EVT_CONNECTIVITY: + + break; + case ST_NCI_EVT_TRANSACTION: + /* According to specification etsi 102 622 + * 11.2.2.4 EVT_TRANSACTION Table 52 + * Description Tag Length + * AID 81 5 to 16 + * PARAMETERS 82 0 to 255 + */ + if (skb->len < NFC_MIN_AID_LENGTH + 2 && + skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) + return -EPROTO; + + transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, + skb->len - 2, GFP_KERNEL); + + transaction->aid_len = skb->data[1]; + memcpy(transaction->aid, &skb->data[2], transaction->aid_len); + + /* Check next byte is PARAMETERS tag (82) */ + if (skb->data[transaction->aid_len + 2] != + NFC_EVT_TRANSACTION_PARAMS_TAG) + return -EPROTO; + + transaction->params_len = skb->data[transaction->aid_len + 3]; + memcpy(transaction->params, skb->data + + transaction->aid_len + 4, transaction->params_len); + + r = nfc_se_transaction(ndev->nfc_dev, host, transaction); + break; + default: + return 1; + } + kfree_skb(skb); + return r; +} + +void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe, + u8 event, struct sk_buff *skb) +{ + u8 gate = ndev->hci_dev->pipes[pipe].gate; + u8 host = ndev->hci_dev->pipes[pipe].host; + + switch (gate) { + case NCI_HCI_ADMIN_GATE: + st_nci_hci_admin_event_received(ndev, event, skb); + break; + case ST_NCI_APDU_READER_GATE: + st_nci_hci_apdu_reader_event_received(ndev, event, skb); + break; + case ST_NCI_CONNECTIVITY_GATE: + st_nci_hci_connectivity_event_received(ndev, host, event, + skb); + break; + } +} +EXPORT_SYMBOL_GPL(st_nci_hci_event_received); + + +void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, + struct sk_buff *skb) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + u8 gate = ndev->hci_dev->pipes[pipe].gate; + + pr_debug("cmd: %x\n", cmd); + + switch (cmd) { + case NCI_HCI_ANY_OPEN_PIPE: + if (gate != ST_NCI_APDU_READER_GATE && + ndev->hci_dev->pipes[pipe].host != ST_NCI_UICC_HOST_ID) + ndev->hci_dev->count_pipes++; + + if (ndev->hci_dev->count_pipes == + ndev->hci_dev->expected_pipes) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + ndev->hci_dev->count_pipes = 0; + complete(&info->se_info.req_completion); + } + break; + } +} +EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received); + +/* + * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0) + * is rejected + */ +static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, + u8 state) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + int r; + struct sk_buff *sk_host_list; + u8 host_id; + + switch (se_idx) { + case ST_NCI_UICC_HOST_ID: + ndev->hci_dev->count_pipes = 0; + ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_UICC; + break; + case ST_NCI_ESE_HOST_ID: + ndev->hci_dev->count_pipes = 0; + ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_EMBEDDED; + break; + default: + return -EINVAL; + } + + /* + * Wait for an EVT_HOT_PLUG in order to + * retrieve a relevant host list. + */ + reinit_completion(&info->se_info.req_completion); + r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); + if (r != NCI_STATUS_OK) + return r; + + mod_timer(&info->se_info.se_active_timer, jiffies + + msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG)); + info->se_info.se_active = true; + + /* Ignore return value and check in any case the host_list */ + wait_for_completion_interruptible(&info->se_info.req_completion); + + /* There might be some "collision" after receiving a HOT_PLUG event + * This may cause the CLF to not answer to the next hci command. + * There is no possible synchronization to prevent this. + * Adding a small delay is the only way to solve the issue. + */ + usleep_range(3000, 5000); + + r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, + NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); + if (r != NCI_HCI_ANY_OK) + return r; + + host_id = sk_host_list->data[sk_host_list->len - 1]; + kfree_skb(sk_host_list); + if (state == ST_NCI_SE_MODE_ON && host_id == se_idx) + return se_idx; + else if (state == ST_NCI_SE_MODE_OFF && host_id != se_idx) + return se_idx; + + return -1; +} + +int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx) +{ + int r; + + pr_debug("st_nci_disable_se\n"); + + if (se_idx == NFC_SE_EMBEDDED) { + r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, + ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); + if (r < 0) + return r; + } + + return 0; +} +EXPORT_SYMBOL_GPL(st_nci_disable_se); + +int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx) +{ + int r; + + pr_debug("st_nci_enable_se\n"); + + if (se_idx == ST_NCI_HCI_HOST_ID_ESE) { + r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, + ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); + if (r < 0) + return r; + } + + return 0; +} +EXPORT_SYMBOL_GPL(st_nci_enable_se); + +static int st_nci_hci_network_init(struct nci_dev *ndev) +{ + struct core_conn_create_dest_spec_params *dest_params; + struct dest_spec_params spec_params; + struct nci_conn_info *conn_info; + int r, dev_num; + + dest_params = + kzalloc(sizeof(struct core_conn_create_dest_spec_params) + + sizeof(struct dest_spec_params), GFP_KERNEL); + if (dest_params == NULL) { + r = -ENOMEM; + goto exit; + } + + dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE; + dest_params->length = sizeof(struct dest_spec_params); + spec_params.id = ndev->hci_dev->nfcee_id; + spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS; + memcpy(dest_params->value, &spec_params, + sizeof(struct dest_spec_params)); + r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1, + sizeof(struct core_conn_create_dest_spec_params) + + sizeof(struct dest_spec_params), + dest_params); + if (r != NCI_STATUS_OK) + goto free_dest_params; + + conn_info = ndev->hci_dev->conn_info; + if (!conn_info) + goto free_dest_params; + + memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, + sizeof(st_nci_gates)); + + /* + * Session id must include the driver name + i2c bus addr + * persistent info to discriminate 2 identical chips + */ + dev_num = find_first_zero_bit(dev_mask, ST_NCI_NUM_DEVICES); + if (dev_num >= ST_NCI_NUM_DEVICES) { + r = -ENODEV; + goto free_dest_params; + } + + scnprintf(ndev->hci_dev->init_data.session_id, + sizeof(ndev->hci_dev->init_data.session_id), + "%s%2x", "ST21BH", dev_num); + + r = nci_hci_dev_session_init(ndev); + if (r != NCI_HCI_ANY_OK) + goto free_dest_params; + + r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, + NCI_NFCEE_ENABLE); + if (r != NCI_STATUS_OK) + goto free_dest_params; + +free_dest_params: + kfree(dest_params); + +exit: + return r; +} + +int st_nci_discover_se(struct nci_dev *ndev) +{ + u8 param[2]; + int r; + int se_count = 0; + + pr_debug("st_nci_discover_se\n"); + + r = st_nci_hci_network_init(ndev); + if (r != 0) + return r; + + param[0] = ST_NCI_UICC_HOST_ID; + param[1] = ST_NCI_HCI_HOST_ID_ESE; + r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, + NCI_HCI_ADMIN_PARAM_WHITELIST, + param, sizeof(param)); + if (r != NCI_HCI_ANY_OK) + return r; + + r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID, + ST_NCI_SE_MODE_ON); + if (r == ST_NCI_UICC_HOST_ID) { + nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC); + se_count++; + } + + /* Try to enable eSE in order to check availability */ + r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE, + ST_NCI_SE_MODE_ON); + if (r == ST_NCI_HCI_HOST_ID_ESE) { + nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE, + NFC_SE_EMBEDDED); + se_count++; + st_nci_se_get_atr(ndev); + } + + return !se_count; +} +EXPORT_SYMBOL_GPL(st_nci_discover_se); + +int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + pr_debug("\n"); + + switch (se_idx) { + case ST_NCI_HCI_HOST_ID_ESE: + info->se_info.cb = cb; + info->se_info.cb_context = cb_context; + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + info->se_info.bwi_active = true; + return nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, + ST_NCI_EVT_TRANSMIT_DATA, apdu, + apdu_length); + default: + return -ENODEV; + } +} +EXPORT_SYMBOL(st_nci_se_io); + +static void st_nci_se_wt_timeout(unsigned long data) +{ + /* + * No answer from the secure element + * within the defined timeout. + * Let's send a reset request as recovery procedure. + * According to the situation, we first try to send a software reset + * to the secure element. If the next command is still not + * answering in time, we send to the CLF a secure element hardware + * reset request. + */ + /* hardware reset managed through VCC_UICC_OUT power supply */ + u8 param = 0x01; + struct st_nci_info *info = (struct st_nci_info *) data; + + pr_debug("\n"); + + info->se_info.bwi_active = false; + + if (!info->se_info.xch_error) { + info->se_info.xch_error = true; + nci_hci_send_event(info->ndlc->ndev, ST_NCI_APDU_READER_GATE, + ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); + } else { + info->se_info.xch_error = false; + nci_hci_send_event(info->ndlc->ndev, ST_NCI_DEVICE_MGNT_GATE, + ST_NCI_EVT_SE_HARD_RESET, ¶m, 1); + } + info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); +} + +static void st_nci_se_activation_timeout(unsigned long data) +{ + struct st_nci_info *info = (struct st_nci_info *) data; + + pr_debug("\n"); + + info->se_info.se_active = false; + + complete(&info->se_info.req_completion); +} + +int st_nci_se_init(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + init_completion(&info->se_info.req_completion); + /* initialize timers */ + init_timer(&info->se_info.bwi_timer); + info->se_info.bwi_timer.data = (unsigned long)info; + info->se_info.bwi_timer.function = st_nci_se_wt_timeout; + info->se_info.bwi_active = false; + + init_timer(&info->se_info.se_active_timer); + info->se_info.se_active_timer.data = (unsigned long)info; + info->se_info.se_active_timer.function = + st_nci_se_activation_timeout; + info->se_info.se_active = false; + + info->se_info.xch_error = false; + + info->se_info.wt_timeout = + ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI); + + return 0; +} +EXPORT_SYMBOL(st_nci_se_init); + +void st_nci_se_deinit(struct nci_dev *ndev) +{ + struct st_nci_info *info = nci_get_drvdata(ndev); + + if (info->se_info.bwi_active) + del_timer_sync(&info->se_info.bwi_timer); + if (info->se_info.se_active) + del_timer_sync(&info->se_info.se_active_timer); + + info->se_info.se_active = false; + info->se_info.bwi_active = false; +} +EXPORT_SYMBOL(st_nci_se_deinit); + diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h new file mode 100644 index 000000000000..ea66e879d67f --- /dev/null +++ b/drivers/nfc/st-nci/st-nci_se.h @@ -0,0 +1,61 @@ +/* + * Secure Element Driver for STMicroelectronics NFC NCI Chip + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#ifndef __LOCAL_ST_NCI_SE_H_ +#define __LOCAL_ST_NCI_SE_H_ + +/* + * ref ISO7816-3 chap 8.1. the initial character TS is followed by a + * sequence of at most 32 characters. + */ +#define ST_NCI_ESE_MAX_LENGTH 33 +#define ST_NCI_HCI_HOST_ID_ESE 0xc0 + +struct st_nci_se_info { + u8 atr[ST_NCI_ESE_MAX_LENGTH]; + struct completion req_completion; + + struct timer_list bwi_timer; + int wt_timeout; /* in msecs */ + bool bwi_active; + + struct timer_list se_active_timer; + bool se_active; + + bool xch_error; + + se_io_cb_t cb; + void *cb_context; +}; + +int st_nci_se_init(struct nci_dev *ndev); +void st_nci_se_deinit(struct nci_dev *ndev); + +int st_nci_discover_se(struct nci_dev *ndev); +int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx); +int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx); +int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context); +int st_nci_hci_load_session(struct nci_dev *ndev); +void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe, + u8 event, struct sk_buff *skb); +void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, + struct sk_buff *skb); + + +#endif /* __LOCAL_ST_NCI_SE_H_ */ diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig deleted file mode 100644 index e0322dd03a70..000000000000 --- a/drivers/nfc/st21nfcb/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config NFC_ST21NFCB - tristate "STMicroelectronics ST21NFCB NFC driver" - depends on NFC_NCI - default n - ---help--- - STMicroelectronics ST21NFCB core driver. It implements the chipset - NCI logic and hooks into the NFC kernel APIs. Physical layers will - register against it. - - To compile this driver as a module, choose m here. The module will - be called st21nfcb. - Say N if unsure. - -config NFC_ST21NFCB_I2C - tristate "NFC ST21NFCB i2c support" - depends on NFC_ST21NFCB && I2C - ---help--- - This module adds support for the STMicroelectronics st21nfcb i2c interface. - Select this if your platform is using the i2c bus. - - If you choose to build a module, it'll be called st21nfcb_i2c. - Say N if unsure. diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile deleted file mode 100644 index ce659a9e5a1a..000000000000 --- a/drivers/nfc/st21nfcb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for ST21NFCB NCI based NFC driver -# - -st21nfcb_nci-objs = ndlc.o st21nfcb.o st21nfcb_se.o -obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb_nci.o - -st21nfcb_i2c-objs = i2c.o -obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c deleted file mode 100644 index dbc0dfd8ae85..000000000000 --- a/drivers/nfc/st21nfcb/i2c.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * I2C Link Layer for ST21NFCB NCI based Driver - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ndlc.h" - -#define DRIVER_DESC "NCI NFC driver for ST21NFCB" - -/* ndlc header */ -#define ST21NFCB_FRAME_HEADROOM 1 -#define ST21NFCB_FRAME_TAILROOM 0 - -#define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ -#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ - -#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c" - -static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = { - {ST21NFCB_NCI_DRIVER_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table); - -struct st21nfcb_i2c_phy { - struct i2c_client *i2c_dev; - struct llt_ndlc *ndlc; - - unsigned int gpio_reset; - unsigned int irq_polarity; -}; - -#define I2C_DUMP_SKB(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -static int st21nfcb_nci_i2c_enable(void *phy_id) -{ - struct st21nfcb_i2c_phy *phy = phy_id; - - gpio_set_value(phy->gpio_reset, 0); - usleep_range(10000, 15000); - gpio_set_value(phy->gpio_reset, 1); - usleep_range(80000, 85000); - - if (phy->ndlc->powered == 0) - enable_irq(phy->i2c_dev->irq); - - return 0; -} - -static void st21nfcb_nci_i2c_disable(void *phy_id) -{ - struct st21nfcb_i2c_phy *phy = phy_id; - - disable_irq_nosync(phy->i2c_dev->irq); -} - -/* - * Writing a frame must not return the number of written bytes. - * It must return either zero for success, or <0 for error. - * In addition, it must not alter the skb - */ -static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb) -{ - int r = -1; - struct st21nfcb_i2c_phy *phy = phy_id; - struct i2c_client *client = phy->i2c_dev; - - I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb); - - if (phy->ndlc->hard_fault != 0) - return phy->ndlc->hard_fault; - - r = i2c_master_send(client, skb->data, skb->len); - if (r < 0) { /* Retry, chip was in standby */ - usleep_range(1000, 4000); - r = i2c_master_send(client, skb->data, skb->len); - } - - if (r >= 0) { - if (r != skb->len) - r = -EREMOTEIO; - else - r = 0; - } - - return r; -} - -/* - * Reads an ndlc frame and returns it in a newly allocated sk_buff. - * returns: - * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at - * end of read) - * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF - * at end of read) - * -EREMOTEIO : i2c read error (fatal) - * -EBADMSG : frame was incorrect and discarded - * (value returned from st21nfcb_nci_i2c_repack) - * -EIO : if no ST21NFCB_SOF_EOF is found after reaching - * the read length end sequence - */ -static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, - struct sk_buff **skb) -{ - int r; - u8 len; - u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE]; - struct i2c_client *client = phy->i2c_dev; - - r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); - if (r < 0) { /* Retry, chip was in standby */ - usleep_range(1000, 4000); - r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); - } - - if (r != ST21NFCB_NCI_I2C_MIN_SIZE) - return -EREMOTEIO; - - len = be16_to_cpu(*(__be16 *) (buf + 2)); - if (len > ST21NFCB_NCI_I2C_MAX_SIZE) { - nfc_err(&client->dev, "invalid frame len\n"); - return -EBADMSG; - } - - *skb = alloc_skb(ST21NFCB_NCI_I2C_MIN_SIZE + len, GFP_KERNEL); - if (*skb == NULL) - return -ENOMEM; - - skb_reserve(*skb, ST21NFCB_NCI_I2C_MIN_SIZE); - skb_put(*skb, ST21NFCB_NCI_I2C_MIN_SIZE); - memcpy((*skb)->data, buf, ST21NFCB_NCI_I2C_MIN_SIZE); - - if (!len) - return 0; - - r = i2c_master_recv(client, buf, len); - if (r != len) { - kfree_skb(*skb); - return -EREMOTEIO; - } - - skb_put(*skb, len); - memcpy((*skb)->data + ST21NFCB_NCI_I2C_MIN_SIZE, buf, len); - - I2C_DUMP_SKB("i2c frame read", *skb); - - return 0; -} - -/* - * Reads an ndlc frame from the chip. - * - * On ST21NFCB, IRQ goes in idle state when read starts. - */ -static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id) -{ - struct st21nfcb_i2c_phy *phy = phy_id; - struct i2c_client *client; - struct sk_buff *skb = NULL; - int r; - - if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) { - WARN_ON_ONCE(1); - return IRQ_NONE; - } - - client = phy->i2c_dev; - dev_dbg(&client->dev, "IRQ\n"); - - if (phy->ndlc->hard_fault) - return IRQ_HANDLED; - - if (!phy->ndlc->powered) { - st21nfcb_nci_i2c_disable(phy); - return IRQ_HANDLED; - } - - r = st21nfcb_nci_i2c_read(phy, &skb); - if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG) - return IRQ_HANDLED; - - ndlc_recv(phy->ndlc, skb); - - return IRQ_HANDLED; -} - -static struct nfc_phy_ops i2c_phy_ops = { - .write = st21nfcb_nci_i2c_write, - .enable = st21nfcb_nci_i2c_enable, - .disable = st21nfcb_nci_i2c_disable, -}; - -#ifdef CONFIG_OF -static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client) -{ - struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); - struct device_node *pp; - int gpio; - int r; - - pp = client->dev.of_node; - if (!pp) - return -ENODEV; - - /* Get GPIO from device tree */ - gpio = of_get_named_gpio(pp, "reset-gpios", 0); - if (gpio < 0) { - nfc_err(&client->dev, - "Failed to retrieve reset-gpios from device tree\n"); - return gpio; - } - - /* GPIO request and configuration */ - r = devm_gpio_request_one(&client->dev, gpio, - GPIOF_OUT_INIT_HIGH, "clf_reset"); - if (r) { - nfc_err(&client->dev, "Failed to request reset pin\n"); - return r; - } - phy->gpio_reset = gpio; - - phy->irq_polarity = irq_get_trigger_type(client->irq); - - return 0; -} -#else -static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client) -{ - return -ENODEV; -} -#endif - -static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client) -{ - struct st21nfcb_nfc_platform_data *pdata; - struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); - int r; - - pdata = client->dev.platform_data; - if (pdata == NULL) { - nfc_err(&client->dev, "No platform data\n"); - return -EINVAL; - } - - /* store for later use */ - phy->gpio_reset = pdata->gpio_reset; - phy->irq_polarity = pdata->irq_polarity; - - r = devm_gpio_request_one(&client->dev, - phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset"); - if (r) { - pr_err("%s : reset gpio_request failed\n", __FILE__); - return r; - } - - return 0; -} - -static int st21nfcb_nci_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct st21nfcb_i2c_phy *phy; - struct st21nfcb_nfc_platform_data *pdata; - int r; - - dev_dbg(&client->dev, "%s\n", __func__); - dev_dbg(&client->dev, "IRQ: %d\n", client->irq); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); - return -ENODEV; - } - - phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy), - GFP_KERNEL); - if (!phy) - return -ENOMEM; - - phy->i2c_dev = client; - - i2c_set_clientdata(client, phy); - - pdata = client->dev.platform_data; - if (!pdata && client->dev.of_node) { - r = st21nfcb_nci_i2c_of_request_resources(client); - if (r) { - nfc_err(&client->dev, "No platform data\n"); - return r; - } - } else if (pdata) { - r = st21nfcb_nci_i2c_request_resources(client); - if (r) { - nfc_err(&client->dev, - "Cannot get platform resources\n"); - return r; - } - } else { - nfc_err(&client->dev, - "st21nfcb platform resources not available\n"); - return -ENODEV; - } - - r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, - ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, - &phy->ndlc); - if (r < 0) { - nfc_err(&client->dev, "Unable to register ndlc layer\n"); - return r; - } - - r = devm_request_threaded_irq(&client->dev, client->irq, NULL, - st21nfcb_nci_irq_thread_fn, - phy->irq_polarity | IRQF_ONESHOT, - ST21NFCB_NCI_DRIVER_NAME, phy); - if (r < 0) - nfc_err(&client->dev, "Unable to register IRQ handler\n"); - - return r; -} - -static int st21nfcb_nci_i2c_remove(struct i2c_client *client) -{ - struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "%s\n", __func__); - - ndlc_remove(phy->ndlc); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id of_st21nfcb_i2c_match[] = { - { .compatible = "st,st21nfcb-i2c", }, - { .compatible = "st,st21nfcb_i2c", }, - {} -}; -MODULE_DEVICE_TABLE(of, of_st21nfcb_i2c_match); -#endif - -static struct i2c_driver st21nfcb_nci_i2c_driver = { - .driver = { - .owner = THIS_MODULE, - .name = ST21NFCB_NCI_I2C_DRIVER_NAME, - .of_match_table = of_match_ptr(of_st21nfcb_i2c_match), - }, - .probe = st21nfcb_nci_i2c_probe, - .id_table = st21nfcb_nci_i2c_id_table, - .remove = st21nfcb_nci_i2c_remove, -}; - -module_i2c_driver(st21nfcb_nci_i2c_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c deleted file mode 100644 index 91e81f37b3a6..000000000000 --- a/drivers/nfc/st21nfcb/ndlc.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#include -#include - -#include "ndlc.h" -#include "st21nfcb.h" - -#define NDLC_TIMER_T1 100 -#define NDLC_TIMER_T1_WAIT 400 -#define NDLC_TIMER_T2 1200 - -#define PCB_TYPE_DATAFRAME 0x80 -#define PCB_TYPE_SUPERVISOR 0xc0 -#define PCB_TYPE_MASK PCB_TYPE_SUPERVISOR - -#define PCB_SYNC_ACK 0x20 -#define PCB_SYNC_NACK 0x10 -#define PCB_SYNC_WAIT 0x30 -#define PCB_SYNC_NOINFO 0x00 -#define PCB_SYNC_MASK PCB_SYNC_WAIT - -#define PCB_DATAFRAME_RETRANSMIT_YES 0x00 -#define PCB_DATAFRAME_RETRANSMIT_NO 0x04 -#define PCB_DATAFRAME_RETRANSMIT_MASK PCB_DATAFRAME_RETRANSMIT_NO - -#define PCB_SUPERVISOR_RETRANSMIT_YES 0x00 -#define PCB_SUPERVISOR_RETRANSMIT_NO 0x02 -#define PCB_SUPERVISOR_RETRANSMIT_MASK PCB_SUPERVISOR_RETRANSMIT_NO - -#define PCB_FRAME_CRC_INFO_PRESENT 0x08 -#define PCB_FRAME_CRC_INFO_NOTPRESENT 0x00 -#define PCB_FRAME_CRC_INFO_MASK PCB_FRAME_CRC_INFO_PRESENT - -#define NDLC_DUMP_SKB(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \ - 16, 1, skb->data, skb->len, 0); \ -} while (0) - -int ndlc_open(struct llt_ndlc *ndlc) -{ - /* toggle reset pin */ - ndlc->ops->enable(ndlc->phy_id); - ndlc->powered = 1; - return 0; -} -EXPORT_SYMBOL(ndlc_open); - -void ndlc_close(struct llt_ndlc *ndlc) -{ - struct nci_mode_set_cmd cmd; - - cmd.cmd_type = ST21NFCB_NCI_SET_NFC_MODE; - cmd.mode = 0; - - /* toggle reset pin */ - ndlc->ops->enable(ndlc->phy_id); - - nci_prop_cmd(ndlc->ndev, ST21NFCB_NCI_CORE_PROP, - sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); - - ndlc->powered = 0; - ndlc->ops->disable(ndlc->phy_id); -} -EXPORT_SYMBOL(ndlc_close); - -int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb) -{ - /* add ndlc header */ - u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | - PCB_FRAME_CRC_INFO_NOTPRESENT; - - *skb_push(skb, 1) = pcb; - skb_queue_tail(&ndlc->send_q, skb); - - schedule_work(&ndlc->sm_work); - - return 0; -} -EXPORT_SYMBOL(ndlc_send); - -static void llt_ndlc_send_queue(struct llt_ndlc *ndlc) -{ - struct sk_buff *skb; - int r; - unsigned long time_sent; - - if (ndlc->send_q.qlen) - pr_debug("sendQlen=%d unackQlen=%d\n", - ndlc->send_q.qlen, ndlc->ack_pending_q.qlen); - - while (ndlc->send_q.qlen) { - skb = skb_dequeue(&ndlc->send_q); - NDLC_DUMP_SKB("ndlc frame written", skb); - r = ndlc->ops->write(ndlc->phy_id, skb); - if (r < 0) { - ndlc->hard_fault = r; - break; - } - time_sent = jiffies; - *(unsigned long *)skb->cb = time_sent; - - skb_queue_tail(&ndlc->ack_pending_q, skb); - - /* start timer t1 for ndlc aknowledge */ - ndlc->t1_active = true; - mod_timer(&ndlc->t1_timer, time_sent + - msecs_to_jiffies(NDLC_TIMER_T1)); - /* start timer t2 for chip availability */ - ndlc->t2_active = true; - mod_timer(&ndlc->t2_timer, time_sent + - msecs_to_jiffies(NDLC_TIMER_T2)); - } -} - -static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc) -{ - struct sk_buff *skb; - u8 pcb; - - while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) { - pcb = skb->data[0]; - switch (pcb & PCB_TYPE_MASK) { - case PCB_TYPE_SUPERVISOR: - skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) | - PCB_SUPERVISOR_RETRANSMIT_YES; - break; - case PCB_TYPE_DATAFRAME: - skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) | - PCB_DATAFRAME_RETRANSMIT_YES; - break; - default: - pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); - kfree_skb(skb); - continue; - } - skb_queue_head(&ndlc->send_q, skb); - } -} - -static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc) -{ - struct sk_buff *skb; - u8 pcb; - unsigned long time_sent; - - if (ndlc->rcv_q.qlen) - pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen); - - while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) { - pcb = skb->data[0]; - skb_pull(skb, 1); - if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { - switch (pcb & PCB_SYNC_MASK) { - case PCB_SYNC_ACK: - del_timer_sync(&ndlc->t1_timer); - del_timer_sync(&ndlc->t2_timer); - ndlc->t2_active = false; - ndlc->t1_active = false; - break; - case PCB_SYNC_NACK: - llt_ndlc_requeue_data_pending(ndlc); - llt_ndlc_send_queue(ndlc); - /* start timer t1 for ndlc aknowledge */ - time_sent = jiffies; - ndlc->t1_active = true; - mod_timer(&ndlc->t1_timer, time_sent + - msecs_to_jiffies(NDLC_TIMER_T1)); - break; - case PCB_SYNC_WAIT: - time_sent = jiffies; - ndlc->t1_active = true; - mod_timer(&ndlc->t1_timer, time_sent + - msecs_to_jiffies(NDLC_TIMER_T1_WAIT)); - break; - default: - pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); - kfree_skb(skb); - break; - } - } else { - nci_recv_frame(ndlc->ndev, skb); - } - } -} - -static void llt_ndlc_sm_work(struct work_struct *work) -{ - struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work); - - llt_ndlc_send_queue(ndlc); - llt_ndlc_rcv_queue(ndlc); - - if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) { - pr_debug - ("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n"); - ndlc->t1_active = false; - - llt_ndlc_requeue_data_pending(ndlc); - llt_ndlc_send_queue(ndlc); - } - - if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) { - pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n"); - ndlc->t2_active = false; - ndlc->t1_active = false; - del_timer_sync(&ndlc->t1_timer); - del_timer_sync(&ndlc->t2_timer); - ndlc_close(ndlc); - ndlc->hard_fault = -EREMOTEIO; - } -} - -void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb) -{ - if (skb == NULL) { - pr_err("NULL Frame -> link is dead\n"); - ndlc->hard_fault = -EREMOTEIO; - ndlc_close(ndlc); - } else { - NDLC_DUMP_SKB("incoming frame", skb); - skb_queue_tail(&ndlc->rcv_q, skb); - } - - schedule_work(&ndlc->sm_work); -} -EXPORT_SYMBOL(ndlc_recv); - -static void ndlc_t1_timeout(unsigned long data) -{ - struct llt_ndlc *ndlc = (struct llt_ndlc *)data; - - pr_debug("\n"); - - schedule_work(&ndlc->sm_work); -} - -static void ndlc_t2_timeout(unsigned long data) -{ - struct llt_ndlc *ndlc = (struct llt_ndlc *)data; - - pr_debug("\n"); - - schedule_work(&ndlc->sm_work); -} - -int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, - int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id) -{ - struct llt_ndlc *ndlc; - - ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL); - if (!ndlc) - return -ENOMEM; - - ndlc->ops = phy_ops; - ndlc->phy_id = phy_id; - ndlc->dev = dev; - ndlc->powered = 0; - - *ndlc_id = ndlc; - - /* initialize timers */ - init_timer(&ndlc->t1_timer); - ndlc->t1_timer.data = (unsigned long)ndlc; - ndlc->t1_timer.function = ndlc_t1_timeout; - - init_timer(&ndlc->t2_timer); - ndlc->t2_timer.data = (unsigned long)ndlc; - ndlc->t2_timer.function = ndlc_t2_timeout; - - skb_queue_head_init(&ndlc->rcv_q); - skb_queue_head_init(&ndlc->send_q); - skb_queue_head_init(&ndlc->ack_pending_q); - - INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work); - - return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom); -} -EXPORT_SYMBOL(ndlc_probe); - -void ndlc_remove(struct llt_ndlc *ndlc) -{ - st21nfcb_nci_remove(ndlc->ndev); - - /* cancel timers */ - del_timer_sync(&ndlc->t1_timer); - del_timer_sync(&ndlc->t2_timer); - ndlc->t2_active = false; - ndlc->t1_active = false; - - skb_queue_purge(&ndlc->rcv_q); - skb_queue_purge(&ndlc->send_q); -} -EXPORT_SYMBOL(ndlc_remove); diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st21nfcb/ndlc.h deleted file mode 100644 index cf6a9d9f2983..000000000000 --- a/drivers/nfc/st21nfcb/ndlc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * NCI based Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#ifndef __LOCAL_NDLC_H_ -#define __LOCAL_NDLC_H_ - -#include -#include - -/* Low Level Transport description */ -struct llt_ndlc { - struct nci_dev *ndev; - struct nfc_phy_ops *ops; - void *phy_id; - - struct timer_list t1_timer; - bool t1_active; - - struct timer_list t2_timer; - bool t2_active; - - struct sk_buff_head rcv_q; - struct sk_buff_head send_q; - struct sk_buff_head ack_pending_q; - - struct work_struct sm_work; - - struct device *dev; - - /* - * < 0 if hardware error occured - * and prevents normal operation. - */ - int hard_fault; - int powered; -}; - -int ndlc_open(struct llt_ndlc *ndlc); -void ndlc_close(struct llt_ndlc *ndlc); -int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb); -void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb); -int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, - int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id); -void ndlc_remove(struct llt_ndlc *ndlc); -#endif /* __LOCAL_NDLC_H__ */ diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c deleted file mode 100644 index a16c3a3d3fff..000000000000 --- a/drivers/nfc/st21nfcb/st21nfcb.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * NCI based Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "st21nfcb.h" -#include "st21nfcb_se.h" - -#define DRIVER_DESC "NCI NFC driver for ST21NFCB" - -#define ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 0x83 - -static int st21nfcb_nci_init(struct nci_dev *ndev) -{ - struct nci_mode_set_cmd cmd; - - cmd.cmd_type = ST21NFCB_NCI_SET_NFC_MODE; - cmd.mode = 1; - - return nci_prop_cmd(ndev, ST21NFCB_NCI_CORE_PROP, - sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); -} - -static int st21nfcb_nci_open(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - int r; - - if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags)) - return 0; - - r = ndlc_open(info->ndlc); - if (r) - clear_bit(ST21NFCB_NCI_RUNNING, &info->flags); - - return r; -} - -static int st21nfcb_nci_close(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags)) - return 0; - - ndlc_close(info->ndlc); - - clear_bit(ST21NFCB_NCI_RUNNING, &info->flags); - - return 0; -} - -static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - skb->dev = (void *)ndev; - - if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags)) - return -EBUSY; - - return ndlc_send(info->ndlc, skb); -} - -static __u32 st21nfcb_nci_get_rfprotocol(struct nci_dev *ndev, - __u8 rf_protocol) -{ - return rf_protocol == ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 ? - NFC_PROTO_ISO15693_MASK : 0; -} - -static int st21nfcb_nci_prop_rsp_packet(struct nci_dev *ndev, - struct sk_buff *skb) -{ - __u8 status = skb->data[0]; - - nci_req_complete(ndev, status); - return 0; -} - -static struct nci_prop_ops st21nfcb_nci_prop_ops[] = { - { - .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, - ST21NFCB_NCI_CORE_PROP), - .rsp = st21nfcb_nci_prop_rsp_packet, - }, -}; - -static struct nci_ops st21nfcb_nci_ops = { - .init = st21nfcb_nci_init, - .open = st21nfcb_nci_open, - .close = st21nfcb_nci_close, - .send = st21nfcb_nci_send, - .get_rfprotocol = st21nfcb_nci_get_rfprotocol, - .discover_se = st21nfcb_nci_discover_se, - .enable_se = st21nfcb_nci_enable_se, - .disable_se = st21nfcb_nci_disable_se, - .se_io = st21nfcb_nci_se_io, - .hci_load_session = st21nfcb_hci_load_session, - .hci_event_received = st21nfcb_hci_event_received, - .hci_cmd_received = st21nfcb_hci_cmd_received, - .prop_ops = st21nfcb_nci_prop_ops, - .n_prop_ops = ARRAY_SIZE(st21nfcb_nci_prop_ops), -}; - -int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, - int phy_tailroom) -{ - struct st21nfcb_nci_info *info; - int r; - u32 protocols; - - info = devm_kzalloc(ndlc->dev, - sizeof(struct st21nfcb_nci_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - protocols = NFC_PROTO_JEWEL_MASK - | NFC_PROTO_MIFARE_MASK - | NFC_PROTO_FELICA_MASK - | NFC_PROTO_ISO14443_MASK - | NFC_PROTO_ISO14443_B_MASK - | NFC_PROTO_ISO15693_MASK - | NFC_PROTO_NFC_DEP_MASK; - - ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols, - phy_headroom, phy_tailroom); - if (!ndlc->ndev) { - pr_err("Cannot allocate nfc ndev\n"); - return -ENOMEM; - } - info->ndlc = ndlc; - - nci_set_drvdata(ndlc->ndev, info); - - r = nci_register_device(ndlc->ndev); - if (r) { - pr_err("Cannot register nfc device to nci core\n"); - nci_free_device(ndlc->ndev); - return r; - } - - return st21nfcb_se_init(ndlc->ndev); -} -EXPORT_SYMBOL_GPL(st21nfcb_nci_probe); - -void st21nfcb_nci_remove(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - ndlc_close(info->ndlc); - - nci_unregister_device(ndev); - nci_free_device(ndev); -} -EXPORT_SYMBOL_GPL(st21nfcb_nci_remove); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h deleted file mode 100644 index 710636325c1f..000000000000 --- a/drivers/nfc/st21nfcb/st21nfcb.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * NCI based Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#ifndef __LOCAL_ST21NFCB_H_ -#define __LOCAL_ST21NFCB_H_ - -#include "st21nfcb_se.h" -#include "ndlc.h" - -/* Define private flags: */ -#define ST21NFCB_NCI_RUNNING 1 - -#define ST21NFCB_NCI_CORE_PROP 0x01 -#define ST21NFCB_NCI_SET_NFC_MODE 0x02 - -struct nci_mode_set_cmd { - u8 cmd_type; - u8 mode; -} __packed; - -struct nci_mode_set_rsp { - u8 status; -} __packed; - -struct st21nfcb_nci_info { - struct llt_ndlc *ndlc; - unsigned long flags; - struct st21nfcb_se_info se_info; -}; - -void st21nfcb_nci_remove(struct nci_dev *ndev); -int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, - int phy_tailroom); - -#endif /* __LOCAL_ST21NFCB_H_ */ diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st21nfcb/st21nfcb_se.c deleted file mode 100644 index 24862a525fb5..000000000000 --- a/drivers/nfc/st21nfcb/st21nfcb_se.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * NCI based Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#include -#include -#include -#include -#include - -#include "st21nfcb.h" -#include "st21nfcb_se.h" - -struct st21nfcb_pipe_info { - u8 pipe_state; - u8 src_host_id; - u8 src_gate_id; - u8 dst_host_id; - u8 dst_gate_id; -} __packed; - -/* Hosts */ -#define ST21NFCB_HOST_CONTROLLER_ID 0x00 -#define ST21NFCB_TERMINAL_HOST_ID 0x01 -#define ST21NFCB_UICC_HOST_ID 0x02 -#define ST21NFCB_ESE_HOST_ID 0xc0 - -/* Gates */ -#define ST21NFCB_DEVICE_MGNT_GATE 0x01 -#define ST21NFCB_APDU_READER_GATE 0xf0 -#define ST21NFCB_CONNECTIVITY_GATE 0x41 - -/* Pipes */ -#define ST21NFCB_DEVICE_MGNT_PIPE 0x02 - -/* Connectivity pipe only */ -#define ST21NFCB_SE_COUNT_PIPE_UICC 0x01 -/* Connectivity + APDU Reader pipe */ -#define ST21NFCB_SE_COUNT_PIPE_EMBEDDED 0x02 - -#define ST21NFCB_SE_TO_HOT_PLUG 1000 /* msecs */ -#define ST21NFCB_SE_TO_PIPES 2000 - -#define ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80) - -#define NCI_HCI_APDU_PARAM_ATR 0x01 -#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01 -#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03 -#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04 - -#define ST21NFCB_EVT_SE_HARD_RESET 0x20 -#define ST21NFCB_EVT_TRANSMIT_DATA 0x10 -#define ST21NFCB_EVT_WTX_REQUEST 0x11 -#define ST21NFCB_EVT_SE_SOFT_RESET 0x11 -#define ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER 0x21 -#define ST21NFCB_EVT_HOT_PLUG 0x03 - -#define ST21NFCB_SE_MODE_OFF 0x00 -#define ST21NFCB_SE_MODE_ON 0x01 - -#define ST21NFCB_EVT_CONNECTIVITY 0x10 -#define ST21NFCB_EVT_TRANSACTION 0x12 - -#define ST21NFCB_DM_GETINFO 0x13 -#define ST21NFCB_DM_GETINFO_PIPE_LIST 0x02 -#define ST21NFCB_DM_GETINFO_PIPE_INFO 0x01 -#define ST21NFCB_DM_PIPE_CREATED 0x02 -#define ST21NFCB_DM_PIPE_OPEN 0x04 -#define ST21NFCB_DM_RF_ACTIVE 0x80 -#define ST21NFCB_DM_DISCONNECT 0x30 - -#define ST21NFCB_DM_IS_PIPE_OPEN(p) \ - ((p & 0x0f) == (ST21NFCB_DM_PIPE_CREATED | ST21NFCB_DM_PIPE_OPEN)) - -#define ST21NFCB_ATR_DEFAULT_BWI 0x04 - -/* - * WT = 2^BWI/10[s], convert into msecs and add a secure - * room by increasing by 2 this timeout - */ -#define ST21NFCB_BWI_TO_TIMEOUT(x) ((1 << x) * 200) -#define ST21NFCB_ATR_GET_Y_FROM_TD(x) (x >> 4) - -/* If TA is present bit 0 is set */ -#define ST21NFCB_ATR_TA_PRESENT(x) (x & 0x01) -/* If TB is present bit 1 is set */ -#define ST21NFCB_ATR_TB_PRESENT(x) (x & 0x02) - -#define ST21NFCB_NUM_DEVICES 256 - -static DECLARE_BITMAP(dev_mask, ST21NFCB_NUM_DEVICES); - -/* Here are the mandatory pipe for st21nfcb */ -static struct nci_hci_gate st21nfcb_gates[] = { - {NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE, - ST21NFCB_HOST_CONTROLLER_ID}, - {NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE, - ST21NFCB_HOST_CONTROLLER_ID}, - {ST21NFCB_DEVICE_MGNT_GATE, ST21NFCB_DEVICE_MGNT_PIPE, - ST21NFCB_HOST_CONTROLLER_ID}, - - /* Secure element pipes are created by secure element host */ - {ST21NFCB_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, - ST21NFCB_HOST_CONTROLLER_ID}, - {ST21NFCB_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, - ST21NFCB_HOST_CONTROLLER_ID}, -}; - -static u8 st21nfcb_se_get_bwi(struct nci_dev *ndev) -{ - int i; - u8 td; - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */ - for (i = 1; i < ST21NFCB_ESE_MAX_LENGTH; i++) { - td = ST21NFCB_ATR_GET_Y_FROM_TD(info->se_info.atr[i]); - if (ST21NFCB_ATR_TA_PRESENT(td)) - i++; - if (ST21NFCB_ATR_TB_PRESENT(td)) { - i++; - return info->se_info.atr[i] >> 4; - } - } - return ST21NFCB_ATR_DEFAULT_BWI; -} - -static void st21nfcb_se_get_atr(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - int r; - struct sk_buff *skb; - - r = nci_hci_get_param(ndev, ST21NFCB_APDU_READER_GATE, - NCI_HCI_APDU_PARAM_ATR, &skb); - if (r < 0) - return; - - if (skb->len <= ST21NFCB_ESE_MAX_LENGTH) { - memcpy(info->se_info.atr, skb->data, skb->len); - - info->se_info.wt_timeout = - ST21NFCB_BWI_TO_TIMEOUT(st21nfcb_se_get_bwi(ndev)); - } - kfree_skb(skb); -} - -int st21nfcb_hci_load_session(struct nci_dev *ndev) -{ - int i, j, r; - struct sk_buff *skb_pipe_list, *skb_pipe_info; - struct st21nfcb_pipe_info *dm_pipe_info; - u8 pipe_list[] = { ST21NFCB_DM_GETINFO_PIPE_LIST, - ST21NFCB_TERMINAL_HOST_ID}; - u8 pipe_info[] = { ST21NFCB_DM_GETINFO_PIPE_INFO, - ST21NFCB_TERMINAL_HOST_ID, 0}; - - /* On ST21NFCB device pipes number are dynamics - * If pipes are already created, hci_dev_up will fail. - * Doing a clear all pipe is a bad idea because: - * - It does useless EEPROM cycling - * - It might cause issue for secure elements support - * (such as removing connectivity or APDU reader pipe) - * A better approach on ST21NFCB is to: - * - get a pipe list for each host. - * (eg: ST21NFCB_HOST_CONTROLLER_ID for now). - * (TODO Later on UICC HOST and eSE HOST) - * - get pipe information - * - match retrieved pipe list in st21nfcb_gates - * ST21NFCB_DEVICE_MGNT_GATE is a proprietary gate - * with ST21NFCB_DEVICE_MGNT_PIPE. - * Pipe can be closed and need to be open. - */ - r = nci_hci_connect_gate(ndev, ST21NFCB_HOST_CONTROLLER_ID, - ST21NFCB_DEVICE_MGNT_GATE, - ST21NFCB_DEVICE_MGNT_PIPE); - if (r < 0) - goto free_info; - - /* Get pipe list */ - r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE, - ST21NFCB_DM_GETINFO, pipe_list, sizeof(pipe_list), - &skb_pipe_list); - if (r < 0) - goto free_info; - - /* Complete the existing gate_pipe table */ - for (i = 0; i < skb_pipe_list->len; i++) { - pipe_info[2] = skb_pipe_list->data[i]; - r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE, - ST21NFCB_DM_GETINFO, pipe_info, - sizeof(pipe_info), &skb_pipe_info); - - if (r) - continue; - - /* - * Match pipe ID and gate ID - * Output format from ST21NFC_DM_GETINFO is: - * - pipe state (1byte) - * - source hid (1byte) - * - source gid (1byte) - * - destination hid (1byte) - * - destination gid (1byte) - */ - dm_pipe_info = (struct st21nfcb_pipe_info *)skb_pipe_info->data; - if (dm_pipe_info->dst_gate_id == ST21NFCB_APDU_READER_GATE && - dm_pipe_info->src_host_id != ST21NFCB_ESE_HOST_ID) { - pr_err("Unexpected apdu_reader pipe on host %x\n", - dm_pipe_info->src_host_id); - continue; - } - - for (j = 0; (j < ARRAY_SIZE(st21nfcb_gates)) && - (st21nfcb_gates[j].gate != dm_pipe_info->dst_gate_id); j++) - ; - - if (j < ARRAY_SIZE(st21nfcb_gates) && - st21nfcb_gates[j].gate == dm_pipe_info->dst_gate_id && - ST21NFCB_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) { - st21nfcb_gates[j].pipe = pipe_info[2]; - - ndev->hci_dev->gate2pipe[st21nfcb_gates[j].gate] = - st21nfcb_gates[j].pipe; - ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].gate = - st21nfcb_gates[j].gate; - ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].host = - dm_pipe_info->src_host_id; - } - } - - memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, - sizeof(st21nfcb_gates)); - -free_info: - kfree_skb(skb_pipe_info); - kfree_skb(skb_pipe_list); - return r; -} -EXPORT_SYMBOL_GPL(st21nfcb_hci_load_session); - -static void st21nfcb_hci_admin_event_received(struct nci_dev *ndev, - u8 event, struct sk_buff *skb) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - switch (event) { - case ST21NFCB_EVT_HOT_PLUG: - if (info->se_info.se_active) { - if (!ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(skb)) { - del_timer_sync(&info->se_info.se_active_timer); - info->se_info.se_active = false; - complete(&info->se_info.req_completion); - } else { - mod_timer(&info->se_info.se_active_timer, - jiffies + - msecs_to_jiffies(ST21NFCB_SE_TO_PIPES)); - } - } - break; - } -} - -static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev, - u8 event, - struct sk_buff *skb) -{ - int r = 0; - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - pr_debug("apdu reader gate event: %x\n", event); - - switch (event) { - case ST21NFCB_EVT_TRANSMIT_DATA: - del_timer_sync(&info->se_info.bwi_timer); - info->se_info.bwi_active = false; - info->se_info.cb(info->se_info.cb_context, - skb->data, skb->len, 0); - break; - case ST21NFCB_EVT_WTX_REQUEST: - mod_timer(&info->se_info.bwi_timer, jiffies + - msecs_to_jiffies(info->se_info.wt_timeout)); - break; - } - - kfree_skb(skb); - return r; -} - -/* - * Returns: - * <= 0: driver handled the event, skb consumed - * 1: driver does not handle the event, please do standard processing - */ -static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev, - u8 host, u8 event, - struct sk_buff *skb) -{ - int r = 0; - struct device *dev = &ndev->nfc_dev->dev; - struct nfc_evt_transaction *transaction; - - pr_debug("connectivity gate event: %x\n", event); - - switch (event) { - case ST21NFCB_EVT_CONNECTIVITY: - - break; - case ST21NFCB_EVT_TRANSACTION: - /* According to specification etsi 102 622 - * 11.2.2.4 EVT_TRANSACTION Table 52 - * Description Tag Length - * AID 81 5 to 16 - * PARAMETERS 82 0 to 255 - */ - if (skb->len < NFC_MIN_AID_LENGTH + 2 && - skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) - return -EPROTO; - - transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, - skb->len - 2, GFP_KERNEL); - - transaction->aid_len = skb->data[1]; - memcpy(transaction->aid, &skb->data[2], transaction->aid_len); - - /* Check next byte is PARAMETERS tag (82) */ - if (skb->data[transaction->aid_len + 2] != - NFC_EVT_TRANSACTION_PARAMS_TAG) - return -EPROTO; - - transaction->params_len = skb->data[transaction->aid_len + 3]; - memcpy(transaction->params, skb->data + - transaction->aid_len + 4, transaction->params_len); - - r = nfc_se_transaction(ndev->nfc_dev, host, transaction); - break; - default: - return 1; - } - kfree_skb(skb); - return r; -} - -void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe, - u8 event, struct sk_buff *skb) -{ - u8 gate = ndev->hci_dev->pipes[pipe].gate; - u8 host = ndev->hci_dev->pipes[pipe].host; - - switch (gate) { - case NCI_HCI_ADMIN_GATE: - st21nfcb_hci_admin_event_received(ndev, event, skb); - break; - case ST21NFCB_APDU_READER_GATE: - st21nfcb_hci_apdu_reader_event_received(ndev, event, skb); - break; - case ST21NFCB_CONNECTIVITY_GATE: - st21nfcb_hci_connectivity_event_received(ndev, host, event, - skb); - break; - } -} -EXPORT_SYMBOL_GPL(st21nfcb_hci_event_received); - - -void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, - struct sk_buff *skb) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - u8 gate = ndev->hci_dev->pipes[pipe].gate; - - pr_debug("cmd: %x\n", cmd); - - switch (cmd) { - case NCI_HCI_ANY_OPEN_PIPE: - if (gate != ST21NFCB_APDU_READER_GATE && - ndev->hci_dev->pipes[pipe].host != ST21NFCB_UICC_HOST_ID) - ndev->hci_dev->count_pipes++; - - if (ndev->hci_dev->count_pipes == - ndev->hci_dev->expected_pipes) { - del_timer_sync(&info->se_info.se_active_timer); - info->se_info.se_active = false; - ndev->hci_dev->count_pipes = 0; - complete(&info->se_info.req_completion); - } - break; - } -} -EXPORT_SYMBOL_GPL(st21nfcb_hci_cmd_received); - -/* - * Remarks: On some early st21nfcb firmware, nci_nfcee_mode_set(0) - * is rejected - */ -static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx, - u8 state) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - int r; - struct sk_buff *sk_host_list; - u8 host_id; - - switch (se_idx) { - case ST21NFCB_UICC_HOST_ID: - ndev->hci_dev->count_pipes = 0; - ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_UICC; - break; - case ST21NFCB_ESE_HOST_ID: - ndev->hci_dev->count_pipes = 0; - ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_EMBEDDED; - break; - default: - return -EINVAL; - } - - /* - * Wait for an EVT_HOT_PLUG in order to - * retrieve a relevant host list. - */ - reinit_completion(&info->se_info.req_completion); - r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); - if (r != NCI_STATUS_OK) - return r; - - mod_timer(&info->se_info.se_active_timer, jiffies + - msecs_to_jiffies(ST21NFCB_SE_TO_HOT_PLUG)); - info->se_info.se_active = true; - - /* Ignore return value and check in any case the host_list */ - wait_for_completion_interruptible(&info->se_info.req_completion); - - /* There might be some "collision" after receiving a HOT_PLUG event - * This may cause the CLF to not answer to the next hci command. - * There is no possible synchronization to prevent this. - * Adding a small delay is the only way to solve the issue. - */ - usleep_range(3000, 5000); - - r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, - NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); - if (r != NCI_HCI_ANY_OK) - return r; - - host_id = sk_host_list->data[sk_host_list->len - 1]; - kfree_skb(sk_host_list); - if (state == ST21NFCB_SE_MODE_ON && host_id == se_idx) - return se_idx; - else if (state == ST21NFCB_SE_MODE_OFF && host_id != se_idx) - return se_idx; - - return -1; -} - -int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx) -{ - int r; - - pr_debug("st21nfcb_nci_disable_se\n"); - - if (se_idx == NFC_SE_EMBEDDED) { - r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, - ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); - if (r < 0) - return r; - } - - return 0; -} -EXPORT_SYMBOL_GPL(st21nfcb_nci_disable_se); - -int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx) -{ - int r; - - pr_debug("st21nfcb_nci_enable_se\n"); - - if (se_idx == ST21NFCB_HCI_HOST_ID_ESE) { - r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, - ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0); - if (r < 0) - return r; - } - - return 0; -} -EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se); - -static int st21nfcb_hci_network_init(struct nci_dev *ndev) -{ - struct core_conn_create_dest_spec_params *dest_params; - struct dest_spec_params spec_params; - struct nci_conn_info *conn_info; - int r, dev_num; - - dest_params = - kzalloc(sizeof(struct core_conn_create_dest_spec_params) + - sizeof(struct dest_spec_params), GFP_KERNEL); - if (dest_params == NULL) { - r = -ENOMEM; - goto exit; - } - - dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE; - dest_params->length = sizeof(struct dest_spec_params); - spec_params.id = ndev->hci_dev->nfcee_id; - spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS; - memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params)); - r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1, - sizeof(struct core_conn_create_dest_spec_params) + - sizeof(struct dest_spec_params), - dest_params); - if (r != NCI_STATUS_OK) - goto free_dest_params; - - conn_info = ndev->hci_dev->conn_info; - if (!conn_info) - goto free_dest_params; - - memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, - sizeof(st21nfcb_gates)); - - /* - * Session id must include the driver name + i2c bus addr - * persistent info to discriminate 2 identical chips - */ - dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES); - if (dev_num >= ST21NFCB_NUM_DEVICES) { - r = -ENODEV; - goto free_dest_params; - } - - scnprintf(ndev->hci_dev->init_data.session_id, - sizeof(ndev->hci_dev->init_data.session_id), - "%s%2x", "ST21BH", dev_num); - - r = nci_hci_dev_session_init(ndev); - if (r != NCI_HCI_ANY_OK) - goto free_dest_params; - - r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, - NCI_NFCEE_ENABLE); - if (r != NCI_STATUS_OK) - goto free_dest_params; - -free_dest_params: - kfree(dest_params); - -exit: - return r; -} - -int st21nfcb_nci_discover_se(struct nci_dev *ndev) -{ - u8 param[2]; - int r; - int se_count = 0; - - pr_debug("st21nfcb_nci_discover_se\n"); - - r = st21nfcb_hci_network_init(ndev); - if (r != 0) - return r; - - param[0] = ST21NFCB_UICC_HOST_ID; - param[1] = ST21NFCB_HCI_HOST_ID_ESE; - r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, - NCI_HCI_ADMIN_PARAM_WHITELIST, - param, sizeof(param)); - if (r != NCI_HCI_ANY_OK) - return r; - - r = st21nfcb_nci_control_se(ndev, ST21NFCB_UICC_HOST_ID, - ST21NFCB_SE_MODE_ON); - if (r == ST21NFCB_UICC_HOST_ID) { - nfc_add_se(ndev->nfc_dev, ST21NFCB_UICC_HOST_ID, NFC_SE_UICC); - se_count++; - } - - /* Try to enable eSE in order to check availability */ - r = st21nfcb_nci_control_se(ndev, ST21NFCB_HCI_HOST_ID_ESE, - ST21NFCB_SE_MODE_ON); - if (r == ST21NFCB_HCI_HOST_ID_ESE) { - nfc_add_se(ndev->nfc_dev, ST21NFCB_HCI_HOST_ID_ESE, - NFC_SE_EMBEDDED); - se_count++; - st21nfcb_se_get_atr(ndev); - } - - return !se_count; -} -EXPORT_SYMBOL_GPL(st21nfcb_nci_discover_se); - -int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx, - u8 *apdu, size_t apdu_length, - se_io_cb_t cb, void *cb_context) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - pr_debug("\n"); - - switch (se_idx) { - case ST21NFCB_HCI_HOST_ID_ESE: - info->se_info.cb = cb; - info->se_info.cb_context = cb_context; - mod_timer(&info->se_info.bwi_timer, jiffies + - msecs_to_jiffies(info->se_info.wt_timeout)); - info->se_info.bwi_active = true; - return nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, - ST21NFCB_EVT_TRANSMIT_DATA, apdu, - apdu_length); - default: - return -ENODEV; - } -} -EXPORT_SYMBOL(st21nfcb_nci_se_io); - -static void st21nfcb_se_wt_timeout(unsigned long data) -{ - /* - * No answer from the secure element - * within the defined timeout. - * Let's send a reset request as recovery procedure. - * According to the situation, we first try to send a software reset - * to the secure element. If the next command is still not - * answering in time, we send to the CLF a secure element hardware - * reset request. - */ - /* hardware reset managed through VCC_UICC_OUT power supply */ - u8 param = 0x01; - struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data; - - pr_debug("\n"); - - info->se_info.bwi_active = false; - - if (!info->se_info.xch_error) { - info->se_info.xch_error = true; - nci_hci_send_event(info->ndlc->ndev, ST21NFCB_APDU_READER_GATE, - ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0); - } else { - info->se_info.xch_error = false; - nci_hci_send_event(info->ndlc->ndev, ST21NFCB_DEVICE_MGNT_GATE, - ST21NFCB_EVT_SE_HARD_RESET, ¶m, 1); - } - info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); -} - -static void st21nfcb_se_activation_timeout(unsigned long data) -{ - struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data; - - pr_debug("\n"); - - info->se_info.se_active = false; - - complete(&info->se_info.req_completion); -} - -int st21nfcb_se_init(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - init_completion(&info->se_info.req_completion); - /* initialize timers */ - init_timer(&info->se_info.bwi_timer); - info->se_info.bwi_timer.data = (unsigned long)info; - info->se_info.bwi_timer.function = st21nfcb_se_wt_timeout; - info->se_info.bwi_active = false; - - init_timer(&info->se_info.se_active_timer); - info->se_info.se_active_timer.data = (unsigned long)info; - info->se_info.se_active_timer.function = - st21nfcb_se_activation_timeout; - info->se_info.se_active = false; - - info->se_info.xch_error = false; - - info->se_info.wt_timeout = - ST21NFCB_BWI_TO_TIMEOUT(ST21NFCB_ATR_DEFAULT_BWI); - - return 0; -} -EXPORT_SYMBOL(st21nfcb_se_init); - -void st21nfcb_se_deinit(struct nci_dev *ndev) -{ - struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); - - if (info->se_info.bwi_active) - del_timer_sync(&info->se_info.bwi_timer); - if (info->se_info.se_active) - del_timer_sync(&info->se_info.se_active_timer); - - info->se_info.se_active = false; - info->se_info.bwi_active = false; -} -EXPORT_SYMBOL(st21nfcb_se_deinit); - diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.h b/drivers/nfc/st21nfcb/st21nfcb_se.h deleted file mode 100644 index 52a323872bea..000000000000 --- a/drivers/nfc/st21nfcb/st21nfcb_se.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * NCI based Driver for STMicroelectronics NFC Chip - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ -#ifndef __LOCAL_ST21NFCB_SE_H_ -#define __LOCAL_ST21NFCB_SE_H_ - -/* - * ref ISO7816-3 chap 8.1. the initial character TS is followed by a - * sequence of at most 32 characters. - */ -#define ST21NFCB_ESE_MAX_LENGTH 33 -#define ST21NFCB_HCI_HOST_ID_ESE 0xc0 - -struct st21nfcb_se_info { - u8 atr[ST21NFCB_ESE_MAX_LENGTH]; - struct completion req_completion; - - struct timer_list bwi_timer; - int wt_timeout; /* in msecs */ - bool bwi_active; - - struct timer_list se_active_timer; - bool se_active; - - bool xch_error; - - se_io_cb_t cb; - void *cb_context; -}; - -int st21nfcb_se_init(struct nci_dev *ndev); -void st21nfcb_se_deinit(struct nci_dev *ndev); - -int st21nfcb_nci_discover_se(struct nci_dev *ndev); -int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx); -int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx); -int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx, - u8 *apdu, size_t apdu_length, - se_io_cb_t cb, void *cb_context); -int st21nfcb_hci_load_session(struct nci_dev *ndev); -void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe, - u8 event, struct sk_buff *skb); -void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, - struct sk_buff *skb); - - -#endif /* __LOCAL_ST21NFCB_NCI_H_ */ diff --git a/include/linux/platform_data/st-nci.h b/include/linux/platform_data/st-nci.h new file mode 100644 index 000000000000..d9d400a297bd --- /dev/null +++ b/include/linux/platform_data/st-nci.h @@ -0,0 +1,29 @@ +/* + * Driver include for ST NCI NFC chip family. + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#ifndef _ST_NCI_H_ +#define _ST_NCI_H_ + +#define ST_NCI_DRIVER_NAME "st_nci" + +struct st_nci_nfc_platform_data { + unsigned int gpio_reset; + unsigned int irq_polarity; +}; + +#endif /* _ST_NCI_H_ */ diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h deleted file mode 100644 index b023373d9874..000000000000 --- a/include/linux/platform_data/st21nfcb.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Driver include for the ST21NFCB NFC chip. - * - * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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, see . - */ - -#ifndef _ST21NFCB_NCI_H_ -#define _ST21NFCB_NCI_H_ - -#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci" - -struct st21nfcb_nfc_platform_data { - unsigned int gpio_reset; - unsigned int irq_polarity; -}; - -#endif /* _ST21NFCB_NCI_H_ */ diff --git a/include/linux/platform_data/st_nci.h b/include/linux/platform_data/st_nci.h new file mode 100644 index 000000000000..d9d400a297bd --- /dev/null +++ b/include/linux/platform_data/st_nci.h @@ -0,0 +1,29 @@ +/* + * Driver include for ST NCI NFC chip family. + * + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#ifndef _ST_NCI_H_ +#define _ST_NCI_H_ + +#define ST_NCI_DRIVER_NAME "st_nci" + +struct st_nci_nfc_platform_data { + unsigned int gpio_reset; + unsigned int irq_polarity; +}; + +#endif /* _ST_NCI_H_ */ -- cgit v1.2.3-71-gd317 From dc14bdef8762a8098b1da881b611d722e24fe787 Mon Sep 17 00:00:00 2001 From: Vincent Cuissard Date: Thu, 11 Jun 2015 14:00:19 +0200 Subject: NFC: nfcmrvl: add platform_data and DT configuration Declare nfcmrvl platform_data structure and few DT parameters for nfcmrvl driver. Signed-off-by: Vincent Cuissard Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/main.c | 66 +++++++++++++++++++++++++++-------- drivers/nfc/nfcmrvl/nfcmrvl.h | 36 +++++++++++++------ drivers/nfc/nfcmrvl/usb.c | 6 +++- include/linux/platform_data/nfcmrvl.h | 31 ++++++++++++++++ 4 files changed, 113 insertions(+), 26 deletions(-) create mode 100644 include/linux/platform_data/nfcmrvl.h (limited to 'include/linux/platform_data') diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 708aad28c567..e317a69a4560 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb) if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags)) return -EBUSY; - if (priv->hci_muxed) { + if (priv->config.hci_muxed) { unsigned char *hdr; unsigned char len = skb->len; @@ -92,9 +93,9 @@ static struct nci_ops nfcmrvl_nci_ops = { }; struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, - struct nfcmrvl_if_ops *ops, - struct device *dev, - unsigned int flags) + struct nfcmrvl_if_ops *ops, + struct device *dev, + struct nfcmrvl_platform_data *pdata) { struct nfcmrvl_private *priv; int rc; @@ -108,23 +109,24 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, priv->drv_data = drv_data; priv->if_ops = ops; priv->dev = dev; - priv->hci_muxed = (flags & NFCMRVL_DEV_FLAG_HCI_MUXED) ? 1 : 0; - priv->reset_n_io = NFCMRVL_DEV_FLAG_GET_RESET_N_IO(flags); - if (priv->reset_n_io) { + memcpy(&priv->config, pdata, sizeof(*pdata)); + + if (priv->config.reset_n_io) { rc = devm_gpio_request_one(dev, - priv->reset_n_io, + priv->config.reset_n_io, GPIOF_OUT_INIT_LOW, "nfcmrvl_reset_n"); if (rc < 0) nfc_err(dev, "failed to request reset_n io\n"); } - if (priv->hci_muxed) + if (priv->config.hci_muxed) headroom = NFCMRVL_HCI_EVENT_HEADER_SIZE; protocols = NFC_PROTO_JEWEL_MASK - | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK + | NFC_PROTO_MIFARE_MASK + | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK | NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; @@ -169,7 +171,7 @@ EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev); int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb) { - if (priv->hci_muxed) { + if (priv->config.hci_muxed) { if (skb->data[0] == NFCMRVL_HCI_EVENT_CODE && skb->data[1] == NFCMRVL_HCI_NFC_EVENT_CODE) { /* Data packet, let's extract NCI payload */ @@ -200,15 +202,51 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv) * To be improved. */ - if (priv->reset_n_io) { + if (priv->config.reset_n_io) { nfc_info(priv->dev, "reset the chip\n"); - gpio_set_value(priv->reset_n_io, 0); + gpio_set_value(priv->config.reset_n_io, 0); usleep_range(5000, 10000); - gpio_set_value(priv->reset_n_io, 1); + gpio_set_value(priv->config.reset_n_io, 1); } else nfc_info(priv->dev, "no reset available on this interface\n"); } +#ifdef CONFIG_OF + +int nfcmrvl_parse_dt(struct device_node *node, + struct nfcmrvl_platform_data *pdata) +{ + int reset_n_io; + + reset_n_io = of_get_named_gpio(node, "reset-n-io", 0); + if (reset_n_io < 0) { + pr_info("no reset-n-io config\n"); + reset_n_io = 0; + } else if (!gpio_is_valid(reset_n_io)) { + pr_err("invalid reset-n-io GPIO\n"); + return reset_n_io; + } + pdata->reset_n_io = reset_n_io; + + if (of_find_property(node, "hci-muxed", NULL)) + pdata->hci_muxed = 1; + else + pdata->hci_muxed = 0; + + return 0; +} + +#else + +int nfcmrvl_parse_dt(struct device_node *node, + struct nfcmrvl_platform_data *pdata) +{ + return -ENODEV; +} + +#endif +EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt); + MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h index 2edae9a4b6bd..214412bd6110 100644 --- a/drivers/nfc/nfcmrvl/nfcmrvl.h +++ b/drivers/nfc/nfcmrvl/nfcmrvl.h @@ -16,6 +16,11 @@ * this warranty disclaimer. **/ +#ifndef _NFCMRVL_H_ +#define _NFCMRVL_H_ + +#include + /* Define private flags: */ #define NFCMRVL_NCI_RUNNING 1 @@ -38,22 +43,25 @@ #define NFCMRVL_HCI_OGF 0x81 #define NFCMRVL_HCI_OCF 0xFE -#define NFCMRVL_DEV_FLAG_HCI_MUXED (1 << 0) -#define NFCMRVL_DEV_FLAG_SET_RESET_N_IO(X) ((X) << 16) -#define NFCMRVL_DEV_FLAG_GET_RESET_N_IO(X) ((X) >> 16) struct nfcmrvl_private { - /* Tell if NCI packets are encapsulated in HCI ones */ - int hci_muxed; + unsigned long flags; + + /* Platform configuration */ + struct nfcmrvl_platform_data config; + struct nci_dev *ndev; - /* Reset IO (0 if not available) */ - int reset_n_io; + /* + ** PHY related information + */ - unsigned long flags; + /* PHY driver context */ void *drv_data; + /* PHY device */ struct device *dev; + /* Low level driver ops */ struct nfcmrvl_if_ops *if_ops; }; @@ -66,8 +74,14 @@ struct nfcmrvl_if_ops { void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv); int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb); struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, - struct nfcmrvl_if_ops *ops, - struct device *dev, - unsigned int flags); + struct nfcmrvl_if_ops *ops, + struct device *dev, + struct nfcmrvl_platform_data *pdata); + void nfcmrvl_chip_reset(struct nfcmrvl_private *priv); + +int nfcmrvl_parse_dt(struct device_node *node, + struct nfcmrvl_platform_data *pdata); + +#endif diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c index c4046b681bfa..aa3f3c1cff0a 100644 --- a/drivers/nfc/nfcmrvl/usb.c +++ b/drivers/nfc/nfcmrvl/usb.c @@ -302,6 +302,10 @@ static int nfcmrvl_probe(struct usb_interface *intf, struct nfcmrvl_private *priv; int i; struct usb_device *udev = interface_to_usbdev(intf); + struct nfcmrvl_platform_data config; + + /* No configuration for USB */ + memset(&config, 0, sizeof(config)); nfc_info(&udev->dev, "intf %p id %p\n", intf, id); @@ -339,7 +343,7 @@ static int nfcmrvl_probe(struct usb_interface *intf, init_usb_anchor(&drv_data->deferred); priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops, - &drv_data->udev->dev, 0); + &drv_data->udev->dev, &config); if (IS_ERR(priv)) return PTR_ERR(priv); diff --git a/include/linux/platform_data/nfcmrvl.h b/include/linux/platform_data/nfcmrvl.h new file mode 100644 index 000000000000..106cfe5ed589 --- /dev/null +++ b/include/linux/platform_data/nfcmrvl.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available on the worldwide web at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _NFCMRVL_PTF_H_ +#define _NFCMRVL_PTF_H_ + +struct nfcmrvl_platform_data { + /* + * Generic + */ + + /* GPIO that is wired to RESET_N signal */ + unsigned int reset_n_io; + /* Tell if transport is muxed in HCI one */ + unsigned int hci_muxed; +}; + +#endif /* _NFCMRVL_PTF_H_ */ -- cgit v1.2.3-71-gd317 From e097dc624f784debbde49701a493bf920bc422c7 Mon Sep 17 00:00:00 2001 From: Vincent Cuissard Date: Thu, 11 Jun 2015 14:00:20 +0200 Subject: NFC: nfcmrvl: add UART driver Add support of Marvell NFC chip controlled over UART Signed-off-by: Vincent Cuissard Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/nfcmrvl.txt | 29 +++ drivers/nfc/nfcmrvl/Kconfig | 11 + drivers/nfc/nfcmrvl/Makefile | 3 + drivers/nfc/nfcmrvl/nfcmrvl.h | 7 + drivers/nfc/nfcmrvl/uart.c | 225 +++++++++++++++++++++ include/linux/platform_data/nfcmrvl.h | 9 + net/nfc/nci/uart.c | 1 - 7 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt create mode 100644 drivers/nfc/nfcmrvl/uart.c (limited to 'include/linux/platform_data') diff --git a/Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt b/Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt new file mode 100644 index 000000000000..7c4a0cc370cf --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt @@ -0,0 +1,29 @@ +* Marvell International Ltd. NCI NFC Controller + +Required properties: +- compatible: Should be "mrvl,nfc-uart". + +Optional SoC specific properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- reset-n-io: Output GPIO pin used to reset the chip (active low). +- hci-muxed: Specifies that the chip is muxing NCI over HCI frames. + +Optional UART-based chip specific properties: +- flow-control: Specifies that the chip is using RTS/CTS. +- break-control: Specifies that the chip needs specific break management. + +Example (for ARM-based BeagleBoard Black with 88W8887 on UART5): + +&uart5 { + status = "okay"; + + nfcmrvluart: nfcmrvluart@5 { + compatible = "mrvl,nfc-uart"; + + reset-n-io = <&gpio3 16 0>; + + hci-muxed; + flow-control; + } +}; diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig index 5e18afd9abe2..796be2411440 100644 --- a/drivers/nfc/nfcmrvl/Kconfig +++ b/drivers/nfc/nfcmrvl/Kconfig @@ -21,3 +21,14 @@ config NFC_MRVL_USB Say Y here to compile support for Marvell NFC-over-USB driver into the kernel or say M to compile it as module. + +config NFC_MRVL_UART + tristate "Marvell NFC-over-UART driver" + depends on NFC_MRVL && NFC_NCI_UART + help + Marvell NFC-over-UART driver. + + This driver provides support for Marvell NFC-over-UART devices + + Say Y here to compile support for Marvell NFC-over-UART driver + into the kernel or say M to compile it as module. diff --git a/drivers/nfc/nfcmrvl/Makefile b/drivers/nfc/nfcmrvl/Makefile index 97a0de72dc01..775196274d1f 100644 --- a/drivers/nfc/nfcmrvl/Makefile +++ b/drivers/nfc/nfcmrvl/Makefile @@ -7,3 +7,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o nfcmrvl_usb-y += usb.o obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o + +nfcmrvl_uart-y += uart.o +obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h index 214412bd6110..09780d57c9b8 100644 --- a/drivers/nfc/nfcmrvl/nfcmrvl.h +++ b/drivers/nfc/nfcmrvl/nfcmrvl.h @@ -43,6 +43,11 @@ #define NFCMRVL_HCI_OGF 0x81 #define NFCMRVL_HCI_OCF 0xFE +enum nfcmrvl_phy { + NFCMRVL_PHY_USB = 0, + NFCMRVL_PHY_UART = 1, +}; + struct nfcmrvl_private { @@ -61,6 +66,8 @@ struct nfcmrvl_private { void *drv_data; /* PHY device */ struct device *dev; + /* PHY type */ + enum nfcmrvl_phy phy; /* Low level driver ops */ struct nfcmrvl_if_ops *if_ops; }; diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c new file mode 100644 index 000000000000..61442d6528a6 --- /dev/null +++ b/drivers/nfc/nfcmrvl/uart.c @@ -0,0 +1,225 @@ +/** + * Marvell NFC-over-UART driver + * + * Copyright (C) 2015, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available on the worldwide web at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include +#include +#include +#include +#include +#include "nfcmrvl.h" + +static unsigned int hci_muxed; +static unsigned int flow_control; +static unsigned int break_control; +static unsigned int reset_n_io; + +/* +** NFCMRVL NCI OPS +*/ + +static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv) +{ + return 0; +} + +static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv) +{ + return 0; +} + +static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv, + struct sk_buff *skb) +{ + struct nci_uart *nu = priv->drv_data; + + return nu->ops.send(nu, skb); +} + +static struct nfcmrvl_if_ops uart_ops = { + .nci_open = nfcmrvl_uart_nci_open, + .nci_close = nfcmrvl_uart_nci_close, + .nci_send = nfcmrvl_uart_nci_send, +}; + +#ifdef CONFIG_OF + +static int nfcmrvl_uart_parse_dt(struct device_node *node, + struct nfcmrvl_platform_data *pdata) +{ + struct device_node *matched_node; + int ret; + + matched_node = of_find_compatible_node(node, NULL, "mrvl,nfc-uart"); + if (!matched_node) + return -ENODEV; + + ret = nfcmrvl_parse_dt(matched_node, pdata); + if (ret < 0) { + pr_err("Failed to get generic entries\n"); + return ret; + } + + if (of_find_property(matched_node, "flow-control", NULL)) + pdata->flow_control = 1; + else + pdata->flow_control = 0; + + if (of_find_property(matched_node, "break-control", NULL)) + pdata->break_control = 1; + else + pdata->break_control = 0; + + return 0; +} + +#else + +static int nfcmrvl_uart_parse_dt(struct device_node *node, + struct nfcmrvl_platform_data *pdata) +{ + return -ENODEV; +} + +#endif + +/* +** NCI UART OPS +*/ + +static int nfcmrvl_nci_uart_open(struct nci_uart *nu) +{ + struct nfcmrvl_private *priv; + struct nfcmrvl_platform_data *pdata = NULL; + struct nfcmrvl_platform_data config; + + /* + * Platform data cannot be used here since usually it is already used + * by low level serial driver. We can try to retrieve serial device + * and check if DT entries were added. + */ + + if (nu->tty->dev->parent && nu->tty->dev->parent->of_node) + if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node, + &config) == 0) + pdata = &config; + + if (!pdata) { + pr_info("No platform data / DT -> fallback to module params\n"); + config.hci_muxed = hci_muxed; + config.reset_n_io = reset_n_io; + config.flow_control = flow_control; + config.break_control = break_control; + pdata = &config; + } + + priv = nfcmrvl_nci_register_dev(nu, &uart_ops, nu->tty->dev, pdata); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + priv->phy = NFCMRVL_PHY_UART; + + nu->drv_data = priv; + nu->ndev = priv->ndev; + + /* Set BREAK */ + if (priv->config.break_control && nu->tty->ops->break_ctl) + nu->tty->ops->break_ctl(nu->tty, -1); + + return 0; +} + +static void nfcmrvl_nci_uart_close(struct nci_uart *nu) +{ + nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data); +} + +static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb) +{ + return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data, + skb); +} + +static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu) +{ + struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; + + /* Remove BREAK to wake up the NFCC */ + if (priv->config.break_control && nu->tty->ops->break_ctl) { + nu->tty->ops->break_ctl(nu->tty, 0); + usleep_range(3000, 5000); + } +} + +static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu) +{ + struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; + + /* + ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him + ** up. we set BREAK. Once we will be ready to send again we will remove + ** it. + */ + if (priv->config.break_control && nu->tty->ops->break_ctl) + nu->tty->ops->break_ctl(nu->tty, -1); +} + +static struct nci_uart nfcmrvl_nci_uart = { + .owner = THIS_MODULE, + .name = "nfcmrvl_uart", + .driver = NCI_UART_DRIVER_MARVELL, + .ops = { + .open = nfcmrvl_nci_uart_open, + .close = nfcmrvl_nci_uart_close, + .recv = nfcmrvl_nci_uart_recv, + .tx_start = nfcmrvl_nci_uart_tx_start, + .tx_done = nfcmrvl_nci_uart_tx_done, + } +}; + +/* +** Module init +*/ + +static int nfcmrvl_uart_init_module(void) +{ + return nci_uart_register(&nfcmrvl_nci_uart); +} + +static void nfcmrvl_uart_exit_module(void) +{ + nci_uart_unregister(&nfcmrvl_nci_uart); +} + +module_init(nfcmrvl_uart_init_module); +module_exit(nfcmrvl_uart_exit_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell NFC-over-UART"); +MODULE_LICENSE("GPL v2"); + +module_param(flow_control, uint, 0); +MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init."); + +module_param(break_control, uint, 0); +MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal."); + +module_param(hci_muxed, uint, 0); +MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one."); + +module_param(reset_n_io, uint, 0); +MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal."); diff --git a/include/linux/platform_data/nfcmrvl.h b/include/linux/platform_data/nfcmrvl.h index 106cfe5ed589..ac91707dabcb 100644 --- a/include/linux/platform_data/nfcmrvl.h +++ b/include/linux/platform_data/nfcmrvl.h @@ -26,6 +26,15 @@ struct nfcmrvl_platform_data { unsigned int reset_n_io; /* Tell if transport is muxed in HCI one */ unsigned int hci_muxed; + + /* + * UART specific + */ + + /* Tell if UART needs flow control at init */ + unsigned int flow_control; + /* Tell if firmware supports break control for power management */ + unsigned int break_control; }; #endif /* _NFCMRVL_PTF_H_ */ diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 70c279543074..2c48810af5bb 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -12,7 +12,6 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. - */ /* Inspired (hugely) by HCI LDISC implementation in Bluetooth. -- cgit v1.2.3-71-gd317 From a9bd32a8b4c4c2670f9ed8cae63f9378b6df3ded Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 13 Mar 2015 11:09:45 -0700 Subject: msm: msm_fb: Remove dead code This code is no longer used now that mach-msm has been removed. Delete it. Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: David Brown Cc: Bryan Huntsman Cc: Daniel Walker Signed-off-by: Stephen Boyd Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/Kconfig | 7 - drivers/video/fbdev/Makefile | 1 - drivers/video/fbdev/msm/Makefile | 19 - drivers/video/fbdev/msm/mddi.c | 821 -------------------------- drivers/video/fbdev/msm/mddi_client_dummy.c | 85 --- drivers/video/fbdev/msm/mddi_client_nt35399.c | 252 -------- drivers/video/fbdev/msm/mddi_client_toshiba.c | 280 --------- drivers/video/fbdev/msm/mddi_hw.h | 305 ---------- drivers/video/fbdev/msm/mdp.c | 520 ---------------- drivers/video/fbdev/msm/mdp_csc_table.h | 582 ------------------ drivers/video/fbdev/msm/mdp_hw.h | 627 -------------------- drivers/video/fbdev/msm/mdp_ppp.c | 731 ----------------------- drivers/video/fbdev/msm/mdp_scale_tables.c | 766 ------------------------ drivers/video/fbdev/msm/mdp_scale_tables.h | 38 -- drivers/video/fbdev/msm/msm_fb.c | 659 --------------------- include/linux/platform_data/video-msm_fb.h | 146 ----- 16 files changed, 5839 deletions(-) delete mode 100644 drivers/video/fbdev/msm/Makefile delete mode 100644 drivers/video/fbdev/msm/mddi.c delete mode 100644 drivers/video/fbdev/msm/mddi_client_dummy.c delete mode 100644 drivers/video/fbdev/msm/mddi_client_nt35399.c delete mode 100644 drivers/video/fbdev/msm/mddi_client_toshiba.c delete mode 100644 drivers/video/fbdev/msm/mddi_hw.h delete mode 100644 drivers/video/fbdev/msm/mdp.c delete mode 100644 drivers/video/fbdev/msm/mdp_csc_table.h delete mode 100644 drivers/video/fbdev/msm/mdp_hw.h delete mode 100644 drivers/video/fbdev/msm/mdp_ppp.c delete mode 100644 drivers/video/fbdev/msm/mdp_scale_tables.c delete mode 100644 drivers/video/fbdev/msm/mdp_scale_tables.h delete mode 100644 drivers/video/fbdev/msm/msm_fb.c delete mode 100644 include/linux/platform_data/video-msm_fb.h (limited to 'include/linux/platform_data') diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 54fb8f86b68d..2d98de535e0f 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2326,13 +2326,6 @@ config FB_PRE_INIT_FB Select this option if display contents should be inherited as set by the bootloader. -config FB_MSM - tristate "MSM Framebuffer support" - depends on FB && ARCH_MSM - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - config FB_MX3 tristate "MX3 Framebuffer support" depends on FB && MX3_IPU diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 1979afffccfe..cecea5063a80 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -126,7 +126,6 @@ obj-y += omap2/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ -obj-$(CONFIG_FB_MSM) += msm/ obj-$(CONFIG_FB_NUC900) += nuc900fb.o obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile deleted file mode 100644 index 802d6ae523fb..000000000000 --- a/drivers/video/fbdev/msm/Makefile +++ /dev/null @@ -1,19 +0,0 @@ - -# core framebuffer -# -obj-y := msm_fb.o - -# MDP DMA/PPP engine -# -obj-y += mdp.o mdp_scale_tables.o mdp_ppp.o - -# MDDI interface -# -obj-y += mddi.o - -# MDDI client/panel drivers -# -obj-y += mddi_client_dummy.o -obj-y += mddi_client_toshiba.o -obj-y += mddi_client_nt35399.o - diff --git a/drivers/video/fbdev/msm/mddi.c b/drivers/video/fbdev/msm/mddi.c deleted file mode 100644 index e0f8011a3c4b..000000000000 --- a/drivers/video/fbdev/msm/mddi.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * MSM MDDI Transport - * - * Copyright (C) 2007 Google Incorporated - * Copyright (C) 2007 QUALCOMM Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mddi_hw.h" - -#define FLAG_DISABLE_HIBERNATION 0x0001 -#define FLAG_HAVE_CAPS 0x0002 -#define FLAG_HAS_VSYNC_IRQ 0x0004 -#define FLAG_HAVE_STATUS 0x0008 - -#define CMD_GET_CLIENT_CAP 0x0601 -#define CMD_GET_CLIENT_STATUS 0x0602 - -union mddi_rev { - unsigned char raw[MDDI_REV_BUFFER_SIZE]; - struct mddi_rev_packet hdr; - struct mddi_client_status status; - struct mddi_client_caps caps; - struct mddi_register_access reg; -}; - -struct reg_read_info { - struct completion done; - uint32_t reg; - uint32_t status; - uint32_t result; -}; - -struct mddi_info { - uint16_t flags; - uint16_t version; - char __iomem *base; - int irq; - struct clk *clk; - struct msm_mddi_client_data client_data; - - /* buffer for rev encap packets */ - void *rev_data; - dma_addr_t rev_addr; - struct mddi_llentry *reg_write_data; - dma_addr_t reg_write_addr; - struct mddi_llentry *reg_read_data; - dma_addr_t reg_read_addr; - size_t rev_data_curr; - - spinlock_t int_lock; - uint32_t int_enable; - uint32_t got_int; - wait_queue_head_t int_wait; - - struct mutex reg_write_lock; - struct mutex reg_read_lock; - struct reg_read_info *reg_read; - - struct mddi_client_caps caps; - struct mddi_client_status status; - - void (*power_client)(struct msm_mddi_client_data *, int); - - /* client device published to bind us to the - * appropriate mddi_client driver - */ - char client_name[20]; - - struct platform_device client_pdev; -}; - -static void mddi_init_rev_encap(struct mddi_info *mddi); - -#define mddi_readl(r) readl(mddi->base + (MDDI_##r)) -#define mddi_writel(v, r) writel((v), mddi->base + (MDDI_##r)) - -void mddi_activate_link(struct msm_mddi_client_data *cdata) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - - mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD); -} - -static void mddi_handle_link_list_done(struct mddi_info *mddi) -{ -} - -static void mddi_reset_rev_encap_ptr(struct mddi_info *mddi) -{ - printk(KERN_INFO "mddi: resetting rev ptr\n"); - mddi->rev_data_curr = 0; - mddi_writel(mddi->rev_addr, REV_PTR); - mddi_writel(mddi->rev_addr, REV_PTR); - mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD); -} - -static void mddi_handle_rev_data(struct mddi_info *mddi, union mddi_rev *rev) -{ - int i; - struct reg_read_info *ri; - - if ((rev->hdr.length <= MDDI_REV_BUFFER_SIZE - 2) && - (rev->hdr.length >= sizeof(struct mddi_rev_packet) - 2)) { - - switch (rev->hdr.type) { - case TYPE_CLIENT_CAPS: - memcpy(&mddi->caps, &rev->caps, - sizeof(struct mddi_client_caps)); - mddi->flags |= FLAG_HAVE_CAPS; - wake_up(&mddi->int_wait); - break; - case TYPE_CLIENT_STATUS: - memcpy(&mddi->status, &rev->status, - sizeof(struct mddi_client_status)); - mddi->flags |= FLAG_HAVE_STATUS; - wake_up(&mddi->int_wait); - break; - case TYPE_REGISTER_ACCESS: - ri = mddi->reg_read; - if (ri == 0) { - printk(KERN_INFO "rev: got reg %x = %x without " - " pending read\n", - rev->reg.register_address, - rev->reg.register_data_list); - break; - } - if (ri->reg != rev->reg.register_address) { - printk(KERN_INFO "rev: got reg %x = %x for " - "wrong register, expected " - "%x\n", - rev->reg.register_address, - rev->reg.register_data_list, ri->reg); - break; - } - mddi->reg_read = NULL; - ri->status = 0; - ri->result = rev->reg.register_data_list; - complete(&ri->done); - break; - default: - printk(KERN_INFO "rev: unknown reverse packet: " - "len=%04x type=%04x CURR_REV_PTR=%x\n", - rev->hdr.length, rev->hdr.type, - mddi_readl(CURR_REV_PTR)); - for (i = 0; i < rev->hdr.length + 2; i++) { - if ((i % 16) == 0) - printk(KERN_INFO "\n"); - printk(KERN_INFO " %02x", rev->raw[i]); - } - printk(KERN_INFO "\n"); - mddi_reset_rev_encap_ptr(mddi); - } - } else { - printk(KERN_INFO "bad rev length, %d, CURR_REV_PTR %x\n", - rev->hdr.length, mddi_readl(CURR_REV_PTR)); - mddi_reset_rev_encap_ptr(mddi); - } -} - -static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask); - -static void mddi_handle_rev_data_avail(struct mddi_info *mddi) -{ - uint32_t rev_data_count; - uint32_t rev_crc_err_count; - struct reg_read_info *ri; - size_t prev_offset; - uint16_t length; - - union mddi_rev *crev = mddi->rev_data + mddi->rev_data_curr; - - /* clear the interrupt */ - mddi_writel(MDDI_INT_REV_DATA_AVAIL, INT); - rev_data_count = mddi_readl(REV_PKT_CNT); - rev_crc_err_count = mddi_readl(REV_CRC_ERR); - if (rev_data_count > 1) - printk(KERN_INFO "rev_data_count %d\n", rev_data_count); - - if (rev_crc_err_count) { - printk(KERN_INFO "rev_crc_err_count %d, INT %x\n", - rev_crc_err_count, mddi_readl(INT)); - ri = mddi->reg_read; - if (ri == 0) { - printk(KERN_INFO "rev: got crc error without pending " - "read\n"); - } else { - mddi->reg_read = NULL; - ri->status = -EIO; - ri->result = -1; - complete(&ri->done); - } - } - - if (rev_data_count == 0) - return; - - prev_offset = mddi->rev_data_curr; - - length = *((uint8_t *)mddi->rev_data + mddi->rev_data_curr); - mddi->rev_data_curr++; - if (mddi->rev_data_curr == MDDI_REV_BUFFER_SIZE) - mddi->rev_data_curr = 0; - length += *((uint8_t *)mddi->rev_data + mddi->rev_data_curr) << 8; - mddi->rev_data_curr += 1 + length; - if (mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE) - mddi->rev_data_curr = - mddi->rev_data_curr % MDDI_REV_BUFFER_SIZE; - - if (length > MDDI_REV_BUFFER_SIZE - 2) { - printk(KERN_INFO "mddi: rev data length greater than buffer" - "size\n"); - mddi_reset_rev_encap_ptr(mddi); - return; - } - - if (prev_offset + 2 + length >= MDDI_REV_BUFFER_SIZE) { - union mddi_rev tmprev; - size_t rem = MDDI_REV_BUFFER_SIZE - prev_offset; - memcpy(&tmprev.raw[0], mddi->rev_data + prev_offset, rem); - memcpy(&tmprev.raw[rem], mddi->rev_data, 2 + length - rem); - mddi_handle_rev_data(mddi, &tmprev); - } else { - mddi_handle_rev_data(mddi, crev); - } - - if (prev_offset < MDDI_REV_BUFFER_SIZE / 2 && - mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE / 2) { - mddi_writel(mddi->rev_addr, REV_PTR); - } -} - -static irqreturn_t mddi_isr(int irq, void *data) -{ - struct msm_mddi_client_data *cdata = data; - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - uint32_t active, status; - - spin_lock(&mddi->int_lock); - - active = mddi_readl(INT); - status = mddi_readl(STAT); - - mddi_writel(active, INT); - - /* ignore any interrupts we have disabled */ - active &= mddi->int_enable; - - mddi->got_int |= active; - wake_up(&mddi->int_wait); - - if (active & MDDI_INT_PRI_LINK_LIST_DONE) { - mddi->int_enable &= (~MDDI_INT_PRI_LINK_LIST_DONE); - mddi_handle_link_list_done(mddi); - } - if (active & MDDI_INT_REV_DATA_AVAIL) - mddi_handle_rev_data_avail(mddi); - - if (active & ~MDDI_INT_NEED_CLEAR) - mddi->int_enable &= ~(active & ~MDDI_INT_NEED_CLEAR); - - if (active & MDDI_INT_LINK_ACTIVE) { - mddi->int_enable &= (~MDDI_INT_LINK_ACTIVE); - mddi->int_enable |= MDDI_INT_IN_HIBERNATION; - } - - if (active & MDDI_INT_IN_HIBERNATION) { - mddi->int_enable &= (~MDDI_INT_IN_HIBERNATION); - mddi->int_enable |= MDDI_INT_LINK_ACTIVE; - } - - mddi_writel(mddi->int_enable, INTEN); - spin_unlock(&mddi->int_lock); - - return IRQ_HANDLED; -} - -static long mddi_wait_interrupt_timeout(struct mddi_info *mddi, - uint32_t intmask, int timeout) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&mddi->int_lock, irq_flags); - mddi->got_int &= ~intmask; - mddi->int_enable |= intmask; - mddi_writel(mddi->int_enable, INTEN); - spin_unlock_irqrestore(&mddi->int_lock, irq_flags); - return wait_event_timeout(mddi->int_wait, mddi->got_int & intmask, - timeout); -} - -static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask) -{ - if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0) - printk(KERN_INFO "mddi_wait_interrupt %d, timeout " - "waiting for %x, INT = %x, STAT = %x gotint = %x\n", - current->pid, intmask, mddi_readl(INT), mddi_readl(STAT), - mddi->got_int); -} - -static void mddi_init_rev_encap(struct mddi_info *mddi) -{ - memset(mddi->rev_data, 0xee, MDDI_REV_BUFFER_SIZE); - mddi_writel(mddi->rev_addr, REV_PTR); - mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); -} - -void mddi_set_auto_hibernate(struct msm_mddi_client_data *cdata, int on) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - mddi_writel(MDDI_CMD_POWERDOWN, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_IN_HIBERNATION); - mddi_writel(MDDI_CMD_HIBERNATE | !!on, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); -} - - -static uint16_t mddi_init_registers(struct mddi_info *mddi) -{ - mddi_writel(0x0001, VERSION); - mddi_writel(MDDI_HOST_BYTES_PER_SUBFRAME, BPS); - mddi_writel(0x0003, SPM); /* subframes per media */ - mddi_writel(0x0005, TA1_LEN); - mddi_writel(MDDI_HOST_TA2_LEN, TA2_LEN); - mddi_writel(0x0096, DRIVE_HI); - /* 0x32 normal, 0x50 for Toshiba display */ - mddi_writel(0x0050, DRIVE_LO); - mddi_writel(0x003C, DISP_WAKE); /* wakeup counter */ - mddi_writel(MDDI_HOST_REV_RATE_DIV, REV_RATE_DIV); - - mddi_writel(MDDI_REV_BUFFER_SIZE, REV_SIZE); - mddi_writel(MDDI_MAX_REV_PKT_SIZE, REV_ENCAP_SZ); - - /* disable periodic rev encap */ - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - - if (mddi_readl(PAD_CTL) == 0) { - /* If we are turning on band gap, need to wait 5us before - * turning on the rest of the PAD */ - mddi_writel(0x08000, PAD_CTL); - udelay(5); - } - - /* Recommendation from PAD hw team */ - mddi_writel(0xa850f, PAD_CTL); - - - /* Need an even number for counts */ - mddi_writel(0x60006, DRIVER_START_CNT); - - mddi_set_auto_hibernate(&mddi->client_data, 0); - - mddi_writel(MDDI_CMD_DISP_IGNORE, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - - mddi_init_rev_encap(mddi); - return mddi_readl(CORE_VER) & 0xffff; -} - -static void mddi_suspend(struct msm_mddi_client_data *cdata) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - /* turn off the client */ - if (mddi->power_client) - mddi->power_client(&mddi->client_data, 0); - /* turn off the link */ - mddi_writel(MDDI_CMD_RESET, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - /* turn off the clock */ - clk_disable(mddi->clk); -} - -static void mddi_resume(struct msm_mddi_client_data *cdata) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - mddi_set_auto_hibernate(&mddi->client_data, 0); - /* turn on the client */ - if (mddi->power_client) - mddi->power_client(&mddi->client_data, 1); - /* turn on the clock */ - clk_enable(mddi->clk); - /* set up the local registers */ - mddi->rev_data_curr = 0; - mddi_init_registers(mddi); - mddi_writel(mddi->int_enable, INTEN); - mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD); - mddi_writel(MDDI_CMD_SEND_RTD, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - mddi_set_auto_hibernate(&mddi->client_data, 1); -} - -static int mddi_get_client_caps(struct mddi_info *mddi) -{ - int i, j; - - /* clear any stale interrupts */ - mddi_writel(0xffffffff, INT); - - mddi->int_enable = MDDI_INT_LINK_ACTIVE | - MDDI_INT_IN_HIBERNATION | - MDDI_INT_PRI_LINK_LIST_DONE | - MDDI_INT_REV_DATA_AVAIL | - MDDI_INT_REV_OVERFLOW | - MDDI_INT_REV_OVERWRITE | - MDDI_INT_RTD_FAILURE; - mddi_writel(mddi->int_enable, INTEN); - - mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - - for (j = 0; j < 3; j++) { - /* the toshiba vga panel does not respond to get - * caps unless you SEND_RTD, but the first SEND_RTD - * will fail... - */ - for (i = 0; i < 4; i++) { - uint32_t stat; - - mddi_writel(MDDI_CMD_SEND_RTD, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - stat = mddi_readl(STAT); - printk(KERN_INFO "mddi cmd send rtd: int %x, stat %x, " - "rtd val %x\n", mddi_readl(INT), stat, - mddi_readl(RTD_VAL)); - if ((stat & MDDI_STAT_RTD_MEAS_FAIL) == 0) - break; - msleep(1); - } - - mddi_writel(CMD_GET_CLIENT_CAP, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - wait_event_timeout(mddi->int_wait, mddi->flags & FLAG_HAVE_CAPS, - HZ / 100); - - if (mddi->flags & FLAG_HAVE_CAPS) - break; - printk(KERN_INFO "mddi_init, timeout waiting for caps\n"); - } - return mddi->flags & FLAG_HAVE_CAPS; -} - -/* link must be active when this is called */ -int mddi_check_status(struct mddi_info *mddi) -{ - int ret = -1, retry = 3; - mutex_lock(&mddi->reg_read_lock); - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - - do { - mddi->flags &= ~FLAG_HAVE_STATUS; - mddi_writel(CMD_GET_CLIENT_STATUS, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - wait_event_timeout(mddi->int_wait, - mddi->flags & FLAG_HAVE_STATUS, - HZ / 100); - - if (mddi->flags & FLAG_HAVE_STATUS) { - if (mddi->status.crc_error_count) - printk(KERN_INFO "mddi status: crc_error " - "count: %d\n", - mddi->status.crc_error_count); - else - ret = 0; - break; - } else - printk(KERN_INFO "mddi status: failed to get client " - "status\n"); - mddi_writel(MDDI_CMD_SEND_RTD, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - } while (--retry); - - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - mutex_unlock(&mddi->reg_read_lock); - return ret; -} - - -void mddi_remote_write(struct msm_mddi_client_data *cdata, uint32_t val, - uint32_t reg) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - struct mddi_llentry *ll; - struct mddi_register_access *ra; - - mutex_lock(&mddi->reg_write_lock); - - ll = mddi->reg_write_data; - - ra = &(ll->u.r); - ra->length = 14 + 4; - ra->type = TYPE_REGISTER_ACCESS; - ra->client_id = 0; - ra->read_write_info = MDDI_WRITE | 1; - ra->crc16 = 0; - - ra->register_address = reg; - ra->register_data_list = val; - - ll->flags = 1; - ll->header_count = 14; - ll->data_count = 4; - ll->data = mddi->reg_write_addr + offsetof(struct mddi_llentry, - u.r.register_data_list); - ll->next = 0; - ll->reserved = 0; - - mddi_writel(mddi->reg_write_addr, PRI_PTR); - - mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE); - mutex_unlock(&mddi->reg_write_lock); -} - -uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) -{ - struct mddi_info *mddi = container_of(cdata, struct mddi_info, - client_data); - struct mddi_llentry *ll; - struct mddi_register_access *ra; - struct reg_read_info ri; - unsigned s; - int retry_count = 2; - unsigned long irq_flags; - - mutex_lock(&mddi->reg_read_lock); - - ll = mddi->reg_read_data; - - ra = &(ll->u.r); - ra->length = 14; - ra->type = TYPE_REGISTER_ACCESS; - ra->client_id = 0; - ra->read_write_info = MDDI_READ | 1; - ra->crc16 = 0; - - ra->register_address = reg; - - ll->flags = 0x11; - ll->header_count = 14; - ll->data_count = 0; - ll->data = 0; - ll->next = 0; - ll->reserved = 0; - - s = mddi_readl(STAT); - - ri.reg = reg; - ri.status = -1; - - do { - init_completion(&ri.done); - mddi->reg_read = &ri; - mddi_writel(mddi->reg_read_addr, PRI_PTR); - - mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE); - - /* Enable Periodic Reverse Encapsulation. */ - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - if (wait_for_completion_timeout(&ri.done, HZ/10) == 0 && - !ri.done.done) { - printk(KERN_INFO "mddi_remote_read(%x) timeout " - "(%d %d %d)\n", - reg, ri.status, ri.result, ri.done.done); - spin_lock_irqsave(&mddi->int_lock, irq_flags); - mddi->reg_read = NULL; - spin_unlock_irqrestore(&mddi->int_lock, irq_flags); - ri.status = -1; - ri.result = -1; - } - if (ri.status == 0) - break; - - mddi_writel(MDDI_CMD_SEND_RTD, CMD); - mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - printk(KERN_INFO "mddi_remote_read: failed, sent " - "MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x " - "curr_rev_ptr %x\n", mddi_readl(INT), mddi_readl(STAT), - mddi_readl(RTD_VAL), mddi_readl(CURR_REV_PTR)); - } while (retry_count-- > 0); - /* Disable Periodic Reverse Encapsulation. */ - mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - mddi->reg_read = NULL; - mutex_unlock(&mddi->reg_read_lock); - return ri.result; -} - -static struct mddi_info mddi_info[2]; - -static int mddi_clk_setup(struct platform_device *pdev, struct mddi_info *mddi, - unsigned long clk_rate) -{ - int ret; - - /* set up the clocks */ - mddi->clk = clk_get(&pdev->dev, "mddi_clk"); - if (IS_ERR(mddi->clk)) { - printk(KERN_INFO "mddi: failed to get clock\n"); - return PTR_ERR(mddi->clk); - } - ret = clk_enable(mddi->clk); - if (ret) - goto fail; - ret = clk_set_rate(mddi->clk, clk_rate); - if (ret) - goto fail; - return 0; - -fail: - clk_put(mddi->clk); - return ret; -} - -static int __init mddi_rev_data_setup(struct mddi_info *mddi) -{ - void *dma; - dma_addr_t dma_addr; - - /* set up dma buffer */ - dma = dma_alloc_coherent(NULL, 0x1000, &dma_addr, GFP_KERNEL); - if (dma == 0) - return -ENOMEM; - mddi->rev_data = dma; - mddi->rev_data_curr = 0; - mddi->rev_addr = dma_addr; - mddi->reg_write_data = dma + MDDI_REV_BUFFER_SIZE; - mddi->reg_write_addr = dma_addr + MDDI_REV_BUFFER_SIZE; - mddi->reg_read_data = mddi->reg_write_data + 1; - mddi->reg_read_addr = mddi->reg_write_addr + - sizeof(*mddi->reg_write_data); - return 0; -} - -static int mddi_probe(struct platform_device *pdev) -{ - struct msm_mddi_platform_data *pdata = pdev->dev.platform_data; - struct mddi_info *mddi = &mddi_info[pdev->id]; - struct resource *resource; - int ret, i; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - printk(KERN_ERR "mddi: no associated mem resource!\n"); - return -ENOMEM; - } - mddi->base = ioremap(resource->start, resource_size(resource)); - if (!mddi->base) { - printk(KERN_ERR "mddi: failed to remap base!\n"); - ret = -EINVAL; - goto error_ioremap; - } - resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!resource) { - printk(KERN_ERR "mddi: no associated irq resource!\n"); - ret = -EINVAL; - goto error_get_irq_resource; - } - mddi->irq = resource->start; - printk(KERN_INFO "mddi: init() base=0x%p irq=%d\n", mddi->base, - mddi->irq); - mddi->power_client = pdata->power_client; - - mutex_init(&mddi->reg_write_lock); - mutex_init(&mddi->reg_read_lock); - spin_lock_init(&mddi->int_lock); - init_waitqueue_head(&mddi->int_wait); - - ret = mddi_clk_setup(pdev, mddi, pdata->clk_rate); - if (ret) { - printk(KERN_ERR "mddi: failed to setup clock!\n"); - goto error_clk_setup; - } - - ret = mddi_rev_data_setup(mddi); - if (ret) { - printk(KERN_ERR "mddi: failed to setup rev data!\n"); - goto error_rev_data; - } - - mddi->int_enable = 0; - mddi_writel(mddi->int_enable, INTEN); - ret = request_irq(mddi->irq, mddi_isr, 0, "mddi", - &mddi->client_data); - if (ret) { - printk(KERN_ERR "mddi: failed to request enable irq!\n"); - goto error_request_irq; - } - - /* turn on the mddi client bridge chip */ - if (mddi->power_client) - mddi->power_client(&mddi->client_data, 1); - - /* initialize the mddi registers */ - mddi_set_auto_hibernate(&mddi->client_data, 0); - mddi_writel(MDDI_CMD_RESET, CMD); - mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND); - mddi->version = mddi_init_registers(mddi); - if (mddi->version < 0x20) { - printk(KERN_ERR "mddi: unsupported version 0x%x\n", - mddi->version); - ret = -ENODEV; - goto error_mddi_version; - } - - /* read the capabilities off the client */ - if (!mddi_get_client_caps(mddi)) { - printk(KERN_INFO "mddi: no client found\n"); - /* power down the panel */ - mddi_writel(MDDI_CMD_POWERDOWN, CMD); - printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT)); - msleep(100); - printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT)); - return 0; - } - mddi_set_auto_hibernate(&mddi->client_data, 1); - - if (mddi->caps.Mfr_Name == 0 && mddi->caps.Product_Code == 0) - pdata->fixup(&mddi->caps.Mfr_Name, &mddi->caps.Product_Code); - - mddi->client_pdev.id = 0; - for (i = 0; i < pdata->num_clients; i++) { - if (pdata->client_platform_data[i].product_id == - (mddi->caps.Mfr_Name << 16 | mddi->caps.Product_Code)) { - mddi->client_data.private_client_data = - pdata->client_platform_data[i].client_data; - mddi->client_pdev.name = - pdata->client_platform_data[i].name; - mddi->client_pdev.id = - pdata->client_platform_data[i].id; - /* XXX: possibly set clock */ - break; - } - } - - if (i >= pdata->num_clients) - mddi->client_pdev.name = "mddi_c_dummy"; - printk(KERN_INFO "mddi: registering panel %s\n", - mddi->client_pdev.name); - - mddi->client_data.suspend = mddi_suspend; - mddi->client_data.resume = mddi_resume; - mddi->client_data.activate_link = mddi_activate_link; - mddi->client_data.remote_write = mddi_remote_write; - mddi->client_data.remote_read = mddi_remote_read; - mddi->client_data.auto_hibernate = mddi_set_auto_hibernate; - mddi->client_data.fb_resource = pdata->fb_resource; - if (pdev->id == 0) - mddi->client_data.interface_type = MSM_MDDI_PMDH_INTERFACE; - else if (pdev->id == 1) - mddi->client_data.interface_type = MSM_MDDI_EMDH_INTERFACE; - else { - printk(KERN_ERR "mddi: can not determine interface %d!\n", - pdev->id); - ret = -EINVAL; - goto error_mddi_interface; - } - - mddi->client_pdev.dev.platform_data = &mddi->client_data; - printk(KERN_INFO "mddi: publish: %s\n", mddi->client_name); - platform_device_register(&mddi->client_pdev); - return 0; - -error_mddi_interface: -error_mddi_version: - free_irq(mddi->irq, 0); -error_request_irq: - dma_free_coherent(NULL, 0x1000, mddi->rev_data, mddi->rev_addr); -error_rev_data: -error_clk_setup: -error_get_irq_resource: - iounmap(mddi->base); -error_ioremap: - - printk(KERN_INFO "mddi: mddi_init() failed (%d)\n", ret); - return ret; -} - - -static struct platform_driver mddi_driver = { - .probe = mddi_probe, - .driver = { .name = "msm_mddi" }, -}; - -static int __init _mddi_init(void) -{ - return platform_driver_register(&mddi_driver); -} - -module_init(_mddi_init); diff --git a/drivers/video/fbdev/msm/mddi_client_dummy.c b/drivers/video/fbdev/msm/mddi_client_dummy.c deleted file mode 100644 index cdb8f69a5d88..000000000000 --- a/drivers/video/fbdev/msm/mddi_client_dummy.c +++ /dev/null @@ -1,85 +0,0 @@ -/* drivers/video/msm_fb/mddi_client_dummy.c - * - * Support for "dummy" mddi client devices which require no - * special initialization code. - * - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include - -struct panel_info { - struct platform_device pdev; - struct msm_panel_data panel_data; -}; - -static int mddi_dummy_suspend(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_resume(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_blank(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_unblank(struct msm_panel_data *panel_data) -{ - return 0; -} - -static int mddi_dummy_probe(struct platform_device *pdev) -{ - struct msm_mddi_client_data *client_data = pdev->dev.platform_data; - struct panel_info *panel = - devm_kzalloc(&pdev->dev, sizeof(struct panel_info), GFP_KERNEL); - if (!panel) - return -ENOMEM; - platform_set_drvdata(pdev, panel); - panel->panel_data.suspend = mddi_dummy_suspend; - panel->panel_data.resume = mddi_dummy_resume; - panel->panel_data.blank = mddi_dummy_blank; - panel->panel_data.unblank = mddi_dummy_unblank; - panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES; - panel->pdev.name = "msm_panel"; - panel->pdev.id = pdev->id; - platform_device_add_resources(&panel->pdev, - client_data->fb_resource, 1); - panel->panel_data.fb_data = client_data->private_client_data; - panel->pdev.dev.platform_data = &panel->panel_data; - return platform_device_register(&panel->pdev); -} - -static struct platform_driver mddi_client_dummy = { - .probe = mddi_dummy_probe, - .driver = { .name = "mddi_c_dummy" }, -}; - -static int __init mddi_client_dummy_init(void) -{ - platform_driver_register(&mddi_client_dummy); - return 0; -} - -module_init(mddi_client_dummy_init); - diff --git a/drivers/video/fbdev/msm/mddi_client_nt35399.c b/drivers/video/fbdev/msm/mddi_client_nt35399.c deleted file mode 100644 index f96df32e5509..000000000000 --- a/drivers/video/fbdev/msm/mddi_client_nt35399.c +++ /dev/null @@ -1,252 +0,0 @@ -/* drivers/video/msm_fb/mddi_client_nt35399.c - * - * Support for Novatek NT35399 MDDI client of Sapphire - * - * Copyright (C) 2008 HTC Incorporated - * Author: Solomon Chiu (solomon_chiu@htc.com) - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait); - -struct panel_info { - struct msm_mddi_client_data *client_data; - struct platform_device pdev; - struct msm_panel_data panel_data; - struct msmfb_callback *fb_callback; - struct work_struct panel_work; - struct workqueue_struct *fb_wq; - int nt35399_got_int; -}; - -static void -nt35399_request_vsync(struct msm_panel_data *panel_data, - struct msmfb_callback *callback) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - panel->fb_callback = callback; - if (panel->nt35399_got_int) { - panel->nt35399_got_int = 0; - client_data->activate_link(client_data); /* clears interrupt */ - } -} - -static void nt35399_wait_vsync(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - if (panel->nt35399_got_int) { - panel->nt35399_got_int = 0; - client_data->activate_link(client_data); /* clears interrupt */ - } - - if (wait_event_timeout(nt35399_vsync_wait, panel->nt35399_got_int, - HZ/2) == 0) - printk(KERN_ERR "timeout waiting for VSYNC\n"); - - panel->nt35399_got_int = 0; - /* interrupt clears when screen dma starts */ -} - -static int nt35399_suspend(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - int ret; - - ret = bridge_data->uninit(bridge_data, client_data); - if (ret) { - printk(KERN_INFO "mddi nt35399 client: non zero return from " - "uninit\n"); - return ret; - } - client_data->suspend(client_data); - return 0; -} - -static int nt35399_resume(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - int ret; - - client_data->resume(client_data); - ret = bridge_data->init(bridge_data, client_data); - if (ret) - return ret; - return 0; -} - -static int nt35399_blank(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - - return bridge_data->blank(bridge_data, client_data); -} - -static int nt35399_unblank(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - - return bridge_data->unblank(bridge_data, client_data); -} - -irqreturn_t nt35399_vsync_interrupt(int irq, void *data) -{ - struct panel_info *panel = data; - - panel->nt35399_got_int = 1; - - if (panel->fb_callback) { - panel->fb_callback->func(panel->fb_callback); - panel->fb_callback = NULL; - } - - wake_up(&nt35399_vsync_wait); - - return IRQ_HANDLED; -} - -static int setup_vsync(struct panel_info *panel, int init) -{ - int ret; - int gpio = 97; - unsigned int irq; - - if (!init) { - ret = 0; - goto uninit; - } - ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); - if (ret) - goto err_request_gpio_failed; - - ret = irq = gpio_to_irq(gpio); - if (ret < 0) - goto err_get_irq_num_failed; - - ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING, - "vsync", panel); - if (ret) - goto err_request_irq_failed; - - printk(KERN_INFO "vsync on gpio %d now %d\n", - gpio, gpio_get_value(gpio)); - return 0; - -uninit: - free_irq(gpio_to_irq(gpio), panel->client_data); -err_request_irq_failed: -err_get_irq_num_failed: - gpio_free(gpio); -err_request_gpio_failed: - return ret; -} - -static int mddi_nt35399_probe(struct platform_device *pdev) -{ - struct msm_mddi_client_data *client_data = pdev->dev.platform_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - - int ret; - - struct panel_info *panel = devm_kzalloc(&pdev->dev, - sizeof(struct panel_info), - GFP_KERNEL); - - printk(KERN_DEBUG "%s: enter.\n", __func__); - - if (!panel) - return -ENOMEM; - platform_set_drvdata(pdev, panel); - - ret = setup_vsync(panel, 1); - if (ret) { - dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n"); - return ret; - } - - panel->client_data = client_data; - panel->panel_data.suspend = nt35399_suspend; - panel->panel_data.resume = nt35399_resume; - panel->panel_data.wait_vsync = nt35399_wait_vsync; - panel->panel_data.request_vsync = nt35399_request_vsync; - panel->panel_data.blank = nt35399_blank; - panel->panel_data.unblank = nt35399_unblank; - panel->panel_data.fb_data = &bridge_data->fb_data; - panel->panel_data.caps = 0; - - panel->pdev.name = "msm_panel"; - panel->pdev.id = pdev->id; - panel->pdev.resource = client_data->fb_resource; - panel->pdev.num_resources = 1; - panel->pdev.dev.platform_data = &panel->panel_data; - - if (bridge_data->init) - bridge_data->init(bridge_data, client_data); - - platform_device_register(&panel->pdev); - - return 0; -} - -static int mddi_nt35399_remove(struct platform_device *pdev) -{ - struct panel_info *panel = platform_get_drvdata(pdev); - - setup_vsync(panel, 0); - return 0; -} - -static struct platform_driver mddi_client_0bda_8a47 = { - .probe = mddi_nt35399_probe, - .remove = mddi_nt35399_remove, - .driver = { .name = "mddi_c_0bda_8a47" }, -}; - -static int __init mddi_client_nt35399_init(void) -{ - return platform_driver_register(&mddi_client_0bda_8a47); -} - -module_init(mddi_client_nt35399_init); - diff --git a/drivers/video/fbdev/msm/mddi_client_toshiba.c b/drivers/video/fbdev/msm/mddi_client_toshiba.c deleted file mode 100644 index 061d7dfebbf3..000000000000 --- a/drivers/video/fbdev/msm/mddi_client_toshiba.c +++ /dev/null @@ -1,280 +0,0 @@ -/* drivers/video/msm_fb/mddi_client_toshiba.c - * - * Support for Toshiba TC358720XBG mddi client devices which require no - * special initialization code. - * - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define LCD_CONTROL_BLOCK_BASE 0x110000 -#define CMN (LCD_CONTROL_BLOCK_BASE|0x10) -#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) -#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) -#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) -#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0) -#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) -#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) -#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58) -#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) - -#define BASE5 0x150000 -#define BASE6 0x160000 -#define BASE7 0x170000 - -#define GPIOIEV (BASE5 + 0x10) -#define GPIOIE (BASE5 + 0x14) -#define GPIORIS (BASE5 + 0x18) -#define GPIOMIS (BASE5 + 0x1C) -#define GPIOIC (BASE5 + 0x20) - -#define INTMASK (BASE6 + 0x0C) -#define INTMASK_VWAKEOUT (1U << 0) -#define INTMASK_VWAKEOUT_ACTIVE_LOW (1U << 8) -#define GPIOSEL (BASE7 + 0x00) -#define GPIOSEL_VWAKEINT (1U << 0) - -static DECLARE_WAIT_QUEUE_HEAD(toshiba_vsync_wait); - -struct panel_info { - struct msm_mddi_client_data *client_data; - struct platform_device pdev; - struct msm_panel_data panel_data; - struct msmfb_callback *toshiba_callback; - int toshiba_got_int; -}; - - -static void toshiba_request_vsync(struct msm_panel_data *panel_data, - struct msmfb_callback *callback) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - panel->toshiba_callback = callback; - if (panel->toshiba_got_int) { - panel->toshiba_got_int = 0; - client_data->activate_link(client_data); - } -} - -static void toshiba_clear_vsync(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - client_data->activate_link(client_data); -} - -static void toshiba_wait_vsync(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - if (panel->toshiba_got_int) { - panel->toshiba_got_int = 0; - client_data->activate_link(client_data); /* clears interrupt */ - } - if (wait_event_timeout(toshiba_vsync_wait, panel->toshiba_got_int, - HZ/2) == 0) - printk(KERN_ERR "timeout waiting for VSYNC\n"); - panel->toshiba_got_int = 0; - /* interrupt clears when screen dma starts */ -} - -static int toshiba_suspend(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - int ret; - - ret = bridge_data->uninit(bridge_data, client_data); - if (ret) { - printk(KERN_INFO "mddi toshiba client: non zero return from " - "uninit\n"); - return ret; - } - client_data->suspend(client_data); - return 0; -} - -static int toshiba_resume(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - int ret; - - client_data->resume(client_data); - ret = bridge_data->init(bridge_data, client_data); - if (ret) - return ret; - return 0; -} - -static int toshiba_blank(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - - return bridge_data->blank(bridge_data, client_data); -} - -static int toshiba_unblank(struct msm_panel_data *panel_data) -{ - struct panel_info *panel = container_of(panel_data, struct panel_info, - panel_data); - struct msm_mddi_client_data *client_data = panel->client_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - - return bridge_data->unblank(bridge_data, client_data); -} - -irqreturn_t toshiba_vsync_interrupt(int irq, void *data) -{ - struct panel_info *panel = data; - - panel->toshiba_got_int = 1; - if (panel->toshiba_callback) { - panel->toshiba_callback->func(panel->toshiba_callback); - panel->toshiba_callback = 0; - } - wake_up(&toshiba_vsync_wait); - return IRQ_HANDLED; -} - -static int setup_vsync(struct panel_info *panel, - int init) -{ - int ret; - int gpio = 97; - unsigned int irq; - - if (!init) { - ret = 0; - goto uninit; - } - ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); - if (ret) - goto err_request_gpio_failed; - - ret = irq = gpio_to_irq(gpio); - if (ret < 0) - goto err_get_irq_num_failed; - - ret = request_irq(irq, toshiba_vsync_interrupt, IRQF_TRIGGER_RISING, - "vsync", panel); - if (ret) - goto err_request_irq_failed; - printk(KERN_INFO "vsync on gpio %d now %d\n", - gpio, gpio_get_value(gpio)); - return 0; - -uninit: - free_irq(gpio_to_irq(gpio), panel); -err_request_irq_failed: -err_get_irq_num_failed: - gpio_free(gpio); -err_request_gpio_failed: - return ret; -} - -static int mddi_toshiba_probe(struct platform_device *pdev) -{ - int ret; - struct msm_mddi_client_data *client_data = pdev->dev.platform_data; - struct msm_mddi_bridge_platform_data *bridge_data = - client_data->private_client_data; - struct panel_info *panel = - kzalloc(sizeof(struct panel_info), GFP_KERNEL); - if (!panel) - return -ENOMEM; - platform_set_drvdata(pdev, panel); - - /* mddi_remote_write(mddi, 0, WAKEUP); */ - client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL); - client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK); - - ret = setup_vsync(panel, 1); - if (ret) { - dev_err(&pdev->dev, "mddi_bridge_setup_vsync failed\n"); - return ret; - } - - panel->client_data = client_data; - panel->panel_data.suspend = toshiba_suspend; - panel->panel_data.resume = toshiba_resume; - panel->panel_data.wait_vsync = toshiba_wait_vsync; - panel->panel_data.request_vsync = toshiba_request_vsync; - panel->panel_data.clear_vsync = toshiba_clear_vsync; - panel->panel_data.blank = toshiba_blank; - panel->panel_data.unblank = toshiba_unblank; - panel->panel_data.fb_data = &bridge_data->fb_data; - panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES; - - panel->pdev.name = "msm_panel"; - panel->pdev.id = pdev->id; - panel->pdev.resource = client_data->fb_resource; - panel->pdev.num_resources = 1; - panel->pdev.dev.platform_data = &panel->panel_data; - bridge_data->init(bridge_data, client_data); - platform_device_register(&panel->pdev); - - return 0; -} - -static int mddi_toshiba_remove(struct platform_device *pdev) -{ - struct panel_info *panel = platform_get_drvdata(pdev); - - setup_vsync(panel, 0); - kfree(panel); - return 0; -} - -static struct platform_driver mddi_client_d263_0000 = { - .probe = mddi_toshiba_probe, - .remove = mddi_toshiba_remove, - .driver = { .name = "mddi_c_d263_0000" }, -}; - -static int __init mddi_client_toshiba_init(void) -{ - platform_driver_register(&mddi_client_d263_0000); - return 0; -} - -module_init(mddi_client_toshiba_init); - diff --git a/drivers/video/fbdev/msm/mddi_hw.h b/drivers/video/fbdev/msm/mddi_hw.h deleted file mode 100644 index 45cc01fc1e7f..000000000000 --- a/drivers/video/fbdev/msm/mddi_hw.h +++ /dev/null @@ -1,305 +0,0 @@ -/* drivers/video/msm_fb/mddi_hw.h - * - * MSM MDDI Hardware Registers and Structures - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MDDI_HW_H_ -#define _MDDI_HW_H_ - -#include - -#define MDDI_CMD 0x0000 -#define MDDI_VERSION 0x0004 -#define MDDI_PRI_PTR 0x0008 -#define MDDI_SEC_PTR 0x000c -#define MDDI_BPS 0x0010 -#define MDDI_SPM 0x0014 -#define MDDI_INT 0x0018 -#define MDDI_INTEN 0x001c -#define MDDI_REV_PTR 0x0020 -#define MDDI_REV_SIZE 0x0024 -#define MDDI_STAT 0x0028 -#define MDDI_REV_RATE_DIV 0x002c -#define MDDI_REV_CRC_ERR 0x0030 -#define MDDI_TA1_LEN 0x0034 -#define MDDI_TA2_LEN 0x0038 -#define MDDI_TEST_BUS 0x003c -#define MDDI_TEST 0x0040 -#define MDDI_REV_PKT_CNT 0x0044 -#define MDDI_DRIVE_HI 0x0048 -#define MDDI_DRIVE_LO 0x004c -#define MDDI_DISP_WAKE 0x0050 -#define MDDI_REV_ENCAP_SZ 0x0054 -#define MDDI_RTD_VAL 0x0058 -#define MDDI_PAD_CTL 0x0068 -#define MDDI_DRIVER_START_CNT 0x006c -#define MDDI_NEXT_PRI_PTR 0x0070 -#define MDDI_NEXT_SEC_PTR 0x0074 -#define MDDI_MISR_CTL 0x0078 -#define MDDI_MISR_DATA 0x007c -#define MDDI_SF_CNT 0x0080 -#define MDDI_MF_CNT 0x0084 -#define MDDI_CURR_REV_PTR 0x0088 -#define MDDI_CORE_VER 0x008c - -#define MDDI_INT_PRI_PTR_READ 0x0001 -#define MDDI_INT_SEC_PTR_READ 0x0002 -#define MDDI_INT_REV_DATA_AVAIL 0x0004 -#define MDDI_INT_DISP_REQ 0x0008 -#define MDDI_INT_PRI_UNDERFLOW 0x0010 -#define MDDI_INT_SEC_UNDERFLOW 0x0020 -#define MDDI_INT_REV_OVERFLOW 0x0040 -#define MDDI_INT_CRC_ERROR 0x0080 -#define MDDI_INT_MDDI_IN 0x0100 -#define MDDI_INT_PRI_OVERWRITE 0x0200 -#define MDDI_INT_SEC_OVERWRITE 0x0400 -#define MDDI_INT_REV_OVERWRITE 0x0800 -#define MDDI_INT_DMA_FAILURE 0x1000 -#define MDDI_INT_LINK_ACTIVE 0x2000 -#define MDDI_INT_IN_HIBERNATION 0x4000 -#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000 -#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000 -#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000 -#define MDDI_INT_RTD_FAILURE 0x40000 -#define MDDI_INT_REV_PKT_RECEIVED 0x80000 -#define MDDI_INT_REV_PKTS_AVAIL 0x100000 - -#define MDDI_INT_NEED_CLEAR ( \ - MDDI_INT_REV_DATA_AVAIL | \ - MDDI_INT_PRI_UNDERFLOW | \ - MDDI_INT_SEC_UNDERFLOW | \ - MDDI_INT_REV_OVERFLOW | \ - MDDI_INT_CRC_ERROR | \ - MDDI_INT_REV_PKT_RECEIVED) - - -#define MDDI_STAT_LINK_ACTIVE 0x0001 -#define MDDI_STAT_NEW_REV_PTR 0x0002 -#define MDDI_STAT_NEW_PRI_PTR 0x0004 -#define MDDI_STAT_NEW_SEC_PTR 0x0008 -#define MDDI_STAT_IN_HIBERNATION 0x0010 -#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020 -#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040 -#define MDDI_STAT_PENDING_TIMING_PKT 0x0080 -#define MDDI_STAT_PENDING_REV_ENCAP 0x0100 -#define MDDI_STAT_PENDING_POWERDOWN 0x0200 -#define MDDI_STAT_RTD_MEAS_FAIL 0x0800 -#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000 - - -#define MDDI_CMD_POWERDOWN 0x0100 -#define MDDI_CMD_POWERUP 0x0200 -#define MDDI_CMD_HIBERNATE 0x0300 -#define MDDI_CMD_RESET 0x0400 -#define MDDI_CMD_DISP_IGNORE 0x0501 -#define MDDI_CMD_DISP_LISTEN 0x0500 -#define MDDI_CMD_SEND_REV_ENCAP 0x0600 -#define MDDI_CMD_GET_CLIENT_CAP 0x0601 -#define MDDI_CMD_GET_CLIENT_STATUS 0x0602 -#define MDDI_CMD_SEND_RTD 0x0700 -#define MDDI_CMD_LINK_ACTIVE 0x0900 -#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00 -#define MDDI_CMD_FORCE_NEW_REV_PTR 0x0C00 - - - -#define MDDI_VIDEO_REV_PKT_SIZE 0x40 -#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60 -#define MDDI_MAX_REV_PKT_SIZE 0x60 - -/* #define MDDI_REV_BUFFER_SIZE 128 */ -#define MDDI_REV_BUFFER_SIZE (MDDI_MAX_REV_PKT_SIZE * 4) - -/* MDP sends 256 pixel packets, so lower value hibernates more without - * significantly increasing latency of waiting for next subframe */ -#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00 -#define MDDI_HOST_TA2_LEN 0x000c -#define MDDI_HOST_REV_RATE_DIV 0x0002 - - -struct __attribute__((packed)) mddi_rev_packet { - uint16_t length; - uint16_t type; - uint16_t client_id; -}; - -struct __attribute__((packed)) mddi_client_status { - uint16_t length; - uint16_t type; - uint16_t client_id; - uint16_t reverse_link_request; /* bytes needed in rev encap message */ - uint8_t crc_error_count; - uint8_t capability_change; - uint16_t graphics_busy_flags; - uint16_t crc16; -}; - -struct __attribute__((packed)) mddi_client_caps { - uint16_t length; /* length, exclusive of this field */ - uint16_t type; /* 66 */ - uint16_t client_id; - - uint16_t Protocol_Version; - uint16_t Minimum_Protocol_Version; - uint16_t Data_Rate_Capability; - uint8_t Interface_Type_Capability; - uint8_t Number_of_Alt_Displays; - uint16_t PostCal_Data_Rate; - uint16_t Bitmap_Width; - uint16_t Bitmap_Height; - uint16_t Display_Window_Width; - uint16_t Display_Window_Height; - uint32_t Color_Map_Size; - uint16_t Color_Map_RGB_Width; - uint16_t RGB_Capability; - uint8_t Monochrome_Capability; - uint8_t Reserved_1; - uint16_t Y_Cb_Cr_Capability; - uint16_t Bayer_Capability; - uint16_t Alpha_Cursor_Image_Planes; - uint32_t Client_Feature_Capability_Indicators; - uint8_t Maximum_Video_Frame_Rate_Capability; - uint8_t Minimum_Video_Frame_Rate_Capability; - uint16_t Minimum_Sub_frame_Rate; - uint16_t Audio_Buffer_Depth; - uint16_t Audio_Channel_Capability; - uint16_t Audio_Sample_Rate_Capability; - uint8_t Audio_Sample_Resolution; - uint8_t Mic_Audio_Sample_Resolution; - uint16_t Mic_Sample_Rate_Capability; - uint8_t Keyboard_Data_Format; - uint8_t pointing_device_data_format; - uint16_t content_protection_type; - uint16_t Mfr_Name; - uint16_t Product_Code; - uint16_t Reserved_3; - uint32_t Serial_Number; - uint8_t Week_of_Manufacture; - uint8_t Year_of_Manufacture; - - uint16_t crc16; -} mddi_client_capability_type; - - -struct __attribute__((packed)) mddi_video_stream { - uint16_t length; - uint16_t type; /* 16 */ - uint16_t client_id; /* 0 */ - - uint16_t video_data_format_descriptor; -/* format of each pixel in the Pixel Data in the present stream in the - * present packet. - * If bits [15:13] = 000 monochrome - * If bits [15:13] = 001 color pixels (palette). - * If bits [15:13] = 010 color pixels in raw RGB - * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format - * If bits [15:13] = 100 Bayer pixels - */ - - uint16_t pixel_data_attributes; -/* interpreted as follows: - * Bits [1:0] = 11 pixel data is displayed to both eyes - * Bits [1:0] = 10 pixel data is routed to the left eye only. - * Bits [1:0] = 01 pixel data is routed to the right eye only. - * Bits [1:0] = 00 pixel data is routed to the alternate display. - * Bit 2 is 0 Pixel Data is in the standard progressive format. - * Bit 2 is 1 Pixel Data is in interlace format. - * Bit 3 is 0 Pixel Data is in the standard progressive format. - * Bit 3 is 1 Pixel Data is in alternate pixel format. - * Bit 4 is 0 Pixel Data is to or from the display frame buffer. - * Bit 4 is 1 Pixel Data is to or from the camera. - * Bit 5 is 0 pixel data contains the next consecutive row of pixels. - * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge, - * X Start, and Y Start parameters are not defined and - * shall be ignored by the client. - * Bits [7:6] = 01 Pixel data is written to the offline image buffer. - * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display. - * Bits [7:6] = 11 Pixel data is written to all image buffers. - * Bits [7:6] = 10 Invalid. Reserved for future use. - * Bits 8 through 11 alternate display number. - * Bits 12 through 14 are reserved for future use and shall be set to zero. - * Bit 15 is 1 the row of pixels is the last row of pixels in a frame. - */ - - uint16_t x_left_edge; - uint16_t y_top_edge; - /* X,Y coordinate of the top left edge of the screen window */ - - uint16_t x_right_edge; - uint16_t y_bottom_edge; - /* X,Y coordinate of the bottom right edge of the window being - * updated. */ - - uint16_t x_start; - uint16_t y_start; - /* (X Start, Y Start) is the first pixel in the Pixel Data field - * below. */ - - uint16_t pixel_count; - /* number of pixels in the Pixel Data field below. */ - - uint16_t parameter_CRC; - /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */ - - uint16_t reserved; - /* 16-bit variable to make structure align on 4 byte boundary */ -}; - -#define TYPE_VIDEO_STREAM 16 -#define TYPE_CLIENT_CAPS 66 -#define TYPE_REGISTER_ACCESS 146 -#define TYPE_CLIENT_STATUS 70 - -struct __attribute__((packed)) mddi_register_access { - uint16_t length; - uint16_t type; /* 146 */ - uint16_t client_id; - - uint16_t read_write_info; - /* Bits 13:0 a 14-bit unsigned integer that specifies the number of - * 32-bit Register Data List items to be transferred in the - * Register Data List field. - * Bits[15:14] = 00 Write to register(s); - * Bits[15:14] = 10 Read from register(s); - * Bits[15:14] = 11 Response to a Read. - * Bits[15:14] = 01 this value is reserved for future use. */ -#define MDDI_WRITE (0 << 14) -#define MDDI_READ (2 << 14) -#define MDDI_READ_RESP (3 << 14) - - uint32_t register_address; - /* the register address that is to be written to or read from. */ - - uint16_t crc16; - - uint32_t register_data_list; - /* list of 4-byte register data values for/from client registers */ -}; - -struct __attribute__((packed)) mddi_llentry { - uint16_t flags; - uint16_t header_count; - uint16_t data_count; - dma_addr_t data; /* 32 bit */ - struct mddi_llentry *next; - uint16_t reserved; - union { - struct mddi_video_stream v; - struct mddi_register_access r; - uint32_t _[12]; - } u; -}; - -#endif diff --git a/drivers/video/fbdev/msm/mdp.c b/drivers/video/fbdev/msm/mdp.c deleted file mode 100644 index 113c7876c855..000000000000 --- a/drivers/video/fbdev/msm/mdp.c +++ /dev/null @@ -1,520 +0,0 @@ -/* drivers/video/msm_fb/mdp.c - * - * MSM MDP Interface (used by framebuffer core) - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "mdp_hw.h" - -struct class *mdp_class; - -#define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) - -static uint16_t mdp_default_ccs[] = { - 0x254, 0x000, 0x331, 0x254, 0xF38, 0xE61, 0x254, 0x409, 0x000, - 0x010, 0x080, 0x080 -}; - -static DECLARE_WAIT_QUEUE_HEAD(mdp_dma2_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); -static struct msmfb_callback *dma_callback; -static struct clk *clk; -static unsigned int mdp_irq_mask; -static DEFINE_SPINLOCK(mdp_lock); -DEFINE_MUTEX(mdp_mutex); - -static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) -{ - unsigned long irq_flags; - int ret = 0; - - BUG_ON(!mask); - - spin_lock_irqsave(&mdp_lock, irq_flags); - /* if the mask bits are already set return an error, this interrupt - * is already enabled */ - if (mdp_irq_mask & mask) { - printk(KERN_ERR "mdp irq already on already on %x %x\n", - mdp_irq_mask, mask); - ret = -1; - } - /* if the mdp irq is not already enabled enable it */ - if (!mdp_irq_mask) { - if (clk) - clk_enable(clk); - enable_irq(mdp->irq); - } - - /* update the irq mask to reflect the fact that the interrupt is - * enabled */ - mdp_irq_mask |= mask; - spin_unlock_irqrestore(&mdp_lock, irq_flags); - return ret; -} - -static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) -{ - /* this interrupt is already disabled! */ - if (!(mdp_irq_mask & mask)) { - printk(KERN_ERR "mdp irq already off %x %x\n", - mdp_irq_mask, mask); - return -1; - } - /* update the irq mask to reflect the fact that the interrupt is - * disabled */ - mdp_irq_mask &= ~(mask); - /* if no one is waiting on the interrupt, disable it */ - if (!mdp_irq_mask) { - disable_irq_nosync(mdp->irq); - if (clk) - clk_disable(clk); - } - return 0; -} - -static int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) -{ - unsigned long irq_flags; - int ret; - - spin_lock_irqsave(&mdp_lock, irq_flags); - ret = locked_disable_mdp_irq(mdp, mask); - spin_unlock_irqrestore(&mdp_lock, irq_flags); - return ret; -} - -static irqreturn_t mdp_isr(int irq, void *data) -{ - uint32_t status; - unsigned long irq_flags; - struct mdp_info *mdp = data; - - spin_lock_irqsave(&mdp_lock, irq_flags); - - status = mdp_readl(mdp, MDP_INTR_STATUS); - mdp_writel(mdp, status, MDP_INTR_CLEAR); - - status &= mdp_irq_mask; - if (status & DL0_DMA2_TERM_DONE) { - if (dma_callback) { - dma_callback->func(dma_callback); - dma_callback = NULL; - } - wake_up(&mdp_dma2_waitqueue); - } - - if (status & DL0_ROI_DONE) - wake_up(&mdp_ppp_waitqueue); - - if (status) - locked_disable_mdp_irq(mdp, status); - - spin_unlock_irqrestore(&mdp_lock, irq_flags); - return IRQ_HANDLED; -} - -static uint32_t mdp_check_mask(uint32_t mask) -{ - uint32_t ret; - unsigned long irq_flags; - - spin_lock_irqsave(&mdp_lock, irq_flags); - ret = mdp_irq_mask & mask; - spin_unlock_irqrestore(&mdp_lock, irq_flags); - return ret; -} - -static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) -{ - int ret = 0; - unsigned long irq_flags; - - wait_event_timeout(*wq, !mdp_check_mask(mask), HZ); - - spin_lock_irqsave(&mdp_lock, irq_flags); - if (mdp_irq_mask & mask) { - locked_disable_mdp_irq(mdp, mask); - printk(KERN_WARNING "timeout waiting for mdp to complete %x\n", - mask); - ret = -ETIMEDOUT; - } - spin_unlock_irqrestore(&mdp_lock, irq_flags); - - return ret; -} - -void mdp_dma_wait(struct mdp_device *mdp_dev) -{ -#define MDP_MAX_TIMEOUTS 20 - static int timeout_count; - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - - if (mdp_wait(mdp, DL0_DMA2_TERM_DONE, &mdp_dma2_waitqueue) == -ETIMEDOUT) - timeout_count++; - else - timeout_count = 0; - - if (timeout_count > MDP_MAX_TIMEOUTS) { - printk(KERN_ERR "mdp: dma failed %d times, somethings wrong!\n", - MDP_MAX_TIMEOUTS); - BUG(); - } -} - -static int mdp_ppp_wait(struct mdp_info *mdp) -{ - return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue); -} - -void mdp_dma_to_mddi(struct mdp_info *mdp, uint32_t addr, uint32_t stride, - uint32_t width, uint32_t height, uint32_t x, uint32_t y, - struct msmfb_callback *callback) -{ - uint32_t dma2_cfg; - uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ - - if (enable_mdp_irq(mdp, DL0_DMA2_TERM_DONE)) { - printk(KERN_ERR "mdp_dma_to_mddi: busy\n"); - return; - } - - dma_callback = callback; - - dma2_cfg = DMA_PACK_TIGHT | - DMA_PACK_ALIGN_LSB | - DMA_PACK_PATTERN_RGB | - DMA_OUT_SEL_AHB | - DMA_IBUF_NONCONTIGUOUS; - - dma2_cfg |= DMA_IBUF_FORMAT_RGB565; - - dma2_cfg |= DMA_OUT_SEL_MDDI; - - dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; - - dma2_cfg |= DMA_DITHER_EN; - - /* setup size, address, and stride */ - mdp_writel(mdp, (height << 16) | (width), - MDP_CMD_DEBUG_ACCESS_BASE + 0x0184); - mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188); - mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C); - - /* 666 18BPP */ - dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; - - /* set y & x offset and MDDI transaction parameters */ - mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194); - mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0); - mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM, - MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4); - - mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180); - - /* start DMA2 */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044); -} - -void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride, - uint32_t width, uint32_t height, uint32_t x, uint32_t y, - struct msmfb_callback *callback, int interface) -{ - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - - if (interface == MSM_MDDI_PMDH_INTERFACE) { - mdp_dma_to_mddi(mdp, addr, stride, width, height, x, y, - callback); - } -} - -int get_img(struct mdp_img *img, struct fb_info *info, - unsigned long *start, unsigned long *len, - struct file **filep) -{ - int ret = 0; - struct fd f = fdget(img->memory_id); - if (f.file == NULL) - return -1; - - if (MAJOR(file_inode(f.file)->i_rdev) == FB_MAJOR) { - *start = info->fix.smem_start; - *len = info->fix.smem_len; - } else - ret = -1; - fdput(f); - - return ret; -} - -void put_img(struct file *src_file, struct file *dst_file) -{ -} - -int mdp_blit(struct mdp_device *mdp_dev, struct fb_info *fb, - struct mdp_blit_req *req) -{ - int ret; - unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0; - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - struct file *src_file = 0, *dst_file = 0; - - /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ - if (unlikely(req->src_rect.h == 0 || - req->src_rect.w == 0)) { - printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); - return -EINVAL; - } - if (unlikely(req->dst_rect.h == 0 || - req->dst_rect.w == 0)) - return -EINVAL; - - /* do this first so that if this fails, the caller can always - * safely call put_img */ - if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) { - printk(KERN_ERR "mpd_ppp: could not retrieve src image from " - "memory\n"); - return -EINVAL; - } - - if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) { - printk(KERN_ERR "mpd_ppp: could not retrieve dst image from " - "memory\n"); - return -EINVAL; - } - mutex_lock(&mdp_mutex); - - /* transp_masking unimplemented */ - req->transp_mask = MDP_TRANSP_NOP; - if (unlikely((req->transp_mask != MDP_TRANSP_NOP || - req->alpha != MDP_ALPHA_NOP || - HAS_ALPHA(req->src.format)) && - (req->flags & MDP_ROT_90 && - req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) { - int i; - unsigned int tiles = req->dst_rect.h / 16; - unsigned int remainder = req->dst_rect.h % 16; - req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h; - req->dst_rect.h = 16; - for (i = 0; i < tiles; i++) { - enable_mdp_irq(mdp, DL0_ROI_DONE); - ret = mdp_ppp_blit(mdp, req, src_file, src_start, - src_len, dst_file, dst_start, - dst_len); - if (ret) - goto err_bad_blit; - ret = mdp_ppp_wait(mdp); - if (ret) - goto err_wait_failed; - req->dst_rect.y += 16; - req->src_rect.x += req->src_rect.w; - } - if (!remainder) - goto end; - req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h; - req->dst_rect.h = remainder; - } - enable_mdp_irq(mdp, DL0_ROI_DONE); - ret = mdp_ppp_blit(mdp, req, src_file, src_start, src_len, dst_file, - dst_start, - dst_len); - if (ret) - goto err_bad_blit; - ret = mdp_ppp_wait(mdp); - if (ret) - goto err_wait_failed; -end: - put_img(src_file, dst_file); - mutex_unlock(&mdp_mutex); - return 0; -err_bad_blit: - disable_mdp_irq(mdp, DL0_ROI_DONE); -err_wait_failed: - put_img(src_file, dst_file); - mutex_unlock(&mdp_mutex); - return ret; -} - -void mdp_set_grp_disp(struct mdp_device *mdp_dev, unsigned disp_id) -{ - struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); - - disp_id &= 0xf; - mdp_writel(mdp, disp_id, MDP_FULL_BYPASS_WORD43); -} - -int register_mdp_client(struct class_interface *cint) -{ - if (!mdp_class) { - pr_err("mdp: no mdp_class when registering mdp client\n"); - return -ENODEV; - } - cint->class = mdp_class; - return class_interface_register(cint); -} - -#include "mdp_csc_table.h" -#include "mdp_scale_tables.h" - -int mdp_probe(struct platform_device *pdev) -{ - struct resource *resource; - int ret; - int n; - struct mdp_info *mdp; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - pr_err("mdp: can not get mdp mem resource!\n"); - return -ENOMEM; - } - - mdp = kzalloc(sizeof(struct mdp_info), GFP_KERNEL); - if (!mdp) - return -ENOMEM; - - mdp->irq = platform_get_irq(pdev, 0); - if (mdp->irq < 0) { - pr_err("mdp: can not get mdp irq\n"); - ret = mdp->irq; - goto error_get_irq; - } - - mdp->base = ioremap(resource->start, resource_size(resource)); - if (mdp->base == 0) { - printk(KERN_ERR "msmfb: cannot allocate mdp regs!\n"); - ret = -ENOMEM; - goto error_ioremap; - } - - mdp->mdp_dev.dma = mdp_dma; - mdp->mdp_dev.dma_wait = mdp_dma_wait; - mdp->mdp_dev.blit = mdp_blit; - mdp->mdp_dev.set_grp_disp = mdp_set_grp_disp; - - clk = clk_get(&pdev->dev, "mdp_clk"); - if (IS_ERR(clk)) { - printk(KERN_INFO "mdp: failed to get mdp clk"); - ret = PTR_ERR(clk); - goto error_get_clk; - } - - ret = request_irq(mdp->irq, mdp_isr, 0, "msm_mdp", mdp); - if (ret) - goto error_request_irq; - disable_irq(mdp->irq); - mdp_irq_mask = 0; - - /* debug interface write access */ - mdp_writel(mdp, 1, 0x60); - - mdp_writel(mdp, MDP_ANY_INTR_MASK, MDP_INTR_ENABLE); - mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); - - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); - - for (n = 0; n < ARRAY_SIZE(csc_table); n++) - mdp_writel(mdp, csc_table[n].val, csc_table[n].reg); - - /* clear up unused fg/main registers */ - /* comp.plane 2&3 ystride */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); - - /* unpacked pattern */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); - - /* comp.plane 2 & 3 */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); - - /* clear unused bg registers */ - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); - mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); - - for (n = 0; n < ARRAY_SIZE(mdp_upscale_table); n++) - mdp_writel(mdp, mdp_upscale_table[n].val, - mdp_upscale_table[n].reg); - - for (n = 0; n < 9; n++) - mdp_writel(mdp, mdp_default_ccs[n], 0x40440 + 4 * n); - mdp_writel(mdp, mdp_default_ccs[9], 0x40500 + 4 * 0); - mdp_writel(mdp, mdp_default_ccs[10], 0x40500 + 4 * 0); - mdp_writel(mdp, mdp_default_ccs[11], 0x40500 + 4 * 0); - - /* register mdp device */ - mdp->mdp_dev.dev.parent = &pdev->dev; - mdp->mdp_dev.dev.class = mdp_class; - dev_set_name(&mdp->mdp_dev.dev, "mdp%d", pdev->id); - - /* if you can remove the platform device you'd have to implement - * this: - mdp_dev.release = mdp_class; */ - - ret = device_register(&mdp->mdp_dev.dev); - if (ret) - goto error_device_register; - return 0; - -error_device_register: - free_irq(mdp->irq, mdp); -error_request_irq: -error_get_clk: - iounmap(mdp->base); -error_get_irq: -error_ioremap: - kfree(mdp); - return ret; -} - -static struct platform_driver msm_mdp_driver = { - .probe = mdp_probe, - .driver = {.name = "msm_mdp"}, -}; - -static int __init mdp_init(void) -{ - mdp_class = class_create(THIS_MODULE, "msm_mdp"); - if (IS_ERR(mdp_class)) { - printk(KERN_ERR "Error creating mdp class\n"); - return PTR_ERR(mdp_class); - } - return platform_driver_register(&msm_mdp_driver); -} - -subsys_initcall(mdp_init); diff --git a/drivers/video/fbdev/msm/mdp_csc_table.h b/drivers/video/fbdev/msm/mdp_csc_table.h deleted file mode 100644 index d1cde30ead52..000000000000 --- a/drivers/video/fbdev/msm/mdp_csc_table.h +++ /dev/null @@ -1,582 +0,0 @@ -/* drivers/video/msm_fb/mdp_csc_table.h - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -static struct { - uint32_t reg; - uint32_t val; -} csc_table[] = { - { 0x40400, 0x83 }, - { 0x40404, 0x102 }, - { 0x40408, 0x32 }, - { 0x4040c, 0xffffffb5 }, - { 0x40410, 0xffffff6c }, - { 0x40414, 0xe1 }, - { 0x40418, 0xe1 }, - { 0x4041c, 0xffffff45 }, - { 0x40420, 0xffffffdc }, - { 0x40440, 0x254 }, - { 0x40444, 0x0 }, - { 0x40448, 0x331 }, - { 0x4044c, 0x254 }, - { 0x40450, 0xffffff38 }, - { 0x40454, 0xfffffe61 }, - { 0x40458, 0x254 }, - { 0x4045c, 0x409 }, - { 0x40460, 0x0 }, - { 0x40480, 0x5d }, - { 0x40484, 0x13a }, - { 0x40488, 0x20 }, - { 0x4048c, 0xffffffcd }, - { 0x40490, 0xffffff54 }, - { 0x40494, 0xe1 }, - { 0x40498, 0xe1 }, - { 0x4049c, 0xffffff35 }, - { 0x404a0, 0xffffffec }, - { 0x404c0, 0x254 }, - { 0x404c4, 0x0 }, - { 0x404c8, 0x396 }, - { 0x404cc, 0x254 }, - { 0x404d0, 0xffffff94 }, - { 0x404d4, 0xfffffef0 }, - { 0x404d8, 0x254 }, - { 0x404dc, 0x43a }, - { 0x404e0, 0x0 }, - { 0x40500, 0x10 }, - { 0x40504, 0x80 }, - { 0x40508, 0x80 }, - { 0x40540, 0x10 }, - { 0x40544, 0x80 }, - { 0x40548, 0x80 }, - { 0x40580, 0x10 }, - { 0x40584, 0xeb }, - { 0x40588, 0x10 }, - { 0x4058c, 0xf0 }, - { 0x405c0, 0x10 }, - { 0x405c4, 0xeb }, - { 0x405c8, 0x10 }, - { 0x405cc, 0xf0 }, - { 0x40800, 0x0 }, - { 0x40804, 0x151515 }, - { 0x40808, 0x1d1d1d }, - { 0x4080c, 0x232323 }, - { 0x40810, 0x272727 }, - { 0x40814, 0x2b2b2b }, - { 0x40818, 0x2f2f2f }, - { 0x4081c, 0x333333 }, - { 0x40820, 0x363636 }, - { 0x40824, 0x393939 }, - { 0x40828, 0x3b3b3b }, - { 0x4082c, 0x3e3e3e }, - { 0x40830, 0x404040 }, - { 0x40834, 0x434343 }, - { 0x40838, 0x454545 }, - { 0x4083c, 0x474747 }, - { 0x40840, 0x494949 }, - { 0x40844, 0x4b4b4b }, - { 0x40848, 0x4d4d4d }, - { 0x4084c, 0x4f4f4f }, - { 0x40850, 0x515151 }, - { 0x40854, 0x535353 }, - { 0x40858, 0x555555 }, - { 0x4085c, 0x565656 }, - { 0x40860, 0x585858 }, - { 0x40864, 0x5a5a5a }, - { 0x40868, 0x5b5b5b }, - { 0x4086c, 0x5d5d5d }, - { 0x40870, 0x5e5e5e }, - { 0x40874, 0x606060 }, - { 0x40878, 0x616161 }, - { 0x4087c, 0x636363 }, - { 0x40880, 0x646464 }, - { 0x40884, 0x666666 }, - { 0x40888, 0x676767 }, - { 0x4088c, 0x686868 }, - { 0x40890, 0x6a6a6a }, - { 0x40894, 0x6b6b6b }, - { 0x40898, 0x6c6c6c }, - { 0x4089c, 0x6e6e6e }, - { 0x408a0, 0x6f6f6f }, - { 0x408a4, 0x707070 }, - { 0x408a8, 0x717171 }, - { 0x408ac, 0x727272 }, - { 0x408b0, 0x747474 }, - { 0x408b4, 0x757575 }, - { 0x408b8, 0x767676 }, - { 0x408bc, 0x777777 }, - { 0x408c0, 0x787878 }, - { 0x408c4, 0x797979 }, - { 0x408c8, 0x7a7a7a }, - { 0x408cc, 0x7c7c7c }, - { 0x408d0, 0x7d7d7d }, - { 0x408d4, 0x7e7e7e }, - { 0x408d8, 0x7f7f7f }, - { 0x408dc, 0x808080 }, - { 0x408e0, 0x818181 }, - { 0x408e4, 0x828282 }, - { 0x408e8, 0x838383 }, - { 0x408ec, 0x848484 }, - { 0x408f0, 0x858585 }, - { 0x408f4, 0x868686 }, - { 0x408f8, 0x878787 }, - { 0x408fc, 0x888888 }, - { 0x40900, 0x898989 }, - { 0x40904, 0x8a8a8a }, - { 0x40908, 0x8b8b8b }, - { 0x4090c, 0x8c8c8c }, - { 0x40910, 0x8d8d8d }, - { 0x40914, 0x8e8e8e }, - { 0x40918, 0x8f8f8f }, - { 0x4091c, 0x8f8f8f }, - { 0x40920, 0x909090 }, - { 0x40924, 0x919191 }, - { 0x40928, 0x929292 }, - { 0x4092c, 0x939393 }, - { 0x40930, 0x949494 }, - { 0x40934, 0x959595 }, - { 0x40938, 0x969696 }, - { 0x4093c, 0x969696 }, - { 0x40940, 0x979797 }, - { 0x40944, 0x989898 }, - { 0x40948, 0x999999 }, - { 0x4094c, 0x9a9a9a }, - { 0x40950, 0x9b9b9b }, - { 0x40954, 0x9c9c9c }, - { 0x40958, 0x9c9c9c }, - { 0x4095c, 0x9d9d9d }, - { 0x40960, 0x9e9e9e }, - { 0x40964, 0x9f9f9f }, - { 0x40968, 0xa0a0a0 }, - { 0x4096c, 0xa0a0a0 }, - { 0x40970, 0xa1a1a1 }, - { 0x40974, 0xa2a2a2 }, - { 0x40978, 0xa3a3a3 }, - { 0x4097c, 0xa4a4a4 }, - { 0x40980, 0xa4a4a4 }, - { 0x40984, 0xa5a5a5 }, - { 0x40988, 0xa6a6a6 }, - { 0x4098c, 0xa7a7a7 }, - { 0x40990, 0xa7a7a7 }, - { 0x40994, 0xa8a8a8 }, - { 0x40998, 0xa9a9a9 }, - { 0x4099c, 0xaaaaaa }, - { 0x409a0, 0xaaaaaa }, - { 0x409a4, 0xababab }, - { 0x409a8, 0xacacac }, - { 0x409ac, 0xadadad }, - { 0x409b0, 0xadadad }, - { 0x409b4, 0xaeaeae }, - { 0x409b8, 0xafafaf }, - { 0x409bc, 0xafafaf }, - { 0x409c0, 0xb0b0b0 }, - { 0x409c4, 0xb1b1b1 }, - { 0x409c8, 0xb2b2b2 }, - { 0x409cc, 0xb2b2b2 }, - { 0x409d0, 0xb3b3b3 }, - { 0x409d4, 0xb4b4b4 }, - { 0x409d8, 0xb4b4b4 }, - { 0x409dc, 0xb5b5b5 }, - { 0x409e0, 0xb6b6b6 }, - { 0x409e4, 0xb6b6b6 }, - { 0x409e8, 0xb7b7b7 }, - { 0x409ec, 0xb8b8b8 }, - { 0x409f0, 0xb8b8b8 }, - { 0x409f4, 0xb9b9b9 }, - { 0x409f8, 0xbababa }, - { 0x409fc, 0xbababa }, - { 0x40a00, 0xbbbbbb }, - { 0x40a04, 0xbcbcbc }, - { 0x40a08, 0xbcbcbc }, - { 0x40a0c, 0xbdbdbd }, - { 0x40a10, 0xbebebe }, - { 0x40a14, 0xbebebe }, - { 0x40a18, 0xbfbfbf }, - { 0x40a1c, 0xc0c0c0 }, - { 0x40a20, 0xc0c0c0 }, - { 0x40a24, 0xc1c1c1 }, - { 0x40a28, 0xc1c1c1 }, - { 0x40a2c, 0xc2c2c2 }, - { 0x40a30, 0xc3c3c3 }, - { 0x40a34, 0xc3c3c3 }, - { 0x40a38, 0xc4c4c4 }, - { 0x40a3c, 0xc5c5c5 }, - { 0x40a40, 0xc5c5c5 }, - { 0x40a44, 0xc6c6c6 }, - { 0x40a48, 0xc6c6c6 }, - { 0x40a4c, 0xc7c7c7 }, - { 0x40a50, 0xc8c8c8 }, - { 0x40a54, 0xc8c8c8 }, - { 0x40a58, 0xc9c9c9 }, - { 0x40a5c, 0xc9c9c9 }, - { 0x40a60, 0xcacaca }, - { 0x40a64, 0xcbcbcb }, - { 0x40a68, 0xcbcbcb }, - { 0x40a6c, 0xcccccc }, - { 0x40a70, 0xcccccc }, - { 0x40a74, 0xcdcdcd }, - { 0x40a78, 0xcecece }, - { 0x40a7c, 0xcecece }, - { 0x40a80, 0xcfcfcf }, - { 0x40a84, 0xcfcfcf }, - { 0x40a88, 0xd0d0d0 }, - { 0x40a8c, 0xd0d0d0 }, - { 0x40a90, 0xd1d1d1 }, - { 0x40a94, 0xd2d2d2 }, - { 0x40a98, 0xd2d2d2 }, - { 0x40a9c, 0xd3d3d3 }, - { 0x40aa0, 0xd3d3d3 }, - { 0x40aa4, 0xd4d4d4 }, - { 0x40aa8, 0xd4d4d4 }, - { 0x40aac, 0xd5d5d5 }, - { 0x40ab0, 0xd6d6d6 }, - { 0x40ab4, 0xd6d6d6 }, - { 0x40ab8, 0xd7d7d7 }, - { 0x40abc, 0xd7d7d7 }, - { 0x40ac0, 0xd8d8d8 }, - { 0x40ac4, 0xd8d8d8 }, - { 0x40ac8, 0xd9d9d9 }, - { 0x40acc, 0xd9d9d9 }, - { 0x40ad0, 0xdadada }, - { 0x40ad4, 0xdbdbdb }, - { 0x40ad8, 0xdbdbdb }, - { 0x40adc, 0xdcdcdc }, - { 0x40ae0, 0xdcdcdc }, - { 0x40ae4, 0xdddddd }, - { 0x40ae8, 0xdddddd }, - { 0x40aec, 0xdedede }, - { 0x40af0, 0xdedede }, - { 0x40af4, 0xdfdfdf }, - { 0x40af8, 0xdfdfdf }, - { 0x40afc, 0xe0e0e0 }, - { 0x40b00, 0xe0e0e0 }, - { 0x40b04, 0xe1e1e1 }, - { 0x40b08, 0xe1e1e1 }, - { 0x40b0c, 0xe2e2e2 }, - { 0x40b10, 0xe3e3e3 }, - { 0x40b14, 0xe3e3e3 }, - { 0x40b18, 0xe4e4e4 }, - { 0x40b1c, 0xe4e4e4 }, - { 0x40b20, 0xe5e5e5 }, - { 0x40b24, 0xe5e5e5 }, - { 0x40b28, 0xe6e6e6 }, - { 0x40b2c, 0xe6e6e6 }, - { 0x40b30, 0xe7e7e7 }, - { 0x40b34, 0xe7e7e7 }, - { 0x40b38, 0xe8e8e8 }, - { 0x40b3c, 0xe8e8e8 }, - { 0x40b40, 0xe9e9e9 }, - { 0x40b44, 0xe9e9e9 }, - { 0x40b48, 0xeaeaea }, - { 0x40b4c, 0xeaeaea }, - { 0x40b50, 0xebebeb }, - { 0x40b54, 0xebebeb }, - { 0x40b58, 0xececec }, - { 0x40b5c, 0xececec }, - { 0x40b60, 0xededed }, - { 0x40b64, 0xededed }, - { 0x40b68, 0xeeeeee }, - { 0x40b6c, 0xeeeeee }, - { 0x40b70, 0xefefef }, - { 0x40b74, 0xefefef }, - { 0x40b78, 0xf0f0f0 }, - { 0x40b7c, 0xf0f0f0 }, - { 0x40b80, 0xf1f1f1 }, - { 0x40b84, 0xf1f1f1 }, - { 0x40b88, 0xf2f2f2 }, - { 0x40b8c, 0xf2f2f2 }, - { 0x40b90, 0xf2f2f2 }, - { 0x40b94, 0xf3f3f3 }, - { 0x40b98, 0xf3f3f3 }, - { 0x40b9c, 0xf4f4f4 }, - { 0x40ba0, 0xf4f4f4 }, - { 0x40ba4, 0xf5f5f5 }, - { 0x40ba8, 0xf5f5f5 }, - { 0x40bac, 0xf6f6f6 }, - { 0x40bb0, 0xf6f6f6 }, - { 0x40bb4, 0xf7f7f7 }, - { 0x40bb8, 0xf7f7f7 }, - { 0x40bbc, 0xf8f8f8 }, - { 0x40bc0, 0xf8f8f8 }, - { 0x40bc4, 0xf9f9f9 }, - { 0x40bc8, 0xf9f9f9 }, - { 0x40bcc, 0xfafafa }, - { 0x40bd0, 0xfafafa }, - { 0x40bd4, 0xfafafa }, - { 0x40bd8, 0xfbfbfb }, - { 0x40bdc, 0xfbfbfb }, - { 0x40be0, 0xfcfcfc }, - { 0x40be4, 0xfcfcfc }, - { 0x40be8, 0xfdfdfd }, - { 0x40bec, 0xfdfdfd }, - { 0x40bf0, 0xfefefe }, - { 0x40bf4, 0xfefefe }, - { 0x40bf8, 0xffffff }, - { 0x40bfc, 0xffffff }, - { 0x40c00, 0x0 }, - { 0x40c04, 0x0 }, - { 0x40c08, 0x0 }, - { 0x40c0c, 0x0 }, - { 0x40c10, 0x0 }, - { 0x40c14, 0x0 }, - { 0x40c18, 0x0 }, - { 0x40c1c, 0x0 }, - { 0x40c20, 0x0 }, - { 0x40c24, 0x0 }, - { 0x40c28, 0x0 }, - { 0x40c2c, 0x0 }, - { 0x40c30, 0x0 }, - { 0x40c34, 0x0 }, - { 0x40c38, 0x0 }, - { 0x40c3c, 0x0 }, - { 0x40c40, 0x10101 }, - { 0x40c44, 0x10101 }, - { 0x40c48, 0x10101 }, - { 0x40c4c, 0x10101 }, - { 0x40c50, 0x10101 }, - { 0x40c54, 0x10101 }, - { 0x40c58, 0x10101 }, - { 0x40c5c, 0x10101 }, - { 0x40c60, 0x10101 }, - { 0x40c64, 0x10101 }, - { 0x40c68, 0x20202 }, - { 0x40c6c, 0x20202 }, - { 0x40c70, 0x20202 }, - { 0x40c74, 0x20202 }, - { 0x40c78, 0x20202 }, - { 0x40c7c, 0x20202 }, - { 0x40c80, 0x30303 }, - { 0x40c84, 0x30303 }, - { 0x40c88, 0x30303 }, - { 0x40c8c, 0x30303 }, - { 0x40c90, 0x30303 }, - { 0x40c94, 0x40404 }, - { 0x40c98, 0x40404 }, - { 0x40c9c, 0x40404 }, - { 0x40ca0, 0x40404 }, - { 0x40ca4, 0x40404 }, - { 0x40ca8, 0x50505 }, - { 0x40cac, 0x50505 }, - { 0x40cb0, 0x50505 }, - { 0x40cb4, 0x50505 }, - { 0x40cb8, 0x60606 }, - { 0x40cbc, 0x60606 }, - { 0x40cc0, 0x60606 }, - { 0x40cc4, 0x70707 }, - { 0x40cc8, 0x70707 }, - { 0x40ccc, 0x70707 }, - { 0x40cd0, 0x70707 }, - { 0x40cd4, 0x80808 }, - { 0x40cd8, 0x80808 }, - { 0x40cdc, 0x80808 }, - { 0x40ce0, 0x90909 }, - { 0x40ce4, 0x90909 }, - { 0x40ce8, 0xa0a0a }, - { 0x40cec, 0xa0a0a }, - { 0x40cf0, 0xa0a0a }, - { 0x40cf4, 0xb0b0b }, - { 0x40cf8, 0xb0b0b }, - { 0x40cfc, 0xb0b0b }, - { 0x40d00, 0xc0c0c }, - { 0x40d04, 0xc0c0c }, - { 0x40d08, 0xd0d0d }, - { 0x40d0c, 0xd0d0d }, - { 0x40d10, 0xe0e0e }, - { 0x40d14, 0xe0e0e }, - { 0x40d18, 0xe0e0e }, - { 0x40d1c, 0xf0f0f }, - { 0x40d20, 0xf0f0f }, - { 0x40d24, 0x101010 }, - { 0x40d28, 0x101010 }, - { 0x40d2c, 0x111111 }, - { 0x40d30, 0x111111 }, - { 0x40d34, 0x121212 }, - { 0x40d38, 0x121212 }, - { 0x40d3c, 0x131313 }, - { 0x40d40, 0x131313 }, - { 0x40d44, 0x141414 }, - { 0x40d48, 0x151515 }, - { 0x40d4c, 0x151515 }, - { 0x40d50, 0x161616 }, - { 0x40d54, 0x161616 }, - { 0x40d58, 0x171717 }, - { 0x40d5c, 0x171717 }, - { 0x40d60, 0x181818 }, - { 0x40d64, 0x191919 }, - { 0x40d68, 0x191919 }, - { 0x40d6c, 0x1a1a1a }, - { 0x40d70, 0x1b1b1b }, - { 0x40d74, 0x1b1b1b }, - { 0x40d78, 0x1c1c1c }, - { 0x40d7c, 0x1c1c1c }, - { 0x40d80, 0x1d1d1d }, - { 0x40d84, 0x1e1e1e }, - { 0x40d88, 0x1f1f1f }, - { 0x40d8c, 0x1f1f1f }, - { 0x40d90, 0x202020 }, - { 0x40d94, 0x212121 }, - { 0x40d98, 0x212121 }, - { 0x40d9c, 0x222222 }, - { 0x40da0, 0x232323 }, - { 0x40da4, 0x242424 }, - { 0x40da8, 0x242424 }, - { 0x40dac, 0x252525 }, - { 0x40db0, 0x262626 }, - { 0x40db4, 0x272727 }, - { 0x40db8, 0x272727 }, - { 0x40dbc, 0x282828 }, - { 0x40dc0, 0x292929 }, - { 0x40dc4, 0x2a2a2a }, - { 0x40dc8, 0x2b2b2b }, - { 0x40dcc, 0x2c2c2c }, - { 0x40dd0, 0x2c2c2c }, - { 0x40dd4, 0x2d2d2d }, - { 0x40dd8, 0x2e2e2e }, - { 0x40ddc, 0x2f2f2f }, - { 0x40de0, 0x303030 }, - { 0x40de4, 0x313131 }, - { 0x40de8, 0x323232 }, - { 0x40dec, 0x333333 }, - { 0x40df0, 0x333333 }, - { 0x40df4, 0x343434 }, - { 0x40df8, 0x353535 }, - { 0x40dfc, 0x363636 }, - { 0x40e00, 0x373737 }, - { 0x40e04, 0x383838 }, - { 0x40e08, 0x393939 }, - { 0x40e0c, 0x3a3a3a }, - { 0x40e10, 0x3b3b3b }, - { 0x40e14, 0x3c3c3c }, - { 0x40e18, 0x3d3d3d }, - { 0x40e1c, 0x3e3e3e }, - { 0x40e20, 0x3f3f3f }, - { 0x40e24, 0x404040 }, - { 0x40e28, 0x414141 }, - { 0x40e2c, 0x424242 }, - { 0x40e30, 0x434343 }, - { 0x40e34, 0x444444 }, - { 0x40e38, 0x464646 }, - { 0x40e3c, 0x474747 }, - { 0x40e40, 0x484848 }, - { 0x40e44, 0x494949 }, - { 0x40e48, 0x4a4a4a }, - { 0x40e4c, 0x4b4b4b }, - { 0x40e50, 0x4c4c4c }, - { 0x40e54, 0x4d4d4d }, - { 0x40e58, 0x4f4f4f }, - { 0x40e5c, 0x505050 }, - { 0x40e60, 0x515151 }, - { 0x40e64, 0x525252 }, - { 0x40e68, 0x535353 }, - { 0x40e6c, 0x545454 }, - { 0x40e70, 0x565656 }, - { 0x40e74, 0x575757 }, - { 0x40e78, 0x585858 }, - { 0x40e7c, 0x595959 }, - { 0x40e80, 0x5b5b5b }, - { 0x40e84, 0x5c5c5c }, - { 0x40e88, 0x5d5d5d }, - { 0x40e8c, 0x5e5e5e }, - { 0x40e90, 0x606060 }, - { 0x40e94, 0x616161 }, - { 0x40e98, 0x626262 }, - { 0x40e9c, 0x646464 }, - { 0x40ea0, 0x656565 }, - { 0x40ea4, 0x666666 }, - { 0x40ea8, 0x686868 }, - { 0x40eac, 0x696969 }, - { 0x40eb0, 0x6a6a6a }, - { 0x40eb4, 0x6c6c6c }, - { 0x40eb8, 0x6d6d6d }, - { 0x40ebc, 0x6f6f6f }, - { 0x40ec0, 0x707070 }, - { 0x40ec4, 0x717171 }, - { 0x40ec8, 0x737373 }, - { 0x40ecc, 0x747474 }, - { 0x40ed0, 0x767676 }, - { 0x40ed4, 0x777777 }, - { 0x40ed8, 0x797979 }, - { 0x40edc, 0x7a7a7a }, - { 0x40ee0, 0x7c7c7c }, - { 0x40ee4, 0x7d7d7d }, - { 0x40ee8, 0x7f7f7f }, - { 0x40eec, 0x808080 }, - { 0x40ef0, 0x828282 }, - { 0x40ef4, 0x838383 }, - { 0x40ef8, 0x858585 }, - { 0x40efc, 0x868686 }, - { 0x40f00, 0x888888 }, - { 0x40f04, 0x898989 }, - { 0x40f08, 0x8b8b8b }, - { 0x40f0c, 0x8d8d8d }, - { 0x40f10, 0x8e8e8e }, - { 0x40f14, 0x909090 }, - { 0x40f18, 0x919191 }, - { 0x40f1c, 0x939393 }, - { 0x40f20, 0x959595 }, - { 0x40f24, 0x969696 }, - { 0x40f28, 0x989898 }, - { 0x40f2c, 0x9a9a9a }, - { 0x40f30, 0x9b9b9b }, - { 0x40f34, 0x9d9d9d }, - { 0x40f38, 0x9f9f9f }, - { 0x40f3c, 0xa1a1a1 }, - { 0x40f40, 0xa2a2a2 }, - { 0x40f44, 0xa4a4a4 }, - { 0x40f48, 0xa6a6a6 }, - { 0x40f4c, 0xa7a7a7 }, - { 0x40f50, 0xa9a9a9 }, - { 0x40f54, 0xababab }, - { 0x40f58, 0xadadad }, - { 0x40f5c, 0xafafaf }, - { 0x40f60, 0xb0b0b0 }, - { 0x40f64, 0xb2b2b2 }, - { 0x40f68, 0xb4b4b4 }, - { 0x40f6c, 0xb6b6b6 }, - { 0x40f70, 0xb8b8b8 }, - { 0x40f74, 0xbababa }, - { 0x40f78, 0xbbbbbb }, - { 0x40f7c, 0xbdbdbd }, - { 0x40f80, 0xbfbfbf }, - { 0x40f84, 0xc1c1c1 }, - { 0x40f88, 0xc3c3c3 }, - { 0x40f8c, 0xc5c5c5 }, - { 0x40f90, 0xc7c7c7 }, - { 0x40f94, 0xc9c9c9 }, - { 0x40f98, 0xcbcbcb }, - { 0x40f9c, 0xcdcdcd }, - { 0x40fa0, 0xcfcfcf }, - { 0x40fa4, 0xd1d1d1 }, - { 0x40fa8, 0xd3d3d3 }, - { 0x40fac, 0xd5d5d5 }, - { 0x40fb0, 0xd7d7d7 }, - { 0x40fb4, 0xd9d9d9 }, - { 0x40fb8, 0xdbdbdb }, - { 0x40fbc, 0xdddddd }, - { 0x40fc0, 0xdfdfdf }, - { 0x40fc4, 0xe1e1e1 }, - { 0x40fc8, 0xe3e3e3 }, - { 0x40fcc, 0xe5e5e5 }, - { 0x40fd0, 0xe7e7e7 }, - { 0x40fd4, 0xe9e9e9 }, - { 0x40fd8, 0xebebeb }, - { 0x40fdc, 0xeeeeee }, - { 0x40fe0, 0xf0f0f0 }, - { 0x40fe4, 0xf2f2f2 }, - { 0x40fe8, 0xf4f4f4 }, - { 0x40fec, 0xf6f6f6 }, - { 0x40ff0, 0xf8f8f8 }, - { 0x40ff4, 0xfbfbfb }, - { 0x40ff8, 0xfdfdfd }, - { 0x40ffc, 0xffffff }, -}; diff --git a/drivers/video/fbdev/msm/mdp_hw.h b/drivers/video/fbdev/msm/mdp_hw.h deleted file mode 100644 index 35848d741001..000000000000 --- a/drivers/video/fbdev/msm/mdp_hw.h +++ /dev/null @@ -1,627 +0,0 @@ -/* drivers/video/msm_fb/mdp_hw.h - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MDP_HW_H_ -#define _MDP_HW_H_ - -#include - -struct mdp_info { - struct mdp_device mdp_dev; - char * __iomem base; - int irq; -}; -struct mdp_blit_req; -struct mdp_device; -int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, - unsigned long src_len, struct file *dst_file, - unsigned long dst_start, unsigned long dst_len); -#define mdp_writel(mdp, value, offset) writel(value, mdp->base + offset) -#define mdp_readl(mdp, offset) readl(mdp->base + offset) - -#define MDP_SYNC_CONFIG_0 (0x00000) -#define MDP_SYNC_CONFIG_1 (0x00004) -#define MDP_SYNC_CONFIG_2 (0x00008) -#define MDP_SYNC_STATUS_0 (0x0000c) -#define MDP_SYNC_STATUS_1 (0x00010) -#define MDP_SYNC_STATUS_2 (0x00014) -#define MDP_SYNC_THRESH_0 (0x00018) -#define MDP_SYNC_THRESH_1 (0x0001c) -#define MDP_INTR_ENABLE (0x00020) -#define MDP_INTR_STATUS (0x00024) -#define MDP_INTR_CLEAR (0x00028) -#define MDP_DISPLAY0_START (0x00030) -#define MDP_DISPLAY1_START (0x00034) -#define MDP_DISPLAY_STATUS (0x00038) -#define MDP_EBI2_LCD0 (0x0003c) -#define MDP_EBI2_LCD1 (0x00040) -#define MDP_DISPLAY0_ADDR (0x00054) -#define MDP_DISPLAY1_ADDR (0x00058) -#define MDP_EBI2_PORTMAP_MODE (0x0005c) -#define MDP_MODE (0x00060) -#define MDP_TV_OUT_STATUS (0x00064) -#define MDP_HW_VERSION (0x00070) -#define MDP_SW_RESET (0x00074) -#define MDP_AXI_ERROR_MASTER_STOP (0x00078) -#define MDP_SEL_CLK_OR_HCLK_TEST_BUS (0x0007c) -#define MDP_PRIMARY_VSYNC_OUT_CTRL (0x00080) -#define MDP_SECONDARY_VSYNC_OUT_CTRL (0x00084) -#define MDP_EXTERNAL_VSYNC_OUT_CTRL (0x00088) -#define MDP_VSYNC_CTRL (0x0008c) -#define MDP_CGC_EN (0x00100) -#define MDP_CMD_STATUS (0x10008) -#define MDP_PROFILE_EN (0x10010) -#define MDP_PROFILE_COUNT (0x10014) -#define MDP_DMA_START (0x10044) -#define MDP_FULL_BYPASS_WORD0 (0x10100) -#define MDP_FULL_BYPASS_WORD1 (0x10104) -#define MDP_COMMAND_CONFIG (0x10104) -#define MDP_FULL_BYPASS_WORD2 (0x10108) -#define MDP_FULL_BYPASS_WORD3 (0x1010c) -#define MDP_FULL_BYPASS_WORD4 (0x10110) -#define MDP_FULL_BYPASS_WORD6 (0x10118) -#define MDP_FULL_BYPASS_WORD7 (0x1011c) -#define MDP_FULL_BYPASS_WORD8 (0x10120) -#define MDP_FULL_BYPASS_WORD9 (0x10124) -#define MDP_PPP_SOURCE_CONFIG (0x10124) -#define MDP_FULL_BYPASS_WORD10 (0x10128) -#define MDP_FULL_BYPASS_WORD11 (0x1012c) -#define MDP_FULL_BYPASS_WORD12 (0x10130) -#define MDP_FULL_BYPASS_WORD13 (0x10134) -#define MDP_FULL_BYPASS_WORD14 (0x10138) -#define MDP_PPP_OPERATION_CONFIG (0x10138) -#define MDP_FULL_BYPASS_WORD15 (0x1013c) -#define MDP_FULL_BYPASS_WORD16 (0x10140) -#define MDP_FULL_BYPASS_WORD17 (0x10144) -#define MDP_FULL_BYPASS_WORD18 (0x10148) -#define MDP_FULL_BYPASS_WORD19 (0x1014c) -#define MDP_FULL_BYPASS_WORD20 (0x10150) -#define MDP_PPP_DESTINATION_CONFIG (0x10150) -#define MDP_FULL_BYPASS_WORD21 (0x10154) -#define MDP_FULL_BYPASS_WORD22 (0x10158) -#define MDP_FULL_BYPASS_WORD23 (0x1015c) -#define MDP_FULL_BYPASS_WORD24 (0x10160) -#define MDP_FULL_BYPASS_WORD25 (0x10164) -#define MDP_FULL_BYPASS_WORD26 (0x10168) -#define MDP_FULL_BYPASS_WORD27 (0x1016c) -#define MDP_FULL_BYPASS_WORD29 (0x10174) -#define MDP_FULL_BYPASS_WORD30 (0x10178) -#define MDP_FULL_BYPASS_WORD31 (0x1017c) -#define MDP_FULL_BYPASS_WORD32 (0x10180) -#define MDP_DMA_CONFIG (0x10180) -#define MDP_FULL_BYPASS_WORD33 (0x10184) -#define MDP_FULL_BYPASS_WORD34 (0x10188) -#define MDP_FULL_BYPASS_WORD35 (0x1018c) -#define MDP_FULL_BYPASS_WORD37 (0x10194) -#define MDP_FULL_BYPASS_WORD39 (0x1019c) -#define MDP_FULL_BYPASS_WORD40 (0x101a0) -#define MDP_FULL_BYPASS_WORD41 (0x101a4) -#define MDP_FULL_BYPASS_WORD43 (0x101ac) -#define MDP_FULL_BYPASS_WORD46 (0x101b8) -#define MDP_FULL_BYPASS_WORD47 (0x101bc) -#define MDP_FULL_BYPASS_WORD48 (0x101c0) -#define MDP_FULL_BYPASS_WORD49 (0x101c4) -#define MDP_FULL_BYPASS_WORD50 (0x101c8) -#define MDP_FULL_BYPASS_WORD51 (0x101cc) -#define MDP_FULL_BYPASS_WORD52 (0x101d0) -#define MDP_FULL_BYPASS_WORD53 (0x101d4) -#define MDP_FULL_BYPASS_WORD54 (0x101d8) -#define MDP_FULL_BYPASS_WORD55 (0x101dc) -#define MDP_FULL_BYPASS_WORD56 (0x101e0) -#define MDP_FULL_BYPASS_WORD57 (0x101e4) -#define MDP_FULL_BYPASS_WORD58 (0x101e8) -#define MDP_FULL_BYPASS_WORD59 (0x101ec) -#define MDP_FULL_BYPASS_WORD60 (0x101f0) -#define MDP_VSYNC_THRESHOLD (0x101f0) -#define MDP_FULL_BYPASS_WORD61 (0x101f4) -#define MDP_FULL_BYPASS_WORD62 (0x101f8) -#define MDP_FULL_BYPASS_WORD63 (0x101fc) -#define MDP_TFETCH_TEST_MODE (0x20004) -#define MDP_TFETCH_STATUS (0x20008) -#define MDP_TFETCH_TILE_COUNT (0x20010) -#define MDP_TFETCH_FETCH_COUNT (0x20014) -#define MDP_TFETCH_CONSTANT_COLOR (0x20040) -#define MDP_CSC_BYPASS (0x40004) -#define MDP_SCALE_COEFF_LSB (0x5fffc) -#define MDP_TV_OUT_CTL (0xc0000) -#define MDP_TV_OUT_FIR_COEFF (0xc0004) -#define MDP_TV_OUT_BUF_ADDR (0xc0008) -#define MDP_TV_OUT_CC_DATA (0xc000c) -#define MDP_TV_OUT_SOBEL (0xc0010) -#define MDP_TV_OUT_Y_CLAMP (0xc0018) -#define MDP_TV_OUT_CB_CLAMP (0xc001c) -#define MDP_TV_OUT_CR_CLAMP (0xc0020) -#define MDP_TEST_MODE_CLK (0xd0000) -#define MDP_TEST_MISR_RESET_CLK (0xd0004) -#define MDP_TEST_EXPORT_MISR_CLK (0xd0008) -#define MDP_TEST_MISR_CURR_VAL_CLK (0xd000c) -#define MDP_TEST_MODE_HCLK (0xd0100) -#define MDP_TEST_MISR_RESET_HCLK (0xd0104) -#define MDP_TEST_EXPORT_MISR_HCLK (0xd0108) -#define MDP_TEST_MISR_CURR_VAL_HCLK (0xd010c) -#define MDP_TEST_MODE_DCLK (0xd0200) -#define MDP_TEST_MISR_RESET_DCLK (0xd0204) -#define MDP_TEST_EXPORT_MISR_DCLK (0xd0208) -#define MDP_TEST_MISR_CURR_VAL_DCLK (0xd020c) -#define MDP_TEST_CAPTURED_DCLK (0xd0210) -#define MDP_TEST_MISR_CAPT_VAL_DCLK (0xd0214) -#define MDP_LCDC_CTL (0xe0000) -#define MDP_LCDC_HSYNC_CTL (0xe0004) -#define MDP_LCDC_VSYNC_CTL (0xe0008) -#define MDP_LCDC_ACTIVE_HCTL (0xe000c) -#define MDP_LCDC_ACTIVE_VCTL (0xe0010) -#define MDP_LCDC_BORDER_CLR (0xe0014) -#define MDP_LCDC_H_BLANK (0xe0018) -#define MDP_LCDC_V_BLANK (0xe001c) -#define MDP_LCDC_UNDERFLOW_CLR (0xe0020) -#define MDP_LCDC_HSYNC_SKEW (0xe0024) -#define MDP_LCDC_TEST_CTL (0xe0028) -#define MDP_LCDC_LINE_IRQ (0xe002c) -#define MDP_LCDC_CTL_POLARITY (0xe0030) -#define MDP_LCDC_DMA_CONFIG (0xe1000) -#define MDP_LCDC_DMA_SIZE (0xe1004) -#define MDP_LCDC_DMA_IBUF_ADDR (0xe1008) -#define MDP_LCDC_DMA_IBUF_Y_STRIDE (0xe100c) - - -#define MDP_DMA2_TERM 0x1 -#define MDP_DMA3_TERM 0x2 -#define MDP_PPP_TERM 0x3 - -/* MDP_INTR_ENABLE */ -#define DL0_ROI_DONE (1<<0) -#define DL1_ROI_DONE (1<<1) -#define DL0_DMA2_TERM_DONE (1<<2) -#define DL1_DMA2_TERM_DONE (1<<3) -#define DL0_PPP_TERM_DONE (1<<4) -#define DL1_PPP_TERM_DONE (1<<5) -#define TV_OUT_DMA3_DONE (1<<6) -#define TV_ENC_UNDERRUN (1<<7) -#define DL0_FETCH_DONE (1<<11) -#define DL1_FETCH_DONE (1<<12) - -#define MDP_PPP_BUSY_STATUS (DL0_ROI_DONE| \ - DL1_ROI_DONE| \ - DL0_PPP_TERM_DONE| \ - DL1_PPP_TERM_DONE) - -#define MDP_ANY_INTR_MASK (DL0_ROI_DONE| \ - DL1_ROI_DONE| \ - DL0_DMA2_TERM_DONE| \ - DL1_DMA2_TERM_DONE| \ - DL0_PPP_TERM_DONE| \ - DL1_PPP_TERM_DONE| \ - DL0_FETCH_DONE| \ - DL1_FETCH_DONE| \ - TV_ENC_UNDERRUN) - -#define MDP_TOP_LUMA 16 -#define MDP_TOP_CHROMA 0 -#define MDP_BOTTOM_LUMA 19 -#define MDP_BOTTOM_CHROMA 3 -#define MDP_LEFT_LUMA 22 -#define MDP_LEFT_CHROMA 6 -#define MDP_RIGHT_LUMA 25 -#define MDP_RIGHT_CHROMA 9 - -#define CLR_G 0x0 -#define CLR_B 0x1 -#define CLR_R 0x2 -#define CLR_ALPHA 0x3 - -#define CLR_Y CLR_G -#define CLR_CB CLR_B -#define CLR_CR CLR_R - -/* from lsb to msb */ -#define MDP_GET_PACK_PATTERN(a, x, y, z, bit) \ - (((a)<<(bit*3))|((x)<<(bit*2))|((y)< -#include -#include -#include -#include - -#include "mdp_hw.h" -#include "mdp_scale_tables.h" - -#define DLOG(x...) do {} while (0) - -#define MDP_DOWNSCALE_BLUR (MDP_DOWNSCALE_MAX + 1) -static int downscale_y_table = MDP_DOWNSCALE_MAX; -static int downscale_x_table = MDP_DOWNSCALE_MAX; - -struct mdp_regs { - uint32_t src0; - uint32_t src1; - uint32_t dst0; - uint32_t dst1; - uint32_t src_cfg; - uint32_t dst_cfg; - uint32_t src_pack; - uint32_t dst_pack; - uint32_t src_rect; - uint32_t dst_rect; - uint32_t src_ystride; - uint32_t dst_ystride; - uint32_t op; - uint32_t src_bpp; - uint32_t dst_bpp; - uint32_t edge; - uint32_t phasex_init; - uint32_t phasey_init; - uint32_t phasex_step; - uint32_t phasey_step; -}; - -static uint32_t pack_pattern[] = { - PPP_ARRAY0(PACK_PATTERN) -}; - -static uint32_t src_img_cfg[] = { - PPP_ARRAY1(CFG, SRC) -}; - -static uint32_t dst_img_cfg[] = { - PPP_ARRAY1(CFG, DST) -}; - -static uint32_t bytes_per_pixel[] = { - [MDP_RGB_565] = 2, - [MDP_RGB_888] = 3, - [MDP_XRGB_8888] = 4, - [MDP_ARGB_8888] = 4, - [MDP_RGBA_8888] = 4, - [MDP_BGRA_8888] = 4, - [MDP_RGBX_8888] = 4, - [MDP_Y_CBCR_H2V1] = 1, - [MDP_Y_CBCR_H2V2] = 1, - [MDP_Y_CRCB_H2V1] = 1, - [MDP_Y_CRCB_H2V2] = 1, - [MDP_YCRYCB_H2V1] = 2 -}; - -static uint32_t dst_op_chroma[] = { - PPP_ARRAY1(CHROMA_SAMP, DST) -}; - -static uint32_t src_op_chroma[] = { - PPP_ARRAY1(CHROMA_SAMP, SRC) -}; - -static uint32_t bg_op_chroma[] = { - PPP_ARRAY1(CHROMA_SAMP, BG) -}; - -static void rotate_dst_addr_x(struct mdp_blit_req *req, struct mdp_regs *regs) -{ - regs->dst0 += (req->dst_rect.w - - min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp; - regs->dst1 += (req->dst_rect.w - - min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp; -} - -static void rotate_dst_addr_y(struct mdp_blit_req *req, struct mdp_regs *regs) -{ - regs->dst0 += (req->dst_rect.h - - min((uint32_t)16, req->dst_rect.h)) * - regs->dst_ystride; - regs->dst1 += (req->dst_rect.h - - min((uint32_t)16, req->dst_rect.h)) * - regs->dst_ystride; -} - -static void blit_rotate(struct mdp_blit_req *req, - struct mdp_regs *regs) -{ - if (req->flags == MDP_ROT_NOP) - return; - - regs->op |= PPP_OP_ROT_ON; - if ((req->flags & MDP_ROT_90 || req->flags & MDP_FLIP_LR) && - !(req->flags & MDP_ROT_90 && req->flags & MDP_FLIP_LR)) - rotate_dst_addr_x(req, regs); - if (req->flags & MDP_ROT_90) - regs->op |= PPP_OP_ROT_90; - if (req->flags & MDP_FLIP_UD) { - regs->op |= PPP_OP_FLIP_UD; - rotate_dst_addr_y(req, regs); - } - if (req->flags & MDP_FLIP_LR) - regs->op |= PPP_OP_FLIP_LR; -} - -static void blit_convert(struct mdp_blit_req *req, struct mdp_regs *regs) -{ - if (req->src.format == req->dst.format) - return; - if (IS_RGB(req->src.format) && IS_YCRCB(req->dst.format)) { - regs->op |= PPP_OP_CONVERT_RGB2YCBCR | PPP_OP_CONVERT_ON; - } else if (IS_YCRCB(req->src.format) && IS_RGB(req->dst.format)) { - regs->op |= PPP_OP_CONVERT_YCBCR2RGB | PPP_OP_CONVERT_ON; - if (req->dst.format == MDP_RGB_565) - regs->op |= PPP_OP_CONVERT_MATRIX_SECONDARY; - } -} - -#define GET_BIT_RANGE(value, high, low) \ - (((1 << (high - low + 1)) - 1) & (value >> low)) -static uint32_t transp_convert(struct mdp_blit_req *req) -{ - uint32_t transp = 0; - if (req->src.format == MDP_RGB_565) { - /* pad each value to 8 bits by copying the high bits into the - * low end, convert RGB to RBG by switching low 2 components */ - transp |= ((GET_BIT_RANGE(req->transp_mask, 15, 11) << 3) | - (GET_BIT_RANGE(req->transp_mask, 15, 13))) << 16; - - transp |= ((GET_BIT_RANGE(req->transp_mask, 4, 0) << 3) | - (GET_BIT_RANGE(req->transp_mask, 4, 2))) << 8; - - transp |= (GET_BIT_RANGE(req->transp_mask, 10, 5) << 2) | - (GET_BIT_RANGE(req->transp_mask, 10, 9)); - } else { - /* convert RGB to RBG */ - transp |= (GET_BIT_RANGE(req->transp_mask, 15, 8)) | - (GET_BIT_RANGE(req->transp_mask, 23, 16) << 16) | - (GET_BIT_RANGE(req->transp_mask, 7, 0) << 8); - } - return transp; -} -#undef GET_BIT_RANGE - -static void blit_blend(struct mdp_blit_req *req, struct mdp_regs *regs) -{ - /* TRANSP BLEND */ - if (req->transp_mask != MDP_TRANSP_NOP) { - req->transp_mask = transp_convert(req); - if (req->alpha != MDP_ALPHA_NOP) { - /* use blended transparancy mode - * pixel = (src == transp) ? dst : blend - * blend is combo of blend_eq_sel and - * blend_alpha_sel */ - regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON | - PPP_OP_BLEND_ALPHA_BLEND_NORMAL | - PPP_OP_BLEND_CONSTANT_ALPHA | - PPP_BLEND_ALPHA_TRANSP; - } else { - /* simple transparancy mode - * pixel = (src == transp) ? dst : src */ - regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON | - PPP_OP_BLEND_SRCPIXEL_TRANSP; - } - } - - req->alpha &= 0xff; - /* ALPHA BLEND */ - if (HAS_ALPHA(req->src.format)) { - regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON | - PPP_OP_BLEND_SRCPIXEL_ALPHA; - } else if (req->alpha < MDP_ALPHA_NOP) { - /* just blend by alpha */ - regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON | - PPP_OP_BLEND_ALPHA_BLEND_NORMAL | - PPP_OP_BLEND_CONSTANT_ALPHA; - } - - regs->op |= bg_op_chroma[req->dst.format]; -} - -#define ONE_HALF (1LL << 32) -#define ONE (1LL << 33) -#define TWO (2LL << 33) -#define THREE (3LL << 33) -#define FRAC_MASK (ONE - 1) -#define INT_MASK (~FRAC_MASK) - -static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin, - uint32_t *phase_init, uint32_t *phase_step) -{ - /* to improve precicsion calculations are done in U31.33 and converted - * to U3.29 at the end */ - int64_t k1, k2, k3, k4, tmp; - uint64_t n, d, os, os_p, od, od_p, oreq; - unsigned rpa = 0; - int64_t ip64, delta; - - if (dim_out % 3 == 0) - rpa = !(dim_in % (dim_out / 3)); - - n = ((uint64_t)dim_out) << 34; - d = dim_in; - if (!d) - return -1; - do_div(n, d); - k3 = (n + 1) >> 1; - if ((k3 >> 4) < (1LL << 27) || (k3 >> 4) > (1LL << 31)) { - DLOG("crap bad scale\n"); - return -1; - } - n = ((uint64_t)dim_in) << 34; - d = (uint64_t)dim_out; - if (!d) - return -1; - do_div(n, d); - k1 = (n + 1) >> 1; - k2 = (k1 - ONE) >> 1; - - *phase_init = (int)(k2 >> 4); - k4 = (k3 - ONE) >> 1; - - if (rpa) { - os = ((uint64_t)origin << 33) - ONE_HALF; - tmp = (dim_out * os) + ONE_HALF; - if (!dim_in) - return -1; - do_div(tmp, dim_in); - od = tmp - ONE_HALF; - } else { - os = ((uint64_t)origin << 1) - 1; - od = (((k3 * os) >> 1) + k4); - } - - od_p = od & INT_MASK; - if (od_p != od) - od_p += ONE; - - if (rpa) { - tmp = (dim_in * od_p) + ONE_HALF; - if (!dim_in) - return -1; - do_div(tmp, dim_in); - os_p = tmp - ONE_HALF; - } else { - os_p = ((k1 * (od_p >> 33)) + k2); - } - - oreq = (os_p & INT_MASK) - ONE; - - ip64 = os_p - oreq; - delta = ((int64_t)(origin) << 33) - oreq; - ip64 -= delta; - /* limit to valid range before the left shift */ - delta = (ip64 & (1LL << 63)) ? 4 : -4; - delta <<= 33; - while (abs((int)(ip64 >> 33)) > 4) - ip64 += delta; - *phase_init = (int)(ip64 >> 4); - *phase_step = (uint32_t)(k1 >> 4); - return 0; -} - -static void load_scale_table(const struct mdp_info *mdp, - struct mdp_table_entry *table, int len) -{ - int i; - for (i = 0; i < len; i++) - mdp_writel(mdp, table[i].val, table[i].reg); -} - -enum { -IMG_LEFT, -IMG_RIGHT, -IMG_TOP, -IMG_BOTTOM, -}; - -static void get_edge_info(uint32_t src, uint32_t src_coord, uint32_t dst, - uint32_t *interp1, uint32_t *interp2, - uint32_t *repeat1, uint32_t *repeat2) { - if (src > 3 * dst) { - *interp1 = 0; - *interp2 = src - 1; - *repeat1 = 0; - *repeat2 = 0; - } else if (src == 3 * dst) { - *interp1 = 0; - *interp2 = src; - *repeat1 = 0; - *repeat2 = 1; - } else if (src > dst && src < 3 * dst) { - *interp1 = -1; - *interp2 = src; - *repeat1 = 1; - *repeat2 = 1; - } else if (src == dst) { - *interp1 = -1; - *interp2 = src + 1; - *repeat1 = 1; - *repeat2 = 2; - } else { - *interp1 = -2; - *interp2 = src + 1; - *repeat1 = 2; - *repeat2 = 2; - } - *interp1 += src_coord; - *interp2 += src_coord; -} - -static int get_edge_cond(struct mdp_blit_req *req, struct mdp_regs *regs) -{ - int32_t luma_interp[4]; - int32_t luma_repeat[4]; - int32_t chroma_interp[4]; - int32_t chroma_bound[4]; - int32_t chroma_repeat[4]; - uint32_t dst_w, dst_h; - - memset(&luma_interp, 0, sizeof(int32_t) * 4); - memset(&luma_repeat, 0, sizeof(int32_t) * 4); - memset(&chroma_interp, 0, sizeof(int32_t) * 4); - memset(&chroma_bound, 0, sizeof(int32_t) * 4); - memset(&chroma_repeat, 0, sizeof(int32_t) * 4); - regs->edge = 0; - - if (req->flags & MDP_ROT_90) { - dst_w = req->dst_rect.h; - dst_h = req->dst_rect.w; - } else { - dst_w = req->dst_rect.w; - dst_h = req->dst_rect.h; - } - - if (regs->op & (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON)) { - get_edge_info(req->src_rect.h, req->src_rect.y, dst_h, - &luma_interp[IMG_TOP], &luma_interp[IMG_BOTTOM], - &luma_repeat[IMG_TOP], &luma_repeat[IMG_BOTTOM]); - get_edge_info(req->src_rect.w, req->src_rect.x, dst_w, - &luma_interp[IMG_LEFT], &luma_interp[IMG_RIGHT], - &luma_repeat[IMG_LEFT], &luma_repeat[IMG_RIGHT]); - } else { - luma_interp[IMG_LEFT] = req->src_rect.x; - luma_interp[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1; - luma_interp[IMG_TOP] = req->src_rect.y; - luma_interp[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1; - luma_repeat[IMG_LEFT] = 0; - luma_repeat[IMG_TOP] = 0; - luma_repeat[IMG_RIGHT] = 0; - luma_repeat[IMG_BOTTOM] = 0; - } - - chroma_interp[IMG_LEFT] = luma_interp[IMG_LEFT]; - chroma_interp[IMG_RIGHT] = luma_interp[IMG_RIGHT]; - chroma_interp[IMG_TOP] = luma_interp[IMG_TOP]; - chroma_interp[IMG_BOTTOM] = luma_interp[IMG_BOTTOM]; - - chroma_bound[IMG_LEFT] = req->src_rect.x; - chroma_bound[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1; - chroma_bound[IMG_TOP] = req->src_rect.y; - chroma_bound[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1; - - if (IS_YCRCB(req->src.format)) { - chroma_interp[IMG_LEFT] = chroma_interp[IMG_LEFT] >> 1; - chroma_interp[IMG_RIGHT] = (chroma_interp[IMG_RIGHT] + 1) >> 1; - - chroma_bound[IMG_LEFT] = chroma_bound[IMG_LEFT] >> 1; - chroma_bound[IMG_RIGHT] = chroma_bound[IMG_RIGHT] >> 1; - } - - if (req->src.format == MDP_Y_CBCR_H2V2 || - req->src.format == MDP_Y_CRCB_H2V2) { - chroma_interp[IMG_TOP] = (chroma_interp[IMG_TOP] - 1) >> 1; - chroma_interp[IMG_BOTTOM] = (chroma_interp[IMG_BOTTOM] + 1) - >> 1; - chroma_bound[IMG_TOP] = (chroma_bound[IMG_TOP] + 1) >> 1; - chroma_bound[IMG_BOTTOM] = chroma_bound[IMG_BOTTOM] >> 1; - } - - chroma_repeat[IMG_LEFT] = chroma_bound[IMG_LEFT] - - chroma_interp[IMG_LEFT]; - chroma_repeat[IMG_RIGHT] = chroma_interp[IMG_RIGHT] - - chroma_bound[IMG_RIGHT]; - chroma_repeat[IMG_TOP] = chroma_bound[IMG_TOP] - - chroma_interp[IMG_TOP]; - chroma_repeat[IMG_BOTTOM] = chroma_interp[IMG_BOTTOM] - - chroma_bound[IMG_BOTTOM]; - - if (chroma_repeat[IMG_LEFT] < 0 || chroma_repeat[IMG_LEFT] > 3 || - chroma_repeat[IMG_RIGHT] < 0 || chroma_repeat[IMG_RIGHT] > 3 || - chroma_repeat[IMG_TOP] < 0 || chroma_repeat[IMG_TOP] > 3 || - chroma_repeat[IMG_BOTTOM] < 0 || chroma_repeat[IMG_BOTTOM] > 3 || - luma_repeat[IMG_LEFT] < 0 || luma_repeat[IMG_LEFT] > 3 || - luma_repeat[IMG_RIGHT] < 0 || luma_repeat[IMG_RIGHT] > 3 || - luma_repeat[IMG_TOP] < 0 || luma_repeat[IMG_TOP] > 3 || - luma_repeat[IMG_BOTTOM] < 0 || luma_repeat[IMG_BOTTOM] > 3) - return -1; - - regs->edge |= (chroma_repeat[IMG_LEFT] & 3) << MDP_LEFT_CHROMA; - regs->edge |= (chroma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_CHROMA; - regs->edge |= (chroma_repeat[IMG_TOP] & 3) << MDP_TOP_CHROMA; - regs->edge |= (chroma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_CHROMA; - regs->edge |= (luma_repeat[IMG_LEFT] & 3) << MDP_LEFT_LUMA; - regs->edge |= (luma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_LUMA; - regs->edge |= (luma_repeat[IMG_TOP] & 3) << MDP_TOP_LUMA; - regs->edge |= (luma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_LUMA; - return 0; -} - -static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct mdp_regs *regs) -{ - uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y; - uint32_t scale_factor_x, scale_factor_y; - uint32_t downscale; - uint32_t dst_w, dst_h; - - if (req->flags & MDP_ROT_90) { - dst_w = req->dst_rect.h; - dst_h = req->dst_rect.w; - } else { - dst_w = req->dst_rect.w; - dst_h = req->dst_rect.h; - } - if ((req->src_rect.w == dst_w) && (req->src_rect.h == dst_h) && - !(req->flags & MDP_BLUR)) { - regs->phasex_init = 0; - regs->phasey_init = 0; - regs->phasex_step = 0; - regs->phasey_step = 0; - return 0; - } - - if (scale_params(req->src_rect.w, dst_w, 1, &phase_init_x, - &phase_step_x) || - scale_params(req->src_rect.h, dst_h, 1, &phase_init_y, - &phase_step_y)) - return -1; - - scale_factor_x = (dst_w * 10) / req->src_rect.w; - scale_factor_y = (dst_h * 10) / req->src_rect.h; - - if (scale_factor_x > 8) - downscale = MDP_DOWNSCALE_PT8TO1; - else if (scale_factor_x > 6) - downscale = MDP_DOWNSCALE_PT6TOPT8; - else if (scale_factor_x > 4) - downscale = MDP_DOWNSCALE_PT4TOPT6; - else - downscale = MDP_DOWNSCALE_PT2TOPT4; - if (downscale != downscale_x_table) { - load_scale_table(mdp, mdp_downscale_x_table[downscale], 64); - downscale_x_table = downscale; - } - - if (scale_factor_y > 8) - downscale = MDP_DOWNSCALE_PT8TO1; - else if (scale_factor_y > 6) - downscale = MDP_DOWNSCALE_PT6TOPT8; - else if (scale_factor_y > 4) - downscale = MDP_DOWNSCALE_PT4TOPT6; - else - downscale = MDP_DOWNSCALE_PT2TOPT4; - if (downscale != downscale_y_table) { - load_scale_table(mdp, mdp_downscale_y_table[downscale], 64); - downscale_y_table = downscale; - } - - regs->phasex_init = phase_init_x; - regs->phasey_init = phase_init_y; - regs->phasex_step = phase_step_x; - regs->phasey_step = phase_step_y; - regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); - return 0; - -} - -static void blit_blur(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct mdp_regs *regs) -{ - if (!(req->flags & MDP_BLUR)) - return; - - if (!(downscale_x_table == MDP_DOWNSCALE_BLUR && - downscale_y_table == MDP_DOWNSCALE_BLUR)) { - load_scale_table(mdp, mdp_gaussian_blur_table, 128); - downscale_x_table = MDP_DOWNSCALE_BLUR; - downscale_y_table = MDP_DOWNSCALE_BLUR; - } - - regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); -} - - -#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp) - -#define Y_TO_CRCB_RATIO(format) \ - ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ? 2 :\ - (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ? 1 : 1) - -static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp, - uint32_t *len0, uint32_t *len1) -{ - *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp); - if (IS_PSEUDOPLNR(img->format)) - *len1 = *len0/Y_TO_CRCB_RATIO(img->format); - else - *len1 = 0; -} - -static int valid_src_dst(unsigned long src_start, unsigned long src_len, - unsigned long dst_start, unsigned long dst_len, - struct mdp_blit_req *req, struct mdp_regs *regs) -{ - unsigned long src_min_ok = src_start; - unsigned long src_max_ok = src_start + src_len; - unsigned long dst_min_ok = dst_start; - unsigned long dst_max_ok = dst_start + dst_len; - uint32_t src0_len, src1_len, dst0_len, dst1_len; - get_len(&req->src, &req->src_rect, regs->src_bpp, &src0_len, - &src1_len); - get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len, - &dst1_len); - - if (regs->src0 < src_min_ok || regs->src0 > src_max_ok || - regs->src0 + src0_len > src_max_ok) { - DLOG("invalid_src %x %x %lx %lx\n", regs->src0, - src0_len, src_min_ok, src_max_ok); - return 0; - } - if (regs->src_cfg & PPP_SRC_PLANE_PSEUDOPLNR) { - if (regs->src1 < src_min_ok || regs->src1 > src_max_ok || - regs->src1 + src1_len > src_max_ok) { - DLOG("invalid_src1"); - return 0; - } - } - if (regs->dst0 < dst_min_ok || regs->dst0 > dst_max_ok || - regs->dst0 + dst0_len > dst_max_ok) { - DLOG("invalid_dst"); - return 0; - } - if (regs->dst_cfg & PPP_SRC_PLANE_PSEUDOPLNR) { - if (regs->dst1 < dst_min_ok || regs->dst1 > dst_max_ok || - regs->dst1 + dst1_len > dst_max_ok) { - DLOG("invalid_dst1"); - return 0; - } - } - return 1; -} - - -static void flush_imgs(struct mdp_blit_req *req, struct mdp_regs *regs, - struct file *src_file, struct file *dst_file) -{ -} - -static void get_chroma_addr(struct mdp_img *img, struct mdp_rect *rect, - uint32_t base, uint32_t bpp, uint32_t cfg, - uint32_t *addr, uint32_t *ystride) -{ - uint32_t compress_v = Y_TO_CRCB_RATIO(img->format); - uint32_t compress_h = 2; - uint32_t offset; - - if (IS_PSEUDOPLNR(img->format)) { - offset = (rect->x / compress_h) * compress_h; - offset += rect->y == 0 ? 0 : - ((rect->y + 1) / compress_v) * img->width; - *addr = base + (img->width * img->height * bpp); - *addr += offset * bpp; - *ystride |= *ystride << 16; - } else { - *addr = 0; - } -} - -static int send_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct mdp_regs *regs, struct file *src_file, - struct file *dst_file) -{ - mdp_writel(mdp, 1, 0x060); - mdp_writel(mdp, regs->src_rect, PPP_ADDR_SRC_ROI); - mdp_writel(mdp, regs->src0, PPP_ADDR_SRC0); - mdp_writel(mdp, regs->src1, PPP_ADDR_SRC1); - mdp_writel(mdp, regs->src_ystride, PPP_ADDR_SRC_YSTRIDE); - mdp_writel(mdp, regs->src_cfg, PPP_ADDR_SRC_CFG); - mdp_writel(mdp, regs->src_pack, PPP_ADDR_SRC_PACK_PATTERN); - - mdp_writel(mdp, regs->op, PPP_ADDR_OPERATION); - mdp_writel(mdp, regs->phasex_init, PPP_ADDR_PHASEX_INIT); - mdp_writel(mdp, regs->phasey_init, PPP_ADDR_PHASEY_INIT); - mdp_writel(mdp, regs->phasex_step, PPP_ADDR_PHASEX_STEP); - mdp_writel(mdp, regs->phasey_step, PPP_ADDR_PHASEY_STEP); - - mdp_writel(mdp, (req->alpha << 24) | (req->transp_mask & 0xffffff), - PPP_ADDR_ALPHA_TRANSP); - - mdp_writel(mdp, regs->dst_cfg, PPP_ADDR_DST_CFG); - mdp_writel(mdp, regs->dst_pack, PPP_ADDR_DST_PACK_PATTERN); - mdp_writel(mdp, regs->dst_rect, PPP_ADDR_DST_ROI); - mdp_writel(mdp, regs->dst0, PPP_ADDR_DST0); - mdp_writel(mdp, regs->dst1, PPP_ADDR_DST1); - mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_DST_YSTRIDE); - - mdp_writel(mdp, regs->edge, PPP_ADDR_EDGE); - if (regs->op & PPP_OP_BLEND_ON) { - mdp_writel(mdp, regs->dst0, PPP_ADDR_BG0); - mdp_writel(mdp, regs->dst1, PPP_ADDR_BG1); - mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_BG_YSTRIDE); - mdp_writel(mdp, src_img_cfg[req->dst.format], PPP_ADDR_BG_CFG); - mdp_writel(mdp, pack_pattern[req->dst.format], - PPP_ADDR_BG_PACK_PATTERN); - } - flush_imgs(req, regs, src_file, dst_file); - mdp_writel(mdp, 0x1000, MDP_DISPLAY0_START); - return 0; -} - -int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, - struct file *src_file, unsigned long src_start, unsigned long src_len, - struct file *dst_file, unsigned long dst_start, unsigned long dst_len) -{ - struct mdp_regs regs = {0}; - - if (unlikely(req->src.format >= MDP_IMGTYPE_LIMIT || - req->dst.format >= MDP_IMGTYPE_LIMIT)) { - printk(KERN_ERR "mpd_ppp: img is of wrong format\n"); - return -EINVAL; - } - - if (unlikely(req->src_rect.x > req->src.width || - req->src_rect.y > req->src.height || - req->dst_rect.x > req->dst.width || - req->dst_rect.y > req->dst.height)) { - printk(KERN_ERR "mpd_ppp: img rect is outside of img!\n"); - return -EINVAL; - } - - /* set the src image configuration */ - regs.src_cfg = src_img_cfg[req->src.format]; - regs.src_cfg |= (req->src_rect.x & 0x1) ? PPP_SRC_BPP_ROI_ODD_X : 0; - regs.src_cfg |= (req->src_rect.y & 0x1) ? PPP_SRC_BPP_ROI_ODD_Y : 0; - regs.src_rect = (req->src_rect.h << 16) | req->src_rect.w; - regs.src_pack = pack_pattern[req->src.format]; - - /* set the dest image configuration */ - regs.dst_cfg = dst_img_cfg[req->dst.format] | PPP_DST_OUT_SEL_AXI; - regs.dst_rect = (req->dst_rect.h << 16) | req->dst_rect.w; - regs.dst_pack = pack_pattern[req->dst.format]; - - /* set src, bpp, start pixel and ystride */ - regs.src_bpp = bytes_per_pixel[req->src.format]; - regs.src0 = src_start + req->src.offset; - regs.src_ystride = req->src.width * regs.src_bpp; - get_chroma_addr(&req->src, &req->src_rect, regs.src0, regs.src_bpp, - regs.src_cfg, ®s.src1, ®s.src_ystride); - regs.src0 += (req->src_rect.x + (req->src_rect.y * req->src.width)) * - regs.src_bpp; - - /* set dst, bpp, start pixel and ystride */ - regs.dst_bpp = bytes_per_pixel[req->dst.format]; - regs.dst0 = dst_start + req->dst.offset; - regs.dst_ystride = req->dst.width * regs.dst_bpp; - get_chroma_addr(&req->dst, &req->dst_rect, regs.dst0, regs.dst_bpp, - regs.dst_cfg, ®s.dst1, ®s.dst_ystride); - regs.dst0 += (req->dst_rect.x + (req->dst_rect.y * req->dst.width)) * - regs.dst_bpp; - - if (!valid_src_dst(src_start, src_len, dst_start, dst_len, req, - ®s)) { - printk(KERN_ERR "mpd_ppp: final src or dst location is " - "invalid, are you trying to make an image too large " - "or to place it outside the screen?\n"); - return -EINVAL; - } - - /* set up operation register */ - regs.op = 0; - blit_rotate(req, ®s); - blit_convert(req, ®s); - if (req->flags & MDP_DITHER) - regs.op |= PPP_OP_DITHER_EN; - blit_blend(req, ®s); - if (blit_scale(mdp, req, ®s)) { - printk(KERN_ERR "mpd_ppp: error computing scale for img.\n"); - return -EINVAL; - } - blit_blur(mdp, req, ®s); - regs.op |= dst_op_chroma[req->dst.format] | - src_op_chroma[req->src.format]; - - /* if the image is YCRYCB, the x and w must be even */ - if (unlikely(req->src.format == MDP_YCRYCB_H2V1)) { - req->src_rect.x = req->src_rect.x & (~0x1); - req->src_rect.w = req->src_rect.w & (~0x1); - req->dst_rect.x = req->dst_rect.x & (~0x1); - req->dst_rect.w = req->dst_rect.w & (~0x1); - } - if (get_edge_cond(req, ®s)) - return -EINVAL; - - send_blit(mdp, req, ®s, src_file, dst_file); - return 0; -} diff --git a/drivers/video/fbdev/msm/mdp_scale_tables.c b/drivers/video/fbdev/msm/mdp_scale_tables.c deleted file mode 100644 index 604783b2e17c..000000000000 --- a/drivers/video/fbdev/msm/mdp_scale_tables.c +++ /dev/null @@ -1,766 +0,0 @@ -/* drivers/video/msm_fb/mdp_scale_tables.c - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "mdp_scale_tables.h" -#include "mdp_hw.h" - -struct mdp_table_entry mdp_upscale_table[] = { - { 0x5fffc, 0x0 }, - { 0x50200, 0x7fc00000 }, - { 0x5fffc, 0xff80000d }, - { 0x50204, 0x7ec003f9 }, - { 0x5fffc, 0xfec0001c }, - { 0x50208, 0x7d4003f3 }, - { 0x5fffc, 0xfe40002b }, - { 0x5020c, 0x7b8003ed }, - { 0x5fffc, 0xfd80003c }, - { 0x50210, 0x794003e8 }, - { 0x5fffc, 0xfcc0004d }, - { 0x50214, 0x76c003e4 }, - { 0x5fffc, 0xfc40005f }, - { 0x50218, 0x73c003e0 }, - { 0x5fffc, 0xfb800071 }, - { 0x5021c, 0x708003de }, - { 0x5fffc, 0xfac00085 }, - { 0x50220, 0x6d0003db }, - { 0x5fffc, 0xfa000098 }, - { 0x50224, 0x698003d9 }, - { 0x5fffc, 0xf98000ac }, - { 0x50228, 0x654003d8 }, - { 0x5fffc, 0xf8c000c1 }, - { 0x5022c, 0x610003d7 }, - { 0x5fffc, 0xf84000d5 }, - { 0x50230, 0x5c8003d7 }, - { 0x5fffc, 0xf7c000e9 }, - { 0x50234, 0x580003d7 }, - { 0x5fffc, 0xf74000fd }, - { 0x50238, 0x534003d8 }, - { 0x5fffc, 0xf6c00112 }, - { 0x5023c, 0x4e8003d8 }, - { 0x5fffc, 0xf6800126 }, - { 0x50240, 0x494003da }, - { 0x5fffc, 0xf600013a }, - { 0x50244, 0x448003db }, - { 0x5fffc, 0xf600014d }, - { 0x50248, 0x3f4003dd }, - { 0x5fffc, 0xf5c00160 }, - { 0x5024c, 0x3a4003df }, - { 0x5fffc, 0xf5c00172 }, - { 0x50250, 0x354003e1 }, - { 0x5fffc, 0xf5c00184 }, - { 0x50254, 0x304003e3 }, - { 0x5fffc, 0xf6000195 }, - { 0x50258, 0x2b0003e6 }, - { 0x5fffc, 0xf64001a6 }, - { 0x5025c, 0x260003e8 }, - { 0x5fffc, 0xf6c001b4 }, - { 0x50260, 0x214003eb }, - { 0x5fffc, 0xf78001c2 }, - { 0x50264, 0x1c4003ee }, - { 0x5fffc, 0xf80001cf }, - { 0x50268, 0x17c003f1 }, - { 0x5fffc, 0xf90001db }, - { 0x5026c, 0x134003f3 }, - { 0x5fffc, 0xfa0001e5 }, - { 0x50270, 0xf0003f6 }, - { 0x5fffc, 0xfb4001ee }, - { 0x50274, 0xac003f9 }, - { 0x5fffc, 0xfcc001f5 }, - { 0x50278, 0x70003fb }, - { 0x5fffc, 0xfe4001fb }, - { 0x5027c, 0x34003fe }, -}; - -static struct mdp_table_entry mdp_downscale_x_table_PT2TOPT4[] = { - { 0x5fffc, 0x740008c }, - { 0x50280, 0x33800088 }, - { 0x5fffc, 0x800008e }, - { 0x50284, 0x33400084 }, - { 0x5fffc, 0x8400092 }, - { 0x50288, 0x33000080 }, - { 0x5fffc, 0x9000094 }, - { 0x5028c, 0x3300007b }, - { 0x5fffc, 0x9c00098 }, - { 0x50290, 0x32400077 }, - { 0x5fffc, 0xa40009b }, - { 0x50294, 0x32000073 }, - { 0x5fffc, 0xb00009d }, - { 0x50298, 0x31c0006f }, - { 0x5fffc, 0xbc000a0 }, - { 0x5029c, 0x3140006b }, - { 0x5fffc, 0xc8000a2 }, - { 0x502a0, 0x31000067 }, - { 0x5fffc, 0xd8000a5 }, - { 0x502a4, 0x30800062 }, - { 0x5fffc, 0xe4000a8 }, - { 0x502a8, 0x2fc0005f }, - { 0x5fffc, 0xec000aa }, - { 0x502ac, 0x2fc0005b }, - { 0x5fffc, 0xf8000ad }, - { 0x502b0, 0x2f400057 }, - { 0x5fffc, 0x108000b0 }, - { 0x502b4, 0x2e400054 }, - { 0x5fffc, 0x114000b2 }, - { 0x502b8, 0x2e000050 }, - { 0x5fffc, 0x124000b4 }, - { 0x502bc, 0x2d80004c }, - { 0x5fffc, 0x130000b6 }, - { 0x502c0, 0x2d000049 }, - { 0x5fffc, 0x140000b8 }, - { 0x502c4, 0x2c800045 }, - { 0x5fffc, 0x150000b9 }, - { 0x502c8, 0x2c000042 }, - { 0x5fffc, 0x15c000bd }, - { 0x502cc, 0x2b40003e }, - { 0x5fffc, 0x16c000bf }, - { 0x502d0, 0x2a80003b }, - { 0x5fffc, 0x17c000bf }, - { 0x502d4, 0x2a000039 }, - { 0x5fffc, 0x188000c2 }, - { 0x502d8, 0x29400036 }, - { 0x5fffc, 0x19c000c4 }, - { 0x502dc, 0x28800032 }, - { 0x5fffc, 0x1ac000c5 }, - { 0x502e0, 0x2800002f }, - { 0x5fffc, 0x1bc000c7 }, - { 0x502e4, 0x2740002c }, - { 0x5fffc, 0x1cc000c8 }, - { 0x502e8, 0x26c00029 }, - { 0x5fffc, 0x1dc000c9 }, - { 0x502ec, 0x26000027 }, - { 0x5fffc, 0x1ec000cc }, - { 0x502f0, 0x25000024 }, - { 0x5fffc, 0x200000cc }, - { 0x502f4, 0x24800021 }, - { 0x5fffc, 0x210000cd }, - { 0x502f8, 0x23800020 }, - { 0x5fffc, 0x220000ce }, - { 0x502fc, 0x2300001d }, -}; - -static struct mdp_table_entry mdp_downscale_x_table_PT4TOPT6[] = { - { 0x5fffc, 0x740008c }, - { 0x50280, 0x33800088 }, - { 0x5fffc, 0x800008e }, - { 0x50284, 0x33400084 }, - { 0x5fffc, 0x8400092 }, - { 0x50288, 0x33000080 }, - { 0x5fffc, 0x9000094 }, - { 0x5028c, 0x3300007b }, - { 0x5fffc, 0x9c00098 }, - { 0x50290, 0x32400077 }, - { 0x5fffc, 0xa40009b }, - { 0x50294, 0x32000073 }, - { 0x5fffc, 0xb00009d }, - { 0x50298, 0x31c0006f }, - { 0x5fffc, 0xbc000a0 }, - { 0x5029c, 0x3140006b }, - { 0x5fffc, 0xc8000a2 }, - { 0x502a0, 0x31000067 }, - { 0x5fffc, 0xd8000a5 }, - { 0x502a4, 0x30800062 }, - { 0x5fffc, 0xe4000a8 }, - { 0x502a8, 0x2fc0005f }, - { 0x5fffc, 0xec000aa }, - { 0x502ac, 0x2fc0005b }, - { 0x5fffc, 0xf8000ad }, - { 0x502b0, 0x2f400057 }, - { 0x5fffc, 0x108000b0 }, - { 0x502b4, 0x2e400054 }, - { 0x5fffc, 0x114000b2 }, - { 0x502b8, 0x2e000050 }, - { 0x5fffc, 0x124000b4 }, - { 0x502bc, 0x2d80004c }, - { 0x5fffc, 0x130000b6 }, - { 0x502c0, 0x2d000049 }, - { 0x5fffc, 0x140000b8 }, - { 0x502c4, 0x2c800045 }, - { 0x5fffc, 0x150000b9 }, - { 0x502c8, 0x2c000042 }, - { 0x5fffc, 0x15c000bd }, - { 0x502cc, 0x2b40003e }, - { 0x5fffc, 0x16c000bf }, - { 0x502d0, 0x2a80003b }, - { 0x5fffc, 0x17c000bf }, - { 0x502d4, 0x2a000039 }, - { 0x5fffc, 0x188000c2 }, - { 0x502d8, 0x29400036 }, - { 0x5fffc, 0x19c000c4 }, - { 0x502dc, 0x28800032 }, - { 0x5fffc, 0x1ac000c5 }, - { 0x502e0, 0x2800002f }, - { 0x5fffc, 0x1bc000c7 }, - { 0x502e4, 0x2740002c }, - { 0x5fffc, 0x1cc000c8 }, - { 0x502e8, 0x26c00029 }, - { 0x5fffc, 0x1dc000c9 }, - { 0x502ec, 0x26000027 }, - { 0x5fffc, 0x1ec000cc }, - { 0x502f0, 0x25000024 }, - { 0x5fffc, 0x200000cc }, - { 0x502f4, 0x24800021 }, - { 0x5fffc, 0x210000cd }, - { 0x502f8, 0x23800020 }, - { 0x5fffc, 0x220000ce }, - { 0x502fc, 0x2300001d }, -}; - -static struct mdp_table_entry mdp_downscale_x_table_PT6TOPT8[] = { - { 0x5fffc, 0xfe000070 }, - { 0x50280, 0x4bc00068 }, - { 0x5fffc, 0xfe000078 }, - { 0x50284, 0x4bc00060 }, - { 0x5fffc, 0xfe000080 }, - { 0x50288, 0x4b800059 }, - { 0x5fffc, 0xfe000089 }, - { 0x5028c, 0x4b000052 }, - { 0x5fffc, 0xfe400091 }, - { 0x50290, 0x4a80004b }, - { 0x5fffc, 0xfe40009a }, - { 0x50294, 0x4a000044 }, - { 0x5fffc, 0xfe8000a3 }, - { 0x50298, 0x4940003d }, - { 0x5fffc, 0xfec000ac }, - { 0x5029c, 0x48400037 }, - { 0x5fffc, 0xff0000b4 }, - { 0x502a0, 0x47800031 }, - { 0x5fffc, 0xff8000bd }, - { 0x502a4, 0x4640002b }, - { 0x5fffc, 0xc5 }, - { 0x502a8, 0x45000026 }, - { 0x5fffc, 0x8000ce }, - { 0x502ac, 0x43800021 }, - { 0x5fffc, 0x10000d6 }, - { 0x502b0, 0x4240001c }, - { 0x5fffc, 0x18000df }, - { 0x502b4, 0x40800018 }, - { 0x5fffc, 0x24000e6 }, - { 0x502b8, 0x3f000014 }, - { 0x5fffc, 0x30000ee }, - { 0x502bc, 0x3d400010 }, - { 0x5fffc, 0x40000f5 }, - { 0x502c0, 0x3b80000c }, - { 0x5fffc, 0x50000fc }, - { 0x502c4, 0x39800009 }, - { 0x5fffc, 0x6000102 }, - { 0x502c8, 0x37c00006 }, - { 0x5fffc, 0x7000109 }, - { 0x502cc, 0x35800004 }, - { 0x5fffc, 0x840010e }, - { 0x502d0, 0x33800002 }, - { 0x5fffc, 0x9800114 }, - { 0x502d4, 0x31400000 }, - { 0x5fffc, 0xac00119 }, - { 0x502d8, 0x2f4003fe }, - { 0x5fffc, 0xc40011e }, - { 0x502dc, 0x2d0003fc }, - { 0x5fffc, 0xdc00121 }, - { 0x502e0, 0x2b0003fb }, - { 0x5fffc, 0xf400125 }, - { 0x502e4, 0x28c003fa }, - { 0x5fffc, 0x11000128 }, - { 0x502e8, 0x268003f9 }, - { 0x5fffc, 0x12c0012a }, - { 0x502ec, 0x244003f9 }, - { 0x5fffc, 0x1480012c }, - { 0x502f0, 0x224003f8 }, - { 0x5fffc, 0x1640012e }, - { 0x502f4, 0x200003f8 }, - { 0x5fffc, 0x1800012f }, - { 0x502f8, 0x1e0003f8 }, - { 0x5fffc, 0x1a00012f }, - { 0x502fc, 0x1c0003f8 }, -}; - -static struct mdp_table_entry mdp_downscale_x_table_PT8TO1[] = { - { 0x5fffc, 0x0 }, - { 0x50280, 0x7fc00000 }, - { 0x5fffc, 0xff80000d }, - { 0x50284, 0x7ec003f9 }, - { 0x5fffc, 0xfec0001c }, - { 0x50288, 0x7d4003f3 }, - { 0x5fffc, 0xfe40002b }, - { 0x5028c, 0x7b8003ed }, - { 0x5fffc, 0xfd80003c }, - { 0x50290, 0x794003e8 }, - { 0x5fffc, 0xfcc0004d }, - { 0x50294, 0x76c003e4 }, - { 0x5fffc, 0xfc40005f }, - { 0x50298, 0x73c003e0 }, - { 0x5fffc, 0xfb800071 }, - { 0x5029c, 0x708003de }, - { 0x5fffc, 0xfac00085 }, - { 0x502a0, 0x6d0003db }, - { 0x5fffc, 0xfa000098 }, - { 0x502a4, 0x698003d9 }, - { 0x5fffc, 0xf98000ac }, - { 0x502a8, 0x654003d8 }, - { 0x5fffc, 0xf8c000c1 }, - { 0x502ac, 0x610003d7 }, - { 0x5fffc, 0xf84000d5 }, - { 0x502b0, 0x5c8003d7 }, - { 0x5fffc, 0xf7c000e9 }, - { 0x502b4, 0x580003d7 }, - { 0x5fffc, 0xf74000fd }, - { 0x502b8, 0x534003d8 }, - { 0x5fffc, 0xf6c00112 }, - { 0x502bc, 0x4e8003d8 }, - { 0x5fffc, 0xf6800126 }, - { 0x502c0, 0x494003da }, - { 0x5fffc, 0xf600013a }, - { 0x502c4, 0x448003db }, - { 0x5fffc, 0xf600014d }, - { 0x502c8, 0x3f4003dd }, - { 0x5fffc, 0xf5c00160 }, - { 0x502cc, 0x3a4003df }, - { 0x5fffc, 0xf5c00172 }, - { 0x502d0, 0x354003e1 }, - { 0x5fffc, 0xf5c00184 }, - { 0x502d4, 0x304003e3 }, - { 0x5fffc, 0xf6000195 }, - { 0x502d8, 0x2b0003e6 }, - { 0x5fffc, 0xf64001a6 }, - { 0x502dc, 0x260003e8 }, - { 0x5fffc, 0xf6c001b4 }, - { 0x502e0, 0x214003eb }, - { 0x5fffc, 0xf78001c2 }, - { 0x502e4, 0x1c4003ee }, - { 0x5fffc, 0xf80001cf }, - { 0x502e8, 0x17c003f1 }, - { 0x5fffc, 0xf90001db }, - { 0x502ec, 0x134003f3 }, - { 0x5fffc, 0xfa0001e5 }, - { 0x502f0, 0xf0003f6 }, - { 0x5fffc, 0xfb4001ee }, - { 0x502f4, 0xac003f9 }, - { 0x5fffc, 0xfcc001f5 }, - { 0x502f8, 0x70003fb }, - { 0x5fffc, 0xfe4001fb }, - { 0x502fc, 0x34003fe }, -}; - -struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX] = { - [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_x_table_PT2TOPT4, - [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_x_table_PT4TOPT6, - [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_x_table_PT6TOPT8, - [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_x_table_PT8TO1, -}; - -static struct mdp_table_entry mdp_downscale_y_table_PT2TOPT4[] = { - { 0x5fffc, 0x740008c }, - { 0x50300, 0x33800088 }, - { 0x5fffc, 0x800008e }, - { 0x50304, 0x33400084 }, - { 0x5fffc, 0x8400092 }, - { 0x50308, 0x33000080 }, - { 0x5fffc, 0x9000094 }, - { 0x5030c, 0x3300007b }, - { 0x5fffc, 0x9c00098 }, - { 0x50310, 0x32400077 }, - { 0x5fffc, 0xa40009b }, - { 0x50314, 0x32000073 }, - { 0x5fffc, 0xb00009d }, - { 0x50318, 0x31c0006f }, - { 0x5fffc, 0xbc000a0 }, - { 0x5031c, 0x3140006b }, - { 0x5fffc, 0xc8000a2 }, - { 0x50320, 0x31000067 }, - { 0x5fffc, 0xd8000a5 }, - { 0x50324, 0x30800062 }, - { 0x5fffc, 0xe4000a8 }, - { 0x50328, 0x2fc0005f }, - { 0x5fffc, 0xec000aa }, - { 0x5032c, 0x2fc0005b }, - { 0x5fffc, 0xf8000ad }, - { 0x50330, 0x2f400057 }, - { 0x5fffc, 0x108000b0 }, - { 0x50334, 0x2e400054 }, - { 0x5fffc, 0x114000b2 }, - { 0x50338, 0x2e000050 }, - { 0x5fffc, 0x124000b4 }, - { 0x5033c, 0x2d80004c }, - { 0x5fffc, 0x130000b6 }, - { 0x50340, 0x2d000049 }, - { 0x5fffc, 0x140000b8 }, - { 0x50344, 0x2c800045 }, - { 0x5fffc, 0x150000b9 }, - { 0x50348, 0x2c000042 }, - { 0x5fffc, 0x15c000bd }, - { 0x5034c, 0x2b40003e }, - { 0x5fffc, 0x16c000bf }, - { 0x50350, 0x2a80003b }, - { 0x5fffc, 0x17c000bf }, - { 0x50354, 0x2a000039 }, - { 0x5fffc, 0x188000c2 }, - { 0x50358, 0x29400036 }, - { 0x5fffc, 0x19c000c4 }, - { 0x5035c, 0x28800032 }, - { 0x5fffc, 0x1ac000c5 }, - { 0x50360, 0x2800002f }, - { 0x5fffc, 0x1bc000c7 }, - { 0x50364, 0x2740002c }, - { 0x5fffc, 0x1cc000c8 }, - { 0x50368, 0x26c00029 }, - { 0x5fffc, 0x1dc000c9 }, - { 0x5036c, 0x26000027 }, - { 0x5fffc, 0x1ec000cc }, - { 0x50370, 0x25000024 }, - { 0x5fffc, 0x200000cc }, - { 0x50374, 0x24800021 }, - { 0x5fffc, 0x210000cd }, - { 0x50378, 0x23800020 }, - { 0x5fffc, 0x220000ce }, - { 0x5037c, 0x2300001d }, -}; - -static struct mdp_table_entry mdp_downscale_y_table_PT4TOPT6[] = { - { 0x5fffc, 0x740008c }, - { 0x50300, 0x33800088 }, - { 0x5fffc, 0x800008e }, - { 0x50304, 0x33400084 }, - { 0x5fffc, 0x8400092 }, - { 0x50308, 0x33000080 }, - { 0x5fffc, 0x9000094 }, - { 0x5030c, 0x3300007b }, - { 0x5fffc, 0x9c00098 }, - { 0x50310, 0x32400077 }, - { 0x5fffc, 0xa40009b }, - { 0x50314, 0x32000073 }, - { 0x5fffc, 0xb00009d }, - { 0x50318, 0x31c0006f }, - { 0x5fffc, 0xbc000a0 }, - { 0x5031c, 0x3140006b }, - { 0x5fffc, 0xc8000a2 }, - { 0x50320, 0x31000067 }, - { 0x5fffc, 0xd8000a5 }, - { 0x50324, 0x30800062 }, - { 0x5fffc, 0xe4000a8 }, - { 0x50328, 0x2fc0005f }, - { 0x5fffc, 0xec000aa }, - { 0x5032c, 0x2fc0005b }, - { 0x5fffc, 0xf8000ad }, - { 0x50330, 0x2f400057 }, - { 0x5fffc, 0x108000b0 }, - { 0x50334, 0x2e400054 }, - { 0x5fffc, 0x114000b2 }, - { 0x50338, 0x2e000050 }, - { 0x5fffc, 0x124000b4 }, - { 0x5033c, 0x2d80004c }, - { 0x5fffc, 0x130000b6 }, - { 0x50340, 0x2d000049 }, - { 0x5fffc, 0x140000b8 }, - { 0x50344, 0x2c800045 }, - { 0x5fffc, 0x150000b9 }, - { 0x50348, 0x2c000042 }, - { 0x5fffc, 0x15c000bd }, - { 0x5034c, 0x2b40003e }, - { 0x5fffc, 0x16c000bf }, - { 0x50350, 0x2a80003b }, - { 0x5fffc, 0x17c000bf }, - { 0x50354, 0x2a000039 }, - { 0x5fffc, 0x188000c2 }, - { 0x50358, 0x29400036 }, - { 0x5fffc, 0x19c000c4 }, - { 0x5035c, 0x28800032 }, - { 0x5fffc, 0x1ac000c5 }, - { 0x50360, 0x2800002f }, - { 0x5fffc, 0x1bc000c7 }, - { 0x50364, 0x2740002c }, - { 0x5fffc, 0x1cc000c8 }, - { 0x50368, 0x26c00029 }, - { 0x5fffc, 0x1dc000c9 }, - { 0x5036c, 0x26000027 }, - { 0x5fffc, 0x1ec000cc }, - { 0x50370, 0x25000024 }, - { 0x5fffc, 0x200000cc }, - { 0x50374, 0x24800021 }, - { 0x5fffc, 0x210000cd }, - { 0x50378, 0x23800020 }, - { 0x5fffc, 0x220000ce }, - { 0x5037c, 0x2300001d }, -}; - -static struct mdp_table_entry mdp_downscale_y_table_PT6TOPT8[] = { - { 0x5fffc, 0xfe000070 }, - { 0x50300, 0x4bc00068 }, - { 0x5fffc, 0xfe000078 }, - { 0x50304, 0x4bc00060 }, - { 0x5fffc, 0xfe000080 }, - { 0x50308, 0x4b800059 }, - { 0x5fffc, 0xfe000089 }, - { 0x5030c, 0x4b000052 }, - { 0x5fffc, 0xfe400091 }, - { 0x50310, 0x4a80004b }, - { 0x5fffc, 0xfe40009a }, - { 0x50314, 0x4a000044 }, - { 0x5fffc, 0xfe8000a3 }, - { 0x50318, 0x4940003d }, - { 0x5fffc, 0xfec000ac }, - { 0x5031c, 0x48400037 }, - { 0x5fffc, 0xff0000b4 }, - { 0x50320, 0x47800031 }, - { 0x5fffc, 0xff8000bd }, - { 0x50324, 0x4640002b }, - { 0x5fffc, 0xc5 }, - { 0x50328, 0x45000026 }, - { 0x5fffc, 0x8000ce }, - { 0x5032c, 0x43800021 }, - { 0x5fffc, 0x10000d6 }, - { 0x50330, 0x4240001c }, - { 0x5fffc, 0x18000df }, - { 0x50334, 0x40800018 }, - { 0x5fffc, 0x24000e6 }, - { 0x50338, 0x3f000014 }, - { 0x5fffc, 0x30000ee }, - { 0x5033c, 0x3d400010 }, - { 0x5fffc, 0x40000f5 }, - { 0x50340, 0x3b80000c }, - { 0x5fffc, 0x50000fc }, - { 0x50344, 0x39800009 }, - { 0x5fffc, 0x6000102 }, - { 0x50348, 0x37c00006 }, - { 0x5fffc, 0x7000109 }, - { 0x5034c, 0x35800004 }, - { 0x5fffc, 0x840010e }, - { 0x50350, 0x33800002 }, - { 0x5fffc, 0x9800114 }, - { 0x50354, 0x31400000 }, - { 0x5fffc, 0xac00119 }, - { 0x50358, 0x2f4003fe }, - { 0x5fffc, 0xc40011e }, - { 0x5035c, 0x2d0003fc }, - { 0x5fffc, 0xdc00121 }, - { 0x50360, 0x2b0003fb }, - { 0x5fffc, 0xf400125 }, - { 0x50364, 0x28c003fa }, - { 0x5fffc, 0x11000128 }, - { 0x50368, 0x268003f9 }, - { 0x5fffc, 0x12c0012a }, - { 0x5036c, 0x244003f9 }, - { 0x5fffc, 0x1480012c }, - { 0x50370, 0x224003f8 }, - { 0x5fffc, 0x1640012e }, - { 0x50374, 0x200003f8 }, - { 0x5fffc, 0x1800012f }, - { 0x50378, 0x1e0003f8 }, - { 0x5fffc, 0x1a00012f }, - { 0x5037c, 0x1c0003f8 }, -}; - -static struct mdp_table_entry mdp_downscale_y_table_PT8TO1[] = { - { 0x5fffc, 0x0 }, - { 0x50300, 0x7fc00000 }, - { 0x5fffc, 0xff80000d }, - { 0x50304, 0x7ec003f9 }, - { 0x5fffc, 0xfec0001c }, - { 0x50308, 0x7d4003f3 }, - { 0x5fffc, 0xfe40002b }, - { 0x5030c, 0x7b8003ed }, - { 0x5fffc, 0xfd80003c }, - { 0x50310, 0x794003e8 }, - { 0x5fffc, 0xfcc0004d }, - { 0x50314, 0x76c003e4 }, - { 0x5fffc, 0xfc40005f }, - { 0x50318, 0x73c003e0 }, - { 0x5fffc, 0xfb800071 }, - { 0x5031c, 0x708003de }, - { 0x5fffc, 0xfac00085 }, - { 0x50320, 0x6d0003db }, - { 0x5fffc, 0xfa000098 }, - { 0x50324, 0x698003d9 }, - { 0x5fffc, 0xf98000ac }, - { 0x50328, 0x654003d8 }, - { 0x5fffc, 0xf8c000c1 }, - { 0x5032c, 0x610003d7 }, - { 0x5fffc, 0xf84000d5 }, - { 0x50330, 0x5c8003d7 }, - { 0x5fffc, 0xf7c000e9 }, - { 0x50334, 0x580003d7 }, - { 0x5fffc, 0xf74000fd }, - { 0x50338, 0x534003d8 }, - { 0x5fffc, 0xf6c00112 }, - { 0x5033c, 0x4e8003d8 }, - { 0x5fffc, 0xf6800126 }, - { 0x50340, 0x494003da }, - { 0x5fffc, 0xf600013a }, - { 0x50344, 0x448003db }, - { 0x5fffc, 0xf600014d }, - { 0x50348, 0x3f4003dd }, - { 0x5fffc, 0xf5c00160 }, - { 0x5034c, 0x3a4003df }, - { 0x5fffc, 0xf5c00172 }, - { 0x50350, 0x354003e1 }, - { 0x5fffc, 0xf5c00184 }, - { 0x50354, 0x304003e3 }, - { 0x5fffc, 0xf6000195 }, - { 0x50358, 0x2b0003e6 }, - { 0x5fffc, 0xf64001a6 }, - { 0x5035c, 0x260003e8 }, - { 0x5fffc, 0xf6c001b4 }, - { 0x50360, 0x214003eb }, - { 0x5fffc, 0xf78001c2 }, - { 0x50364, 0x1c4003ee }, - { 0x5fffc, 0xf80001cf }, - { 0x50368, 0x17c003f1 }, - { 0x5fffc, 0xf90001db }, - { 0x5036c, 0x134003f3 }, - { 0x5fffc, 0xfa0001e5 }, - { 0x50370, 0xf0003f6 }, - { 0x5fffc, 0xfb4001ee }, - { 0x50374, 0xac003f9 }, - { 0x5fffc, 0xfcc001f5 }, - { 0x50378, 0x70003fb }, - { 0x5fffc, 0xfe4001fb }, - { 0x5037c, 0x34003fe }, -}; - -struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX] = { - [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_y_table_PT2TOPT4, - [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_y_table_PT4TOPT6, - [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_y_table_PT6TOPT8, - [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_y_table_PT8TO1, -}; - -struct mdp_table_entry mdp_gaussian_blur_table[] = { - /* max variance */ - { 0x5fffc, 0x20000080 }, - { 0x50280, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50284, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50288, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5028c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50290, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50294, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50298, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5029c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502a0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502a4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502a8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502ac, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502b0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502b4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502b8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502bc, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502c0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502c4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502c8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502cc, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502d0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502d4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502d8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502dc, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502e0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502e4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502e8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502ec, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502f0, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502f4, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502f8, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x502fc, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50300, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50304, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50308, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5030c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50310, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50314, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50318, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5031c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50320, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50324, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50328, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5032c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50330, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50334, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50338, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5033c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50340, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50344, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50348, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5034c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50350, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50354, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50358, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5035c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50360, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50364, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50368, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5036c, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50370, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50374, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x50378, 0x20000080 }, - { 0x5fffc, 0x20000080 }, - { 0x5037c, 0x20000080 }, -}; diff --git a/drivers/video/fbdev/msm/mdp_scale_tables.h b/drivers/video/fbdev/msm/mdp_scale_tables.h deleted file mode 100644 index 34077b1af603..000000000000 --- a/drivers/video/fbdev/msm/mdp_scale_tables.h +++ /dev/null @@ -1,38 +0,0 @@ -/* drivers/video/msm_fb/mdp_scale_tables.h - * - * Copyright (C) 2007 QUALCOMM Incorporated - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MDP_SCALE_TABLES_H_ -#define _MDP_SCALE_TABLES_H_ - -#include -struct mdp_table_entry { - uint32_t reg; - uint32_t val; -}; - -extern struct mdp_table_entry mdp_upscale_table[64]; - -enum { - MDP_DOWNSCALE_PT2TOPT4, - MDP_DOWNSCALE_PT4TOPT6, - MDP_DOWNSCALE_PT6TOPT8, - MDP_DOWNSCALE_PT8TO1, - MDP_DOWNSCALE_MAX, -}; - -extern struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX]; -extern struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX]; -extern struct mdp_table_entry mdp_gaussian_blur_table[]; - -#endif diff --git a/drivers/video/fbdev/msm/msm_fb.c b/drivers/video/fbdev/msm/msm_fb.c deleted file mode 100644 index 2979d7e72126..000000000000 --- a/drivers/video/fbdev/msm/msm_fb.c +++ /dev/null @@ -1,659 +0,0 @@ -/* drivers/video/msm/msm_fb.c - * - * Core MSM framebuffer driver. - * - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PRINT_FPS 0 -#define PRINT_BLIT_TIME 0 - -#define SLEEPING 0x4 -#define UPDATING 0x3 -#define FULL_UPDATE_DONE 0x2 -#define WAKING 0x1 -#define AWAKE 0x0 - -#define NONE 0 -#define SUSPEND_RESUME 0x1 -#define FPS 0x2 -#define BLIT_TIME 0x4 -#define SHOW_UPDATES 0x8 - -#define DLOG(mask, fmt, args...) \ -do { \ - if (msmfb_debug_mask & mask) \ - printk(KERN_INFO "msmfb: "fmt, ##args); \ -} while (0) - -static int msmfb_debug_mask; -module_param_named(msmfb_debug_mask, msmfb_debug_mask, int, - S_IRUGO | S_IWUSR | S_IWGRP); - -struct mdp_device *mdp; - -struct msmfb_info { - struct fb_info *fb; - struct msm_panel_data *panel; - int xres; - int yres; - unsigned output_format; - unsigned yoffset; - unsigned frame_requested; - unsigned frame_done; - int sleeping; - unsigned update_frame; - struct { - int left; - int top; - int eright; /* exclusive */ - int ebottom; /* exclusive */ - } update_info; - char *black; - - spinlock_t update_lock; - struct mutex panel_init_lock; - wait_queue_head_t frame_wq; - struct work_struct resume_work; - struct msmfb_callback dma_callback; - struct msmfb_callback vsync_callback; - struct hrtimer fake_vsync; - ktime_t vsync_request_time; -}; - -static int msmfb_open(struct fb_info *info, int user) -{ - return 0; -} - -static int msmfb_release(struct fb_info *info, int user) -{ - return 0; -} - -/* Called from dma interrupt handler, must not sleep */ -static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) -{ - unsigned long irq_flags; - struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, - dma_callback); - - spin_lock_irqsave(&msmfb->update_lock, irq_flags); - msmfb->frame_done = msmfb->frame_requested; - if (msmfb->sleeping == UPDATING && - msmfb->frame_done == msmfb->update_frame) { - DLOG(SUSPEND_RESUME, "full update completed\n"); - schedule_work(&msmfb->resume_work); - } - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - wake_up(&msmfb->frame_wq); -} - -static int msmfb_start_dma(struct msmfb_info *msmfb) -{ - uint32_t x, y, w, h; - unsigned addr; - unsigned long irq_flags; - uint32_t yoffset; - s64 time_since_request; - struct msm_panel_data *panel = msmfb->panel; - - spin_lock_irqsave(&msmfb->update_lock, irq_flags); - time_since_request = ktime_to_ns(ktime_sub(ktime_get(), - msmfb->vsync_request_time)); - if (time_since_request > 20 * NSEC_PER_MSEC) { - uint32_t us; - us = do_div(time_since_request, NSEC_PER_MSEC) / NSEC_PER_USEC; - printk(KERN_WARNING "msmfb_start_dma %lld.%03u ms after vsync " - "request\n", time_since_request, us); - } - if (msmfb->frame_done == msmfb->frame_requested) { - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - return -1; - } - if (msmfb->sleeping == SLEEPING) { - DLOG(SUSPEND_RESUME, "tried to start dma while asleep\n"); - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - return -1; - } - x = msmfb->update_info.left; - y = msmfb->update_info.top; - w = msmfb->update_info.eright - x; - h = msmfb->update_info.ebottom - y; - yoffset = msmfb->yoffset; - msmfb->update_info.left = msmfb->xres + 1; - msmfb->update_info.top = msmfb->yres + 1; - msmfb->update_info.eright = 0; - msmfb->update_info.ebottom = 0; - if (unlikely(w > msmfb->xres || h > msmfb->yres || - w == 0 || h == 0)) { - printk(KERN_INFO "invalid update: %d %d %d " - "%d\n", x, y, w, h); - msmfb->frame_done = msmfb->frame_requested; - goto error; - } - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - - addr = ((msmfb->xres * (yoffset + y) + x) * 2); - mdp->dma(mdp, addr + msmfb->fb->fix.smem_start, - msmfb->xres * 2, w, h, x, y, &msmfb->dma_callback, - panel->interface_type); - return 0; -error: - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - /* some clients need to clear their vsync interrupt */ - if (panel->clear_vsync) - panel->clear_vsync(panel); - wake_up(&msmfb->frame_wq); - return 0; -} - -/* Called from esync interrupt handler, must not sleep */ -static void msmfb_handle_vsync_interrupt(struct msmfb_callback *callback) -{ - struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, - vsync_callback); - msmfb_start_dma(msmfb); -} - -static enum hrtimer_restart msmfb_fake_vsync(struct hrtimer *timer) -{ - struct msmfb_info *msmfb = container_of(timer, struct msmfb_info, - fake_vsync); - msmfb_start_dma(msmfb); - return HRTIMER_NORESTART; -} - -static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top, - uint32_t eright, uint32_t ebottom, - uint32_t yoffset, int pan_display) -{ - struct msmfb_info *msmfb = info->par; - struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; - int sleeping; - int retry = 1; - - DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n", - left, top, eright, ebottom, yoffset, pan_display); -restart: - spin_lock_irqsave(&msmfb->update_lock, irq_flags); - - /* if we are sleeping, on a pan_display wait 10ms (to throttle back - * drawing otherwise return */ - if (msmfb->sleeping == SLEEPING) { - DLOG(SUSPEND_RESUME, "drawing while asleep\n"); - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - if (pan_display) - wait_event_interruptible_timeout(msmfb->frame_wq, - msmfb->sleeping != SLEEPING, HZ/10); - return; - } - - sleeping = msmfb->sleeping; - /* on a full update, if the last frame has not completed, wait for it */ - if ((pan_display && msmfb->frame_requested != msmfb->frame_done) || - sleeping == UPDATING) { - int ret; - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - ret = wait_event_interruptible_timeout(msmfb->frame_wq, - msmfb->frame_done == msmfb->frame_requested && - msmfb->sleeping != UPDATING, 5 * HZ); - if (ret <= 0 && (msmfb->frame_requested != msmfb->frame_done || - msmfb->sleeping == UPDATING)) { - if (retry && panel->request_vsync && - (sleeping == AWAKE)) { - panel->request_vsync(panel, - &msmfb->vsync_callback); - retry = 0; - printk(KERN_WARNING "msmfb_pan_display timeout " - "rerequest vsync\n"); - } else { - printk(KERN_WARNING "msmfb_pan_display timeout " - "waiting for frame start, %d %d\n", - msmfb->frame_requested, - msmfb->frame_done); - return; - } - } - goto restart; - } - - - msmfb->frame_requested++; - /* if necessary, update the y offset, if this is the - * first full update on resume, set the sleeping state */ - if (pan_display) { - msmfb->yoffset = yoffset; - if (left == 0 && top == 0 && eright == info->var.xres && - ebottom == info->var.yres) { - if (sleeping == WAKING) { - msmfb->update_frame = msmfb->frame_requested; - DLOG(SUSPEND_RESUME, "full update starting\n"); - msmfb->sleeping = UPDATING; - } - } - } - - /* set the update request */ - if (left < msmfb->update_info.left) - msmfb->update_info.left = left; - if (top < msmfb->update_info.top) - msmfb->update_info.top = top; - if (eright > msmfb->update_info.eright) - msmfb->update_info.eright = eright; - if (ebottom > msmfb->update_info.ebottom) - msmfb->update_info.ebottom = ebottom; - DLOG(SHOW_UPDATES, "update queued %d %d %d %d %d\n", - msmfb->update_info.left, msmfb->update_info.top, - msmfb->update_info.eright, msmfb->update_info.ebottom, - msmfb->yoffset); - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - - /* if the panel is all the way on wait for vsync, otherwise sleep - * for 16 ms (long enough for the dma to panel) and then begin dma */ - msmfb->vsync_request_time = ktime_get(); - if (panel->request_vsync && (sleeping == AWAKE)) { - panel->request_vsync(panel, &msmfb->vsync_callback); - } else { - if (!hrtimer_active(&msmfb->fake_vsync)) { - hrtimer_start(&msmfb->fake_vsync, - ktime_set(0, NSEC_PER_SEC/60), - HRTIMER_MODE_REL); - } - } -} - -static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top, - uint32_t eright, uint32_t ebottom) -{ - msmfb_pan_update(info, left, top, eright, ebottom, 0, 0); -} - -static void power_on_panel(struct work_struct *work) -{ - struct msmfb_info *msmfb = - container_of(work, struct msmfb_info, resume_work); - struct msm_panel_data *panel = msmfb->panel; - unsigned long irq_flags; - - mutex_lock(&msmfb->panel_init_lock); - DLOG(SUSPEND_RESUME, "turning on panel\n"); - if (msmfb->sleeping == UPDATING) { - if (panel->unblank(panel)) { - printk(KERN_INFO "msmfb: panel unblank failed," - "not starting drawing\n"); - goto error; - } - spin_lock_irqsave(&msmfb->update_lock, irq_flags); - msmfb->sleeping = AWAKE; - wake_up(&msmfb->frame_wq); - spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - } -error: - mutex_unlock(&msmfb->panel_init_lock); -} - - -static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - if ((var->xres != info->var.xres) || - (var->yres != info->var.yres) || - (var->xres_virtual != info->var.xres_virtual) || - (var->yres_virtual != info->var.yres_virtual) || - (var->xoffset != info->var.xoffset) || - (var->bits_per_pixel != info->var.bits_per_pixel) || - (var->grayscale != info->var.grayscale)) - return -EINVAL; - return 0; -} - -int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct msmfb_info *msmfb = info->par; - struct msm_panel_data *panel = msmfb->panel; - - /* "UPDT" */ - if ((panel->caps & MSMFB_CAP_PARTIAL_UPDATES) && - (var->reserved[0] == 0x54445055)) { - msmfb_pan_update(info, var->reserved[1] & 0xffff, - var->reserved[1] >> 16, - var->reserved[2] & 0xffff, - var->reserved[2] >> 16, var->yoffset, 1); - } else { - msmfb_pan_update(info, 0, 0, info->var.xres, info->var.yres, - var->yoffset, 1); - } - return 0; -} - -static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) -{ - cfb_fillrect(p, rect); - msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width, - rect->dy + rect->height); -} - -static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) -{ - cfb_copyarea(p, area); - msmfb_update(p, area->dx, area->dy, area->dx + area->width, - area->dy + area->height); -} - -static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image) -{ - cfb_imageblit(p, image); - msmfb_update(p, image->dx, image->dy, image->dx + image->width, - image->dy + image->height); -} - - -static int msmfb_blit(struct fb_info *info, - void __user *p) -{ - struct mdp_blit_req req; - struct mdp_blit_req_list req_list; - int i; - int ret; - - if (copy_from_user(&req_list, p, sizeof(req_list))) - return -EFAULT; - - for (i = 0; i < req_list.count; i++) { - struct mdp_blit_req_list *list = - (struct mdp_blit_req_list *)p; - if (copy_from_user(&req, &list->req[i], sizeof(req))) - return -EFAULT; - ret = mdp->blit(mdp, info, &req); - if (ret) - return ret; - } - return 0; -} - - -DEFINE_MUTEX(mdp_ppp_lock); - -static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int ret; - - switch (cmd) { - case MSMFB_GRP_DISP: - mdp->set_grp_disp(mdp, arg); - break; - case MSMFB_BLIT: - ret = msmfb_blit(p, argp); - if (ret) - return ret; - break; - default: - printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd); - return -EINVAL; - } - return 0; -} - -static struct fb_ops msmfb_ops = { - .owner = THIS_MODULE, - .fb_open = msmfb_open, - .fb_release = msmfb_release, - .fb_check_var = msmfb_check_var, - .fb_pan_display = msmfb_pan_display, - .fb_fillrect = msmfb_fillrect, - .fb_copyarea = msmfb_copyarea, - .fb_imageblit = msmfb_imageblit, - .fb_ioctl = msmfb_ioctl, -}; - -static unsigned PP[16]; - - - -#define BITS_PER_PIXEL 16 - -static void setup_fb_info(struct msmfb_info *msmfb) -{ - struct fb_info *fb_info = msmfb->fb; - int r; - - /* finish setting up the fb_info struct */ - strncpy(fb_info->fix.id, "msmfb", 16); - fb_info->fix.ypanstep = 1; - - fb_info->fbops = &msmfb_ops; - fb_info->flags = FBINFO_DEFAULT; - - fb_info->fix.type = FB_TYPE_PACKED_PIXELS; - fb_info->fix.visual = FB_VISUAL_TRUECOLOR; - fb_info->fix.line_length = msmfb->xres * 2; - - fb_info->var.xres = msmfb->xres; - fb_info->var.yres = msmfb->yres; - fb_info->var.width = msmfb->panel->fb_data->width; - fb_info->var.height = msmfb->panel->fb_data->height; - fb_info->var.xres_virtual = msmfb->xres; - fb_info->var.yres_virtual = msmfb->yres * 2; - fb_info->var.bits_per_pixel = BITS_PER_PIXEL; - fb_info->var.accel_flags = 0; - - fb_info->var.yoffset = 0; - - if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) { - /* - * Set the param in the fixed screen, so userspace can't - * change it. This will be used to check for the - * capability. - */ - fb_info->fix.reserved[0] = 0x5444; - fb_info->fix.reserved[1] = 0x5055; - - /* - * This preloads the value so that if userspace doesn't - * change it, it will be a full update - */ - fb_info->var.reserved[0] = 0x54445055; - fb_info->var.reserved[1] = 0; - fb_info->var.reserved[2] = (uint16_t)msmfb->xres | - ((uint32_t)msmfb->yres << 16); - } - - fb_info->var.red.offset = 11; - fb_info->var.red.length = 5; - fb_info->var.red.msb_right = 0; - fb_info->var.green.offset = 5; - fb_info->var.green.length = 6; - fb_info->var.green.msb_right = 0; - fb_info->var.blue.offset = 0; - fb_info->var.blue.length = 5; - fb_info->var.blue.msb_right = 0; - - r = fb_alloc_cmap(&fb_info->cmap, 16, 0); - fb_info->pseudo_palette = PP; - - PP[0] = 0; - for (r = 1; r < 16; r++) - PP[r] = 0xffffffff; -} - -static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev) -{ - struct fb_info *fb = msmfb->fb; - struct resource *resource; - unsigned long size = msmfb->xres * msmfb->yres * - (BITS_PER_PIXEL >> 3) * 2; - unsigned char *fbram; - - /* board file might have attached a resource describing an fb */ - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) - return -EINVAL; - - /* check the resource is large enough to fit the fb */ - if (resource->end - resource->start < size) { - printk(KERN_ERR "allocated resource is too small for " - "fb\n"); - return -ENOMEM; - } - fb->fix.smem_start = resource->start; - fb->fix.smem_len = resource_size(resource); - fbram = ioremap(resource->start, resource_size(resource)); - if (fbram == NULL) { - printk(KERN_ERR "msmfb: cannot allocate fbram!\n"); - return -ENOMEM; - } - fb->screen_base = fbram; - return 0; -} - -static int msmfb_probe(struct platform_device *pdev) -{ - struct fb_info *fb; - struct msmfb_info *msmfb; - struct msm_panel_data *panel = pdev->dev.platform_data; - int ret; - - if (!panel) { - pr_err("msmfb_probe: no platform data\n"); - return -EINVAL; - } - if (!panel->fb_data) { - pr_err("msmfb_probe: no fb_data\n"); - return -EINVAL; - } - - fb = framebuffer_alloc(sizeof(struct msmfb_info), &pdev->dev); - if (!fb) - return -ENOMEM; - msmfb = fb->par; - msmfb->fb = fb; - msmfb->panel = panel; - msmfb->xres = panel->fb_data->xres; - msmfb->yres = panel->fb_data->yres; - - ret = setup_fbmem(msmfb, pdev); - if (ret) - goto error_setup_fbmem; - - setup_fb_info(msmfb); - - spin_lock_init(&msmfb->update_lock); - mutex_init(&msmfb->panel_init_lock); - init_waitqueue_head(&msmfb->frame_wq); - INIT_WORK(&msmfb->resume_work, power_on_panel); - msmfb->black = devm_kzalloc(&pdev->dev, - msmfb->fb->var.bits_per_pixel*msmfb->xres, - GFP_KERNEL); - if (!msmfb->black) { - ret = -ENOMEM; - goto error_register_framebuffer; - } - - printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n", - msmfb->xres, msmfb->yres); - - msmfb->dma_callback.func = msmfb_handle_dma_interrupt; - msmfb->vsync_callback.func = msmfb_handle_vsync_interrupt; - hrtimer_init(&msmfb->fake_vsync, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - - - msmfb->fake_vsync.function = msmfb_fake_vsync; - - ret = register_framebuffer(fb); - if (ret) - goto error_register_framebuffer; - - msmfb->sleeping = WAKING; - - platform_set_drvdata(pdev, msmfb); - - return 0; - -error_register_framebuffer: - iounmap(fb->screen_base); -error_setup_fbmem: - framebuffer_release(msmfb->fb); - return ret; -} - -static int msmfb_remove(struct platform_device *pdev) -{ - struct msmfb_info *msmfb; - - msmfb = platform_get_drvdata(pdev); - - unregister_framebuffer(msmfb->fb); - iounmap(msmfb->fb->screen_base); - framebuffer_release(msmfb->fb); - - return 0; -} - -static struct platform_driver msm_panel_driver = { - /* need to write remove */ - .probe = msmfb_probe, - .remove = msmfb_remove, - .driver = {.name = "msm_panel"}, -}; - - -static int msmfb_add_mdp_device(struct device *dev, - struct class_interface *class_intf) -{ - /* might need locking if mulitple mdp devices */ - if (mdp) - return 0; - mdp = container_of(dev, struct mdp_device, dev); - return platform_driver_register(&msm_panel_driver); -} - -static void msmfb_remove_mdp_device(struct device *dev, - struct class_interface *class_intf) -{ - /* might need locking if mulitple mdp devices */ - if (dev != &mdp->dev) - return; - platform_driver_unregister(&msm_panel_driver); - mdp = NULL; -} - -static struct class_interface msm_fb_interface = { - .add_dev = &msmfb_add_mdp_device, - .remove_dev = &msmfb_remove_mdp_device, -}; - -static int __init msmfb_init(void) -{ - return register_mdp_client(&msm_fb_interface); -} - -module_init(msmfb_init); diff --git a/include/linux/platform_data/video-msm_fb.h b/include/linux/platform_data/video-msm_fb.h deleted file mode 100644 index 31449be3eadb..000000000000 --- a/include/linux/platform_data/video-msm_fb.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Internal shared definitions for various MSM framebuffer parts. - * - * Copyright (C) 2007 Google Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MSM_FB_H_ -#define _MSM_FB_H_ - -#include - -struct mddi_info; - -struct msm_fb_data { - int xres; /* x resolution in pixels */ - int yres; /* y resolution in pixels */ - int width; /* disply width in mm */ - int height; /* display height in mm */ - unsigned output_format; -}; - -struct msmfb_callback { - void (*func)(struct msmfb_callback *); -}; - -enum { - MSM_MDDI_PMDH_INTERFACE, - MSM_MDDI_EMDH_INTERFACE, - MSM_EBI2_INTERFACE, -}; - -#define MSMFB_CAP_PARTIAL_UPDATES (1 << 0) - -struct msm_panel_data { - /* turns off the fb memory */ - int (*suspend)(struct msm_panel_data *); - /* turns on the fb memory */ - int (*resume)(struct msm_panel_data *); - /* turns off the panel */ - int (*blank)(struct msm_panel_data *); - /* turns on the panel */ - int (*unblank)(struct msm_panel_data *); - void (*wait_vsync)(struct msm_panel_data *); - void (*request_vsync)(struct msm_panel_data *, struct msmfb_callback *); - void (*clear_vsync)(struct msm_panel_data *); - /* from the enum above */ - unsigned interface_type; - /* data to be passed to the fb driver */ - struct msm_fb_data *fb_data; - - /* capabilities supported by the panel */ - uint32_t caps; -}; - -struct msm_mddi_client_data { - void (*suspend)(struct msm_mddi_client_data *); - void (*resume)(struct msm_mddi_client_data *); - void (*activate_link)(struct msm_mddi_client_data *); - void (*remote_write)(struct msm_mddi_client_data *, uint32_t val, - uint32_t reg); - uint32_t (*remote_read)(struct msm_mddi_client_data *, uint32_t reg); - void (*auto_hibernate)(struct msm_mddi_client_data *, int); - /* custom data that needs to be passed from the board file to a - * particular client */ - void *private_client_data; - struct resource *fb_resource; - /* from the list above */ - unsigned interface_type; -}; - -struct msm_mddi_platform_data { - unsigned int clk_rate; - void (*power_client)(struct msm_mddi_client_data *, int on); - - /* fixup the mfr name, product id */ - void (*fixup)(uint16_t *mfr_name, uint16_t *product_id); - - struct resource *fb_resource; /*optional*/ - /* number of clients in the list that follows */ - int num_clients; - /* array of client information of clients */ - struct { - unsigned product_id; /* mfr id in top 16 bits, product id - * in lower 16 bits - */ - char *name; /* the device name will be the platform - * device name registered for the client, - * it should match the name of the associated - * driver - */ - unsigned id; /* id for mddi client device node, will also - * be used as device id of panel devices, if - * the client device will have multiple panels - * space must be left here for them - */ - void *client_data; /* required private client data */ - unsigned int clk_rate; /* optional: if the client requires a - * different mddi clk rate - */ - } client_platform_data[]; -}; - -struct mdp_blit_req; -struct fb_info; -struct mdp_device { - struct device dev; - void (*dma)(struct mdp_device *mpd, uint32_t addr, - uint32_t stride, uint32_t w, uint32_t h, uint32_t x, - uint32_t y, struct msmfb_callback *callback, int interface); - void (*dma_wait)(struct mdp_device *mdp); - int (*blit)(struct mdp_device *mdp, struct fb_info *fb, - struct mdp_blit_req *req); - void (*set_grp_disp)(struct mdp_device *mdp, uint32_t disp_id); -}; - -struct class_interface; -int register_mdp_client(struct class_interface *class_intf); - -/**** private client data structs go below this line ***/ - -struct msm_mddi_bridge_platform_data { - /* from board file */ - int (*init)(struct msm_mddi_bridge_platform_data *, - struct msm_mddi_client_data *); - int (*uninit)(struct msm_mddi_bridge_platform_data *, - struct msm_mddi_client_data *); - /* passed to panel for use by the fb driver */ - int (*blank)(struct msm_mddi_bridge_platform_data *, - struct msm_mddi_client_data *); - int (*unblank)(struct msm_mddi_bridge_platform_data *, - struct msm_mddi_client_data *); - struct msm_fb_data fb_data; -}; - - - -#endif -- cgit v1.2.3-71-gd317 From 2ddf3a792218cddd30140b1f8b32cb6e2d67921f Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Sun, 31 May 2015 02:18:24 +0200 Subject: MIPS: ath79: Add OF support to the GPIO driver Replace the simple GPIO chip registration by a platform driver and make ath79_gpio_init() just register the device. Signed-off-by: Alban Bedel Cc: linux-mips@linux-mips.org Signed-off-by: Ralf Baechle --- arch/mips/ath79/dev-common.c | 51 +++++++++++++++++++++ arch/mips/ath79/gpio.c | 79 +++++++++++++++++++++++--------- include/linux/platform_data/gpio-ath79.h | 19 ++++++++ 3 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 include/linux/platform_data/gpio-ath79.h (limited to 'include/linux/platform_data') diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c index 516225d207ee..9d0172a4dc69 100644 --- a/arch/mips/ath79/dev-common.c +++ b/arch/mips/ath79/dev-common.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -106,3 +107,53 @@ void __init ath79_register_wdt(void) platform_device_register_simple("ath79-wdt", -1, &res, 1); } + +static struct ath79_gpio_platform_data ath79_gpio_pdata; + +static struct resource ath79_gpio_resources[] = { + { + .flags = IORESOURCE_MEM, + .start = AR71XX_GPIO_BASE, + .end = AR71XX_GPIO_BASE + AR71XX_GPIO_SIZE - 1, + }, + { + .start = ATH79_MISC_IRQ(2), + .end = ATH79_MISC_IRQ(2), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ath79_gpio_device = { + .name = "ath79-gpio", + .id = -1, + .resource = ath79_gpio_resources, + .num_resources = ARRAY_SIZE(ath79_gpio_resources), + .dev = { + .platform_data = &ath79_gpio_pdata + }, +}; + +void __init ath79_gpio_init(void) +{ + if (soc_is_ar71xx()) { + ath79_gpio_pdata.ngpios = AR71XX_GPIO_COUNT; + } else if (soc_is_ar7240()) { + ath79_gpio_pdata.ngpios = AR7240_GPIO_COUNT; + } else if (soc_is_ar7241() || soc_is_ar7242()) { + ath79_gpio_pdata.ngpios = AR7241_GPIO_COUNT; + } else if (soc_is_ar913x()) { + ath79_gpio_pdata.ngpios = AR913X_GPIO_COUNT; + } else if (soc_is_ar933x()) { + ath79_gpio_pdata.ngpios = AR933X_GPIO_COUNT; + } else if (soc_is_ar934x()) { + ath79_gpio_pdata.ngpios = AR934X_GPIO_COUNT; + ath79_gpio_pdata.oe_inverted = 1; + } else if (soc_is_qca955x()) { + ath79_gpio_pdata.ngpios = QCA955X_GPIO_COUNT; + ath79_gpio_pdata.oe_inverted = 1; + } else { + BUG(); + } + + platform_device_register(&ath79_gpio_device); +} diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index 8d025b028bb1..f59ccb26520a 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -20,13 +20,15 @@ #include #include #include +#include +#include #include #include #include "common.h" static void __iomem *ath79_gpio_base; -static unsigned long ath79_gpio_count; +static u32 ath79_gpio_count; static DEFINE_SPINLOCK(ath79_gpio_lock); static void __ath79_gpio_set_value(unsigned gpio, int value) @@ -178,39 +180,72 @@ void ath79_gpio_function_disable(u32 mask) ath79_gpio_function_setup(0, mask); } -void __init ath79_gpio_init(void) +static const struct of_device_id ath79_gpio_of_match[] = { + { .compatible = "qca,ar7100-gpio" }, + { .compatible = "qca,ar9340-gpio" }, + {}, +}; + +static int ath79_gpio_probe(struct platform_device *pdev) { + struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + bool oe_inverted; int err; - if (soc_is_ar71xx()) - ath79_gpio_count = AR71XX_GPIO_COUNT; - else if (soc_is_ar7240()) - ath79_gpio_count = AR7240_GPIO_COUNT; - else if (soc_is_ar7241() || soc_is_ar7242()) - ath79_gpio_count = AR7241_GPIO_COUNT; - else if (soc_is_ar913x()) - ath79_gpio_count = AR913X_GPIO_COUNT; - else if (soc_is_ar933x()) - ath79_gpio_count = AR933X_GPIO_COUNT; - else if (soc_is_ar934x()) - ath79_gpio_count = AR934X_GPIO_COUNT; - else if (soc_is_qca955x()) - ath79_gpio_count = QCA955X_GPIO_COUNT; - else - BUG(); + if (np) { + err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); + if (err) { + dev_err(&pdev->dev, "ngpios property is not valid\n"); + return err; + } + if (ath79_gpio_count >= 32) { + dev_err(&pdev->dev, "ngpios must be less than 32\n"); + return -EINVAL; + } + oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); + } else if (pdata) { + ath79_gpio_count = pdata->ngpios; + oe_inverted = pdata->oe_inverted; + } else { + dev_err(&pdev->dev, "No DT node or platform data found\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ath79_gpio_base = devm_ioremap_nocache( + &pdev->dev, res->start, resource_size(res)); + if (!ath79_gpio_base) + return -ENOMEM; - ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); + ath79_gpio_chip.dev = &pdev->dev; ath79_gpio_chip.ngpio = ath79_gpio_count; - if (soc_is_ar934x() || soc_is_qca955x()) { + if (oe_inverted) { ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; } err = gpiochip_add(&ath79_gpio_chip); - if (err) - panic("cannot add AR71xx GPIO chip, error=%d", err); + if (err) { + dev_err(&pdev->dev, + "cannot add AR71xx GPIO chip, error=%d", err); + return err; + } + + return 0; } +static struct platform_driver ath79_gpio_driver = { + .driver = { + .name = "ath79-gpio", + .of_match_table = ath79_gpio_of_match, + }, + .probe = ath79_gpio_probe, +}; + +module_platform_driver(ath79_gpio_driver); + int gpio_get_value(unsigned gpio) { if (gpio < ath79_gpio_count) diff --git a/include/linux/platform_data/gpio-ath79.h b/include/linux/platform_data/gpio-ath79.h new file mode 100644 index 000000000000..88b0db7bee74 --- /dev/null +++ b/include/linux/platform_data/gpio-ath79.h @@ -0,0 +1,19 @@ +/* + * Atheros AR7XXX/AR9XXX GPIO controller platform data + * + * Copyright (C) 2015 Alban Bedel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_PLATFORM_DATA_GPIO_ATH79_H +#define __LINUX_PLATFORM_DATA_GPIO_ATH79_H + +struct ath79_gpio_platform_data { + unsigned ngpios; + bool oe_inverted; +}; + +#endif -- cgit v1.2.3-71-gd317