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