diff options
Diffstat (limited to 'drivers/gpu/drm/pl111/pl111_versatile.c')
-rw-r--r-- | drivers/gpu/drm/pl111/pl111_versatile.c | 148 |
1 files changed, 109 insertions, 39 deletions
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index 4f325c410b5d..64f01a4e6767 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c @@ -8,9 +8,9 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/regmap.h> +#include <linux/vexpress.h> #include "pl111_versatile.h" -#include "pl111_vexpress.h" #include "pl111_drm.h" static struct regmap *versatile_syscon_map; @@ -361,13 +361,110 @@ static const struct pl111_variant_data pl111_vexpress = { .broken_clockdivider = true, }; +#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00 +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 + +static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, + struct pl111_drm_dev_private *priv) +{ + struct platform_device *pdev; + struct device_node *root; + struct device_node *child; + struct device_node *ct_clcd = NULL; + struct regmap *map; + bool has_coretile_clcd = false; + bool has_coretile_hdlcd = false; + bool mux_motherboard = true; + u32 val; + int ret; + + if (!IS_ENABLED(CONFIG_VEXPRESS_CONFIG)) + return -ENODEV; + + /* + * Check if we have a CLCD or HDLCD on the core tile by checking if a + * CLCD or HDLCD is available in the root of the device tree. + */ + root = of_find_node_by_path("/"); + if (!root) + return -EINVAL; + + for_each_available_child_of_node(root, child) { + if (of_device_is_compatible(child, "arm,pl111")) { + has_coretile_clcd = true; + ct_clcd = child; + break; + } + if (of_device_is_compatible(child, "arm,hdlcd")) { + has_coretile_hdlcd = true; + of_node_put(child); + break; + } + } + + of_node_put(root); + + /* + * If there is a coretile HDLCD and it has a driver, + * do not mux the CLCD on the motherboard to the DVI. + */ + if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD)) + mux_motherboard = false; + + /* + * On the Vexpress CA9 we let the CLCD on the coretile + * take precedence, so also in this case do not mux the + * motherboard to the DVI. + */ + if (has_coretile_clcd) + mux_motherboard = false; + + if (mux_motherboard) { + dev_info(dev, "DVI muxed to motherboard CLCD\n"); + val = VEXPRESS_FPGAMUX_MOTHERBOARD; + } else if (ct_clcd == dev->of_node) { + dev_info(dev, + "DVI muxed to daughterboard 1 (core tile) CLCD\n"); + val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1; + } else { + dev_info(dev, "core tile graphics present\n"); + dev_info(dev, "this device will be deactivated\n"); + return -ENODEV; + } + + /* Call into deep Vexpress configuration API */ + pdev = of_find_device_by_node(np); + if (!pdev) { + dev_err(dev, "can't find the sysreg device, deferring\n"); + return -EPROBE_DEFER; + } + + map = devm_regmap_init_vexpress_config(&pdev->dev); + if (IS_ERR(map)) { + platform_device_put(pdev); + return PTR_ERR(map); + } + + ret = regmap_write(map, 0, val); + platform_device_put(pdev); + if (ret) { + dev_err(dev, "error setting DVI muxmode\n"); + return -ENODEV; + } + + priv->variant = &pl111_vexpress; + dev_info(dev, "initializing Versatile Express PL111\n"); + + return 0; +} + int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) { const struct of_device_id *clcd_id; enum versatile_clcd versatile_clcd_type; struct device_node *np; struct regmap *map; - int ret; np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, &clcd_id); @@ -378,6 +475,15 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) versatile_clcd_type = (enum versatile_clcd)clcd_id->data; + /* Versatile Express special handling */ + if (versatile_clcd_type == VEXPRESS_CLCD_V2M) { + int ret = pl111_vexpress_clcd_init(dev, np, priv); + of_node_put(np); + if (ret) + dev_err(dev, "Versatile Express init failed - %d", ret); + return ret; + } + /* * On the Integrator, check if we should use the IM-PD1 instead, * if we find it, it will take precedence. This is on the Integrator/AP @@ -390,37 +496,8 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) versatile_clcd_type = (enum versatile_clcd)clcd_id->data; } - /* Versatile Express special handling */ - if (versatile_clcd_type == VEXPRESS_CLCD_V2M) { - struct platform_device *pdev; - - /* Registers a driver for the muxfpga */ - ret = vexpress_muxfpga_init(); - if (ret) { - dev_err(dev, "unable to initialize muxfpga driver\n"); - of_node_put(np); - return ret; - } - - /* Call into deep Vexpress configuration API */ - pdev = of_find_device_by_node(np); - if (!pdev) { - dev_err(dev, "can't find the sysreg device, deferring\n"); - of_node_put(np); - return -EPROBE_DEFER; - } - map = dev_get_drvdata(&pdev->dev); - if (!map) { - dev_err(dev, "sysreg has not yet probed\n"); - platform_device_put(pdev); - of_node_put(np); - return -EPROBE_DEFER; - } - } else { - map = syscon_node_to_regmap(np); - } + map = syscon_node_to_regmap(np); of_node_put(np); - if (IS_ERR(map)) { dev_err(dev, "no Versatile syscon regmap\n"); return PTR_ERR(map); @@ -466,13 +543,6 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) priv->variant_display_disable = pl111_realview_clcd_disable; dev_info(dev, "set up callbacks for RealView PL111\n"); break; - case VEXPRESS_CLCD_V2M: - priv->variant = &pl111_vexpress; - dev_info(dev, "initializing Versatile Express PL111\n"); - ret = pl111_vexpress_clcd_init(dev, priv, map); - if (ret) - return ret; - break; default: dev_info(dev, "unknown Versatile system controller\n"); break; |