162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 362306a36Sopenharmony_ci * Copyright (C) 2019, 2020 Paul Boddie <paul@boddie.org.uk> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from dw_hdmi-imx.c with i.MX portions removed. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of_platform.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <drm/bridge/dw_hdmi.h> 1362306a36Sopenharmony_ci#include <drm/drm_of.h> 1462306a36Sopenharmony_ci#include <drm/drm_print.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct dw_hdmi_mpll_config ingenic_mpll_cfg[] = { 1762306a36Sopenharmony_ci { 45250000, { { 0x01e0, 0x0000 }, { 0x21e1, 0x0000 }, { 0x41e2, 0x0000 } } }, 1862306a36Sopenharmony_ci { 92500000, { { 0x0140, 0x0005 }, { 0x2141, 0x0005 }, { 0x4142, 0x0005 } } }, 1962306a36Sopenharmony_ci { 148500000, { { 0x00a0, 0x000a }, { 0x20a1, 0x000a }, { 0x40a2, 0x000a } } }, 2062306a36Sopenharmony_ci { 216000000, { { 0x00a0, 0x000a }, { 0x2001, 0x000f }, { 0x4002, 0x000f } } }, 2162306a36Sopenharmony_ci { ~0UL, { { 0x0000, 0x0000 }, { 0x0000, 0x0000 }, { 0x0000, 0x0000 } } } 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct dw_hdmi_curr_ctrl ingenic_cur_ctr[] = { 2562306a36Sopenharmony_ci /*pixelclk bpp8 bpp10 bpp12 */ 2662306a36Sopenharmony_ci { 54000000, { 0x091c, 0x091c, 0x06dc } }, 2762306a36Sopenharmony_ci { 58400000, { 0x091c, 0x06dc, 0x06dc } }, 2862306a36Sopenharmony_ci { 72000000, { 0x06dc, 0x06dc, 0x091c } }, 2962306a36Sopenharmony_ci { 74250000, { 0x06dc, 0x0b5c, 0x091c } }, 3062306a36Sopenharmony_ci { 118800000, { 0x091c, 0x091c, 0x06dc } }, 3162306a36Sopenharmony_ci { 216000000, { 0x06dc, 0x0b5c, 0x091c } }, 3262306a36Sopenharmony_ci { ~0UL, { 0x0000, 0x0000, 0x0000 } }, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Resistance term 133Ohm Cfg 3762306a36Sopenharmony_ci * PREEMP config 0.00 3862306a36Sopenharmony_ci * TX/CK level 10 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_cistatic const struct dw_hdmi_phy_config ingenic_phy_config[] = { 4162306a36Sopenharmony_ci /*pixelclk symbol term vlev */ 4262306a36Sopenharmony_ci { 216000000, 0x800d, 0x0005, 0x01ad}, 4362306a36Sopenharmony_ci { ~0UL, 0x0000, 0x0000, 0x0000} 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic enum drm_mode_status 4762306a36Sopenharmony_ciingenic_dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, 4862306a36Sopenharmony_ci const struct drm_display_info *info, 4962306a36Sopenharmony_ci const struct drm_display_mode *mode) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci if (mode->clock < 13500) 5262306a36Sopenharmony_ci return MODE_CLOCK_LOW; 5362306a36Sopenharmony_ci /* FIXME: Hardware is capable of 270MHz, but setup data is missing. */ 5462306a36Sopenharmony_ci if (mode->clock > 216000) 5562306a36Sopenharmony_ci return MODE_CLOCK_HIGH; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return MODE_OK; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct dw_hdmi_plat_data ingenic_dw_hdmi_plat_data = { 6162306a36Sopenharmony_ci .mpll_cfg = ingenic_mpll_cfg, 6262306a36Sopenharmony_ci .cur_ctr = ingenic_cur_ctr, 6362306a36Sopenharmony_ci .phy_config = ingenic_phy_config, 6462306a36Sopenharmony_ci .mode_valid = ingenic_dw_hdmi_mode_valid, 6562306a36Sopenharmony_ci .output_port = 1, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic const struct of_device_id ingenic_dw_hdmi_dt_ids[] = { 6962306a36Sopenharmony_ci { .compatible = "ingenic,jz4780-dw-hdmi" }, 7062306a36Sopenharmony_ci { /* Sentinel */ }, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ingenic_dw_hdmi_dt_ids); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void ingenic_dw_hdmi_cleanup(void *data) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct dw_hdmi *hdmi = (struct dw_hdmi *)data; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci dw_hdmi_remove(hdmi); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int ingenic_dw_hdmi_probe(struct platform_device *pdev) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct dw_hdmi *hdmi; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci hdmi = dw_hdmi_probe(pdev, &ingenic_dw_hdmi_plat_data); 8662306a36Sopenharmony_ci if (IS_ERR(hdmi)) 8762306a36Sopenharmony_ci return PTR_ERR(hdmi); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return devm_add_action_or_reset(&pdev->dev, ingenic_dw_hdmi_cleanup, hdmi); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct platform_driver ingenic_dw_hdmi_driver = { 9362306a36Sopenharmony_ci .probe = ingenic_dw_hdmi_probe, 9462306a36Sopenharmony_ci .driver = { 9562306a36Sopenharmony_ci .name = "dw-hdmi-ingenic", 9662306a36Sopenharmony_ci .of_match_table = ingenic_dw_hdmi_dt_ids, 9762306a36Sopenharmony_ci }, 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_cimodule_platform_driver(ingenic_dw_hdmi_driver); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciMODULE_DESCRIPTION("JZ4780 Specific DW-HDMI Driver Extension"); 10262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 10362306a36Sopenharmony_ciMODULE_ALIAS("platform:dw-hdmi-ingenic"); 104