116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Copyright (C) 2012 Texas Instruments 316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Author: Rob Clark <robdclark@gmail.com> 416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * This program is free software; you can redistribute it and/or modify it 616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * under the terms of the GNU General Public License version 2 as published by 716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * the Free Software Foundation. 816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 1016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * more details. 1316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 1416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * You should have received a copy of the GNU General Public License along with 1516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 1616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 1716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 1816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* LCDC DRM driver, based on da8xx-fb */ 1916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 2016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include "tilcdc_drv.h" 2116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include "tilcdc_regs.h" 2216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include "tilcdc_tfp410.h" 236e8de0bd6a51fdeebd5d975c4fcc426f730b339bRob Clark#include "tilcdc_slave.h" 240d4bbaf9f3e5b9f52150ddc5a4ee8b0ab83a440bRob Clark#include "tilcdc_panel.h" 2516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 2616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include "drm_fb_helper.h" 2716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 2816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic LIST_HEAD(module_list); 2939de6194131c155901f96686a063212656d80c2eDarren Etheridgestatic bool slave_probing; 3016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 3116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkvoid tilcdc_module_init(struct tilcdc_module *mod, const char *name, 3216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark const struct tilcdc_module_ops *funcs) 3316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 3416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod->name = name; 3516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod->funcs = funcs; 3616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark INIT_LIST_HEAD(&mod->list); 3716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark list_add(&mod->list, &module_list); 3816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 3916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 4016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkvoid tilcdc_module_cleanup(struct tilcdc_module *mod) 4116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 4216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark list_del(&mod->list); 4316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 4416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 4539de6194131c155901f96686a063212656d80c2eDarren Etheridgevoid tilcdc_slave_probedefer(bool defered) 4639de6194131c155901f96686a063212656d80c2eDarren Etheridge{ 4739de6194131c155901f96686a063212656d80c2eDarren Etheridge slave_probing = defered; 4839de6194131c155901f96686a063212656d80c2eDarren Etheridge} 4939de6194131c155901f96686a063212656d80c2eDarren Etheridge 5016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct of_device_id tilcdc_of_match[]; 5116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 5216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, 5316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) 5416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 5516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return drm_fb_cma_create(dev, file_priv, mode_cmd); 5616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 5716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 5816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_fb_output_poll_changed(struct drm_device *dev) 5916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 6016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 6116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->fbdev) 6216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_fbdev_cma_hotplug_event(priv->fbdev); 6316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 6416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 6516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct drm_mode_config_funcs mode_config_funcs = { 6616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .fb_create = tilcdc_fb_create, 6716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .output_poll_changed = tilcdc_fb_output_poll_changed, 6816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 6916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 7016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int modeset_init(struct drm_device *dev) 7116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 7216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 7316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_module *mod; 7416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 7516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_mode_config_init(dev); 7616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 7716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->crtc = tilcdc_crtc_create(dev); 7816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 7916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark list_for_each_entry(mod, &module_list, list) { 8016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DBG("loading module: %s", mod->name); 8116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod->funcs->modeset_init(mod, dev); 8216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 8316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 849e48854c58ca9a0f39e716dcb18247bfc21e2022Sachin Kamat if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { 8516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* oh nos! */ 8616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "no encoders/connectors found\n"); 87b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia drm_mode_config_cleanup(dev); 8816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENXIO; 8916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 9016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 9116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.min_width = 0; 9216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.min_height = 0; 9316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc); 9416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.max_height = 2048; 9516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.funcs = &mode_config_funcs; 9616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 9716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 9816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 9916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 10016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_CPU_FREQ 10116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int cpufreq_transition(struct notifier_block *nb, 10216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark unsigned long val, void *data) 10316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 10416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = container_of(nb, 10516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private, freq_transition); 10616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (val == CPUFREQ_POSTCHANGE) { 10716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) { 10816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->lcd_fck_rate = clk_get_rate(priv->clk); 10916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_crtc_update_clk(priv->crtc); 11016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 11116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 11216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 11316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 11416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 11516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 11616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 11716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 11816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * DRM operations: 11916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 12016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 12116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_unload(struct drm_device *dev) 12216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 12316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 12416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 1253a49012224ca9016658a831a327ff6a7fe5bb4f9Guido Martínez drm_fbdev_cma_fini(priv->fbdev); 12616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_kms_helper_poll_fini(dev); 12716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_mode_config_cleanup(dev); 12816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_vblank_cleanup(dev); 12916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 13016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_get_sync(dev->dev); 13116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_irq_uninstall(dev); 13216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_put_sync(dev->dev); 13316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 13416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_CPU_FREQ 13516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark cpufreq_unregister_notifier(&priv->freq_transition, 13616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark CPUFREQ_TRANSITION_NOTIFIER); 13716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 13816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 13916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->clk) 14016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark clk_put(priv->clk); 14116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->mmio) 14316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark iounmap(priv->mmio); 14416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark flush_workqueue(priv->wq); 14616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark destroy_workqueue(priv->wq); 14716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->dev_private = NULL; 14916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_disable(dev->dev); 15116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark kfree(priv); 15316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 15516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 15616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_load(struct drm_device *dev, unsigned long flags) 15816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 15916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct platform_device *pdev = dev->platformdev; 16016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct device_node *node = pdev->dev.of_node; 16116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv; 162dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot struct tilcdc_module *mod; 16316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct resource *res; 164dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot u32 bpp = 0; 16516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret; 16616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 16716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv = kzalloc(sizeof(*priv), GFP_KERNEL); 16816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!priv) { 16916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to allocate private data\n"); 17016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENOMEM; 17116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 17216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 17316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->dev_private = priv; 17416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 17516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->wq = alloc_ordered_workqueue("tilcdc", 0); 176b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia if (!priv->wq) { 177b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia ret = -ENOMEM; 178b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_free_priv; 179b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia } 18016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 18116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 18216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!res) { 18316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to get memory resource\n"); 18416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = -EINVAL; 185b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_free_wq; 18616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 18716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 18816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->mmio = ioremap_nocache(res->start, resource_size(res)); 18916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!priv->mmio) { 19016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to ioremap\n"); 19116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = -ENOMEM; 192b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_free_wq; 19316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 19416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 19516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->clk = clk_get(dev->dev, "fck"); 19616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (IS_ERR(priv->clk)) { 19716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to get functional clock\n"); 19816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = -ENODEV; 199b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_iounmap; 20016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 20116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 20216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); 20316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (IS_ERR(priv->clk)) { 20416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to get display clock\n"); 20516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = -ENODEV; 206b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_put_clk; 20716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 20816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 20916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_CPU_FREQ 21016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->lcd_fck_rate = clk_get_rate(priv->clk); 21116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->freq_transition.notifier_call = cpufreq_transition; 21216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = cpufreq_register_notifier(&priv->freq_transition, 21316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark CPUFREQ_TRANSITION_NOTIFIER); 21416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret) { 21516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to register cpufreq notifier\n"); 216b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_put_disp_clk; 21716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 21816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 21916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 22016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) 2214e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH; 2224e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge 2234e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge DBG("Maximum Bandwidth Value %d", priv->max_bandwidth); 2244e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge 2254e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge if (of_property_read_u32(node, "ti,max-width", &priv->max_width)) 2264e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge priv->max_width = TILCDC_DEFAULT_MAX_WIDTH; 2274e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge 2284e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width); 2294e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge 2304e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge if (of_property_read_u32(node, "ti,max-pixelclock", 2314e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge &priv->max_pixelclock)) 2324e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK; 2334e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge 2344e5643468715260209e42b715e8cd9643456d2bdDarren Etheridge DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); 23516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 23616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_enable(dev->dev); 23716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 23816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* Determine LCD IP Version */ 23916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_get_sync(dev->dev); 24016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark switch (tilcdc_read(dev, LCDC_PID_REG)) { 24116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark case 0x4c100102: 24216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->rev = 1; 24316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark break; 24416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark case 0x4f200800: 24516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark case 0x4f201000: 24616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->rev = 2; 24716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark break; 24816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark default: 24916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_warn(dev->dev, "Unknown PID Reg value 0x%08x, " 25016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark "defaulting to LCD revision 1\n", 25116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_read(dev, LCDC_PID_REG)); 25216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->rev = 1; 25316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark break; 25416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 25516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 25616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_put_sync(dev->dev); 25716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 25816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = modeset_init(dev); 25916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret < 0) { 26016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to initialize mode setting\n"); 261b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_cpufreq_unregister; 26216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 26316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 26416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = drm_vblank_init(dev, 1); 26516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret < 0) { 26616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to initialize vblank\n"); 267b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_mode_config_cleanup; 26816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 26916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 27016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_get_sync(dev->dev); 271bb0f1b5c1695b4399cfd2359c114ae63edbb3ad8Daniel Vetter ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); 27216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_put_sync(dev->dev); 27316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret < 0) { 27416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "failed to install IRQ handler\n"); 275b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_vblank_cleanup; 27616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 27716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 27816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark platform_set_drvdata(pdev, dev); 27916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 280dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot 281dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot list_for_each_entry(mod, &module_list, list) { 282dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); 283dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot bpp = mod->preferred_bpp; 284dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot if (bpp > 0) 285dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot break; 286dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot } 287dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot 288dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot priv->fbdev = drm_fbdev_cma_init(dev, bpp, 28916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.num_crtc, 29016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev->mode_config.num_connector); 291b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia if (IS_ERR(priv->fbdev)) { 292b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia ret = PTR_ERR(priv->fbdev); 293b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia goto fail_irq_uninstall; 294b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia } 29516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 29616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_kms_helper_poll_init(dev); 29716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 29816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 29916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 300b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_irq_uninstall: 301b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia pm_runtime_get_sync(dev->dev); 302b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia drm_irq_uninstall(dev); 303b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia pm_runtime_put_sync(dev->dev); 304b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 305b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_vblank_cleanup: 306b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia drm_vblank_cleanup(dev); 307b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 308b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_mode_config_cleanup: 309b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia drm_mode_config_cleanup(dev); 310b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 311b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_cpufreq_unregister: 312b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia pm_runtime_disable(dev->dev); 313b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia#ifdef CONFIG_CPU_FREQ 314b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia cpufreq_unregister_notifier(&priv->freq_transition, 315b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia CPUFREQ_TRANSITION_NOTIFIER); 316b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_put_disp_clk: 317b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia clk_put(priv->disp_clk); 318b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia#endif 319b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 320b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_put_clk: 321b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia clk_put(priv->clk); 322b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 323b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_iounmap: 324b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia iounmap(priv->mmio); 325b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 326b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_free_wq: 327b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia flush_workqueue(priv->wq); 328b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia destroy_workqueue(priv->wq); 329b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia 330b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garciafail_free_priv: 331b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia dev->dev_private = NULL; 332b478e336b3e75505707a11e78ef8b964ef0a03afEzequiel Garcia kfree(priv); 33316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return ret; 33416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 33516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 33616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_preclose(struct drm_device *dev, struct drm_file *file) 33716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 33816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 33916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 34016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_crtc_cancel_page_flip(priv->crtc, file); 34116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 34216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 34316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_lastclose(struct drm_device *dev) 34416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 34516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 34616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_fbdev_cma_restore_mode(priv->fbdev); 34716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 34816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 349e9f0d76f3bcd4dda7136baaaaf45bda3b13ff40fDaniel Vetterstatic irqreturn_t tilcdc_irq(int irq, void *arg) 35016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 35116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *dev = arg; 35216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 35316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return tilcdc_crtc_irq(priv->crtc); 35416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 35516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 35616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_irq_preinstall(struct drm_device *dev) 35716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 35816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_clear_irqstatus(dev, 0xffffffff); 35916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 36016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 36116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_irq_postinstall(struct drm_device *dev) 36216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 36316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 36416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 36516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* enable FIFO underflow irq: */ 366a50b24f4a6a0b91568f414200b2a0af39ebbe066Sachin Kamat if (priv->rev == 1) 36716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); 368a50b24f4a6a0b91568f414200b2a0af39ebbe066Sachin Kamat else 36916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_set(dev, LCDC_INT_ENABLE_SET_REG, LCDC_V2_UNDERFLOW_INT_ENA); 37016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 37116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 37216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 37316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 37416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_irq_uninstall(struct drm_device *dev) 37516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 37616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 37716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 37816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* disable irqs that we might have enabled: */ 37916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->rev == 1) { 38016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, 38116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); 38216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA); 38316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } else { 38416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_clear(dev, LCDC_INT_ENABLE_SET_REG, 38516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | 38616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark LCDC_V2_END_OF_FRAME0_INT_ENA | LCDC_V2_END_OF_FRAME1_INT_ENA | 38716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark LCDC_FRAME_DONE); 38816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 38916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 39016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 39116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 39216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void enable_vblank(struct drm_device *dev, bool enable) 39316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 39416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 39516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark u32 reg, mask; 39616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 39716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->rev == 1) { 39816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark reg = LCDC_DMA_CTRL_REG; 39916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mask = LCDC_V1_END_OF_FRAME_INT_ENA; 40016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } else { 40116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark reg = LCDC_INT_ENABLE_SET_REG; 40216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mask = LCDC_V2_END_OF_FRAME0_INT_ENA | 40316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark LCDC_V2_END_OF_FRAME1_INT_ENA | LCDC_FRAME_DONE; 40416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 40516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 40616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (enable) 40716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_set(dev, reg, mask); 40816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark else 40916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_clear(dev, reg, mask); 41016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 41116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 41216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_enable_vblank(struct drm_device *dev, int crtc) 41316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 41416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark enable_vblank(dev, true); 41516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 41616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 41716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 41816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_disable_vblank(struct drm_device *dev, int crtc) 41916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 42016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark enable_vblank(dev, false); 42116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 42216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 42316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) 42416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct { 42516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark const char *name; 42616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark uint8_t rev; 42716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark uint8_t save; 42816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark uint32_t reg; 42932501459be6dc9378a3da63cadee929c26e11368Sachin Kamat} registers[] = { 43016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#define REG(rev, save, reg) { #reg, rev, save, reg } 43116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* exists in revision 1: */ 43216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, false, LCDC_PID_REG), 43316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_CTRL_REG), 43416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, false, LCDC_STAT_REG), 43516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_RASTER_CTRL_REG), 43616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_RASTER_TIMING_0_REG), 43716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_RASTER_TIMING_1_REG), 43816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_RASTER_TIMING_2_REG), 43916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_DMA_CTRL_REG), 44016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_DMA_FB_BASE_ADDR_0_REG), 44116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_DMA_FB_CEILING_ADDR_0_REG), 44216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_DMA_FB_BASE_ADDR_1_REG), 44316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(1, true, LCDC_DMA_FB_CEILING_ADDR_1_REG), 44416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* new in revision 2: */ 44516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, false, LCDC_RAW_STAT_REG), 44616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, false, LCDC_MASKED_STAT_REG), 44716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, false, LCDC_INT_ENABLE_SET_REG), 44816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, false, LCDC_INT_ENABLE_CLR_REG), 44916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, false, LCDC_END_OF_INT_IND_REG), 45016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, true, LCDC_CLK_ENABLE_REG), 45116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark REG(2, true, LCDC_INT_ENABLE_SET_REG), 45216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#undef REG 45316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 45416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 45516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 45616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_DEBUG_FS 45716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_regs_show(struct seq_file *m, void *arg) 45816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 45916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_info_node *node = (struct drm_info_node *) m->private; 46016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *dev = node->minor->dev; 46116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 46216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark unsigned i; 46316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 46416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_get_sync(dev->dev); 46516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 46616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark seq_printf(m, "revision: %d\n", priv->rev); 46716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 46816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark for (i = 0; i < ARRAY_SIZE(registers); i++) 46916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (priv->rev >= registers[i].rev) 47016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark seq_printf(m, "%s:\t %08x\n", registers[i].name, 47116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_read(dev, registers[i].reg)); 47216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 47316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pm_runtime_put_sync(dev->dev); 47416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 47516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 47616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 47716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 47816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_mm_show(struct seq_file *m, void *arg) 47916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 48016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_info_node *node = (struct drm_info_node *) m->private; 48116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *dev = node->minor->dev; 482b04a590623661132fbafdda53a6566b227dc39cfDaniel Vetter return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm); 48316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 48416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 48516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_info_list tilcdc_debugfs_list[] = { 48616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { "regs", tilcdc_regs_show, 0 }, 48716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { "mm", tilcdc_mm_show, 0 }, 48816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { "fb", drm_fb_cma_debugfs_show, 0 }, 48916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 49016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 49116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_debugfs_init(struct drm_minor *minor) 49216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 49316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *dev = minor->dev; 49416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_module *mod; 49516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret; 49616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 49716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = drm_debugfs_create_files(tilcdc_debugfs_list, 49816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ARRAY_SIZE(tilcdc_debugfs_list), 49916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark minor->debugfs_root, minor); 50016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 50116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark list_for_each_entry(mod, &module_list, list) 50216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (mod->funcs->debugfs_init) 50316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod->funcs->debugfs_init(mod, minor); 50416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 50516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret) { 50616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "could not install tilcdc_debugfs_list\n"); 50716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return ret; 50816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 50916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 51016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return ret; 51116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 51216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 51316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tilcdc_debugfs_cleanup(struct drm_minor *minor) 51416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 51516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_module *mod; 51616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_debugfs_remove_files(tilcdc_debugfs_list, 51716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ARRAY_SIZE(tilcdc_debugfs_list), minor); 51816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 51916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark list_for_each_entry(mod, &module_list, list) 52016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (mod->funcs->debugfs_cleanup) 52116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod->funcs->debugfs_cleanup(mod, minor); 52216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 52316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 52416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 52516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct file_operations fops = { 52616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .owner = THIS_MODULE, 52716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .open = drm_open, 52816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .release = drm_release, 52916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .unlocked_ioctl = drm_ioctl, 53016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_COMPAT 53116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .compat_ioctl = drm_compat_ioctl, 53216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 53316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .poll = drm_poll, 53416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .read = drm_read, 53516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .llseek = no_llseek, 53616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .mmap = drm_gem_cma_mmap, 53716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 53816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 53916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_driver tilcdc_driver = { 54016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, 54116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .load = tilcdc_load, 54216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .unload = tilcdc_unload, 54316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .preclose = tilcdc_preclose, 54416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .lastclose = tilcdc_lastclose, 545915b4d11b8b9e7b84ba4a4645b6cc7fbc0c071cfDavid Herrmann .set_busid = drm_platform_set_busid, 54616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .irq_handler = tilcdc_irq, 54716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .irq_preinstall = tilcdc_irq_preinstall, 54816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .irq_postinstall = tilcdc_irq_postinstall, 54916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .irq_uninstall = tilcdc_irq_uninstall, 55016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .get_vblank_counter = drm_vblank_count, 55116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .enable_vblank = tilcdc_enable_vblank, 55216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .disable_vblank = tilcdc_disable_vblank, 55316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .gem_free_object = drm_gem_cma_free_object, 55416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .gem_vm_ops = &drm_gem_cma_vm_ops, 55516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .dumb_create = drm_gem_cma_dumb_create, 55616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .dumb_map_offset = drm_gem_cma_dumb_map_offset, 55743387b37fa2d0f368142b8fa8c9440da92e5381bDaniel Vetter .dumb_destroy = drm_gem_dumb_destroy, 55816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_DEBUG_FS 55916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .debugfs_init = tilcdc_debugfs_init, 56016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .debugfs_cleanup = tilcdc_debugfs_cleanup, 56116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 56216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .fops = &fops, 56316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .name = "tilcdc", 56416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .desc = "TI LCD Controller DRM", 56516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .date = "20121205", 56616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .major = 1, 56716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .minor = 0, 56816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 56916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 57016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 57116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Power management: 57216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 57316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 57416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#ifdef CONFIG_PM_SLEEP 57516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_pm_suspend(struct device *dev) 57616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 57716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *ddev = dev_get_drvdata(dev); 57816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = ddev->dev_private; 57916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark unsigned i, n = 0; 58016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 58116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_kms_helper_poll_disable(ddev); 58216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 58316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* Save register state: */ 58416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark for (i = 0; i < ARRAY_SIZE(registers); i++) 58516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (registers[i].save && (priv->rev >= registers[i].rev)) 58616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg); 58716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 58816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 58916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 59016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 59116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_pm_resume(struct device *dev) 59216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 59316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_device *ddev = dev_get_drvdata(dev); 59416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = ddev->dev_private; 59516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark unsigned i, n = 0; 59616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 59716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* Restore register state: */ 59816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark for (i = 0; i < ARRAY_SIZE(registers); i++) 59916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (registers[i].save && (priv->rev >= registers[i].rev)) 60016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_write(ddev, registers[i].reg, priv->saved_register[n++]); 60116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 60216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_kms_helper_poll_enable(ddev); 60316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 60416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 60516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 60616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#endif 60716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 60816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct dev_pm_ops tilcdc_pm_ops = { 60916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark SET_SYSTEM_SLEEP_PM_OPS(tilcdc_pm_suspend, tilcdc_pm_resume) 61016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 61116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 61216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 61316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Platform driver: 61416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 61516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 61616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_pdev_probe(struct platform_device *pdev) 61716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 61816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* bail out early if no DT data: */ 61916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!pdev->dev.of_node) { 62016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "device-tree data is missing\n"); 62116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENXIO; 62216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 62316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 62439de6194131c155901f96686a063212656d80c2eDarren Etheridge /* defer probing if slave is in deferred probing */ 62539de6194131c155901f96686a063212656d80c2eDarren Etheridge if (slave_probing == true) 62639de6194131c155901f96686a063212656d80c2eDarren Etheridge return -EPROBE_DEFER; 62739de6194131c155901f96686a063212656d80c2eDarren Etheridge 62816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return drm_platform_init(&tilcdc_driver, pdev); 62916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 63016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 63116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tilcdc_pdev_remove(struct platform_device *pdev) 63216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 633c84b4356571d8fb34acbc5522b07f256c0347a22Daniel Vetter drm_put_dev(platform_get_drvdata(pdev)); 63416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 63516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 63616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 63716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 63816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct of_device_id tilcdc_of_match[] = { 63916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { .compatible = "ti,am33xx-tilcdc", }, 64016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { }, 64116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 64216ea975eac671fa40a78594a116a44fef8e3f4a9Rob ClarkMODULE_DEVICE_TABLE(of, tilcdc_of_match); 64316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 64416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct platform_driver tilcdc_platform_driver = { 64516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .probe = tilcdc_pdev_probe, 64616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .remove = tilcdc_pdev_remove, 64716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .driver = { 64816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .owner = THIS_MODULE, 64916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .name = "tilcdc", 65016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .pm = &tilcdc_pm_ops, 65116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .of_match_table = tilcdc_of_match, 65216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark }, 65316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 65416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 65516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int __init tilcdc_drm_init(void) 65616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 65716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DBG("init"); 65816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_tfp410_init(); 6596e8de0bd6a51fdeebd5d975c4fcc426f730b339bRob Clark tilcdc_slave_init(); 6600d4bbaf9f3e5b9f52150ddc5a4ee8b0ab83a440bRob Clark tilcdc_panel_init(); 66116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return platform_driver_register(&tilcdc_platform_driver); 66216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 66316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 66416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void __exit tilcdc_drm_fini(void) 66516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 66616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DBG("fini"); 66716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark platform_driver_unregister(&tilcdc_platform_driver); 668eb565a2bbadc6a5030a6dbe58db1aa52453e7edfGuido Martínez tilcdc_panel_fini(); 669eb565a2bbadc6a5030a6dbe58db1aa52453e7edfGuido Martínez tilcdc_slave_fini(); 670eb565a2bbadc6a5030a6dbe58db1aa52453e7edfGuido Martínez tilcdc_tfp410_fini(); 67116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 67216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 6732023d84d2c3b7a4b8fc5c64c08c59c4e1505e2d3Guido Martínezmodule_init(tilcdc_drm_init); 67416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkmodule_exit(tilcdc_drm_fini); 67516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 67616ea975eac671fa40a78594a116a44fef8e3f4a9Rob ClarkMODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); 67716ea975eac671fa40a78594a116a44fef8e3f4a9Rob ClarkMODULE_DESCRIPTION("TI LCD Controller DRM Driver"); 67816ea975eac671fa40a78594a116a44fef8e3f4a9Rob ClarkMODULE_LICENSE("GPL"); 679