Message ID | 20180502134719.8388-1-linus.walleij@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, May 02, 2018 at 03:47:18PM +0200, Linus Walleij wrote: > The Versatile Express uses a special configuration controller > deeply embedded in the system motherboard FPGA to multiplex the > two to three (!) display controller instances out to the single > SiI9022 bridge. > > Set up an extra file with the logic to probe to the FPGA mux > register on the system controller bus, then parse the device > tree to see if there is a CLCD or HDLCD instance on the core > tile (also known as the daughterboard) by looking in the > root of the device tree for compatible nodes. > > - If there is a HDLCD on the core tile, and there is a driver > for it, we exit probe and deactivate the motherboard CLCD. > We do not touch the DVI mux in this case, to make sure we > don't break HDLCD. > > - If there is a CLCD on both the motherboard and the core tile > (only the CA9 has this) the core tile CLCD takes precedence > and get muxed to the DVI connector. > > - Only if there is no working graphics on the core tile, the > motherboard CLCD is probed and muxed to the DVI connector. > > Core tile graphics should always take precedence as it can > address all memory and is also faster, however the motherboard > CLCD is good to have around for diagnostics and testing. > > It is possible to test the motherboard CLCD by setting the > status = "disabled" property on the core tile CLCD or > HDLCD. > > Scale down the Versatile Express to 16BPP so we can support a > 1024x768 display despite the bus bandwidth restrictions on this > platform. (The motherboard CLCD supports slightly lower > resolution.) > > Cc: Liviu Dudau <liviu.dudau@arm.com> > Cc: Pawel Moll <pawel.moll@arm.com> > Acked-by: Eric Anholt <eric@anholt.net> > Tested-by: Robin Murphy <robin.murphy@arm.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > ChangeLog v4->v5: > - Collect Robin's Tested-by > - Switch to builtin_platform_driver() for the muxfpga as this > file is always built as "-y" for the arch and we need to > avoid module collisions with the main PL111 driver. > ChangeLog v3->v4: > - Add a missing platform_device_put() > - Simplify code with for_each_available_child_of_node() > - Collect Eric's ACK. > ChangeLog v2->v3: > - Rewrite CLCD detection and mux priority logic, look in > the device tree root for core tile graphics. > ChangeLog v1->v2: > - No changes just reposting rebased on mainline changes. > --- > drivers/gpu/drm/pl111/Makefile | 1 + > drivers/gpu/drm/pl111/pl111_versatile.c | 49 +++++++++- > drivers/gpu/drm/pl111/pl111_vexpress.c | 125 ++++++++++++++++++++++++ > drivers/gpu/drm/pl111/pl111_vexpress.h | 22 +++++ > 4 files changed, 196 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/pl111/pl111_vexpress.c > create mode 100644 drivers/gpu/drm/pl111/pl111_vexpress.h > > diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile > index 9c5e8dba8ac6..19a8189dc54f 100644 > --- a/drivers/gpu/drm/pl111/Makefile > +++ b/drivers/gpu/drm/pl111/Makefile > @@ -3,6 +3,7 @@ pl111_drm-y += pl111_display.o \ > pl111_versatile.o \ > pl111_drv.o > > +pl111_drm-$(CONFIG_ARCH_VEXPRESS) += pl111_vexpress.o > pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o > > obj-$(CONFIG_DRM_PL111) += pl111_drm.o > diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c > index 9302f516045e..78ddf8534fd2 100644 > --- a/drivers/gpu/drm/pl111/pl111_versatile.c > +++ b/drivers/gpu/drm/pl111/pl111_versatile.c > @@ -1,12 +1,14 @@ > #include <linux/amba/clcd-regs.h> > #include <linux/device.h> > #include <linux/of.h> > +#include <linux/of_platform.h> > #include <linux/regmap.h> > #include <linux/mfd/syscon.h> > #include <linux/bitops.h> > #include <linux/module.h> > #include <drm/drmP.h> > #include "pl111_versatile.h" > +#include "pl111_vexpress.h" > #include "pl111_drm.h" > > static struct regmap *versatile_syscon_map; > @@ -22,6 +24,7 @@ enum versatile_clcd { > REALVIEW_CLCD_PB11MP, > REALVIEW_CLCD_PBA8, > REALVIEW_CLCD_PBX, > + VEXPRESS_CLCD_V2M, > }; > > static const struct of_device_id versatile_clcd_of_match[] = { > @@ -53,6 +56,10 @@ static const struct of_device_id versatile_clcd_of_match[] = { > .compatible = "arm,realview-pbx-syscon", > .data = (void *)REALVIEW_CLCD_PBX, > }, > + { > + .compatible = "arm,vexpress-muxfpga", > + .data = (void *)VEXPRESS_CLCD_V2M, > + }, > {}, > }; > > @@ -286,12 +293,26 @@ static const struct pl111_variant_data pl111_realview = { > .fb_bpp = 16, > }; > > +/* > + * Versatile Express PL111 variant, again we just push the maximum > + * BPP to 16 to be able to get 1024x768 without saturating the memory > + * bus. The clockdivider also seems broken on the Versatile Express. > + */ > +static const struct pl111_variant_data pl111_vexpress = { > + .name = "PL111 Versatile Express", > + .formats = pl111_realview_pixel_formats, > + .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), > + .fb_bpp = 16, > + .broken_clockdivider = true, > +}; > + > 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); > @@ -301,7 +322,26 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) > } > versatile_clcd_type = (enum versatile_clcd)clcd_id->data; > > - map = syscon_node_to_regmap(np); > + /* Versatile Express special handling */ > + if (versatile_clcd_type == VEXPRESS_CLCD_V2M) { > + struct platform_device *pdev; > + > + /* 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 = dev_get_drvdata(&pdev->dev); > + if (!map) { > + dev_err(dev, "sysreg has not yet probed\n"); > + platform_device_put(pdev); > + return -EPROBE_DEFER; > + } > + } else { > + map = syscon_node_to_regmap(np); > + } > + > if (IS_ERR(map)) { > dev_err(dev, "no Versatile syscon regmap\n"); > return PTR_ERR(map); > @@ -340,6 +380,13 @@ 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; > diff --git a/drivers/gpu/drm/pl111/pl111_vexpress.c b/drivers/gpu/drm/pl111/pl111_vexpress.c > new file mode 100644 > index 000000000000..c9fee625faf1 > --- /dev/null > +++ b/drivers/gpu/drm/pl111/pl111_vexpress.c > @@ -0,0 +1,125 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Versatile Express PL111 handling > + * Copyright (C) 2018 Linus Walleij > + * > + * This module binds to the "arm,vexpress-muxfpga" device on the > + * Versatile Express configuration bus and sets up which CLCD instance > + * gets muxed out on the DVI bridge. > + */ > +#include <linux/device.h> > +#include <linux/module.h> > +#include <linux/regmap.h> > +#include <linux/vexpress.h> > +#include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/of_platform.h> > +#include "pl111_drm.h" > +#include "pl111_vexpress.h" > + > +#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00 > +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 > +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 > + > +int pl111_vexpress_clcd_init(struct device *dev, > + struct pl111_drm_dev_private *priv, > + struct regmap *map) > +{ > + struct device_node *root; > + struct device_node *child; > + struct device_node *ct_clcd = NULL; > + bool has_coretile_clcd = false; > + bool has_coretile_hdlcd = false; > + bool mux_motherboard = true; > + u32 val; > + int ret; > + > + /* > + * 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; > + break; > + } > + } > + > + /* > + * 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; > + } > + > + ret = regmap_write(map, 0, val); > + if (ret) { > + dev_err(dev, "error setting DVI muxmode\n"); > + return -ENODEV; > + } > + > + return 0; > +} > + > +/* > + * This sets up the regmap pointer that will then be retrieved by > + * the detection code in pl111_versatile.c and passed in to the > + * pl111_vexpress_clcd_init() function above. > + */ > +static int vexpress_muxfpga_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct regmap *map; > + > + map = devm_regmap_init_vexpress_config(&pdev->dev); > + if (IS_ERR(map)) > + return PTR_ERR(map); > + dev_set_drvdata(dev, map); > + > + return 0; > +} > + > +static const struct of_device_id vexpress_muxfpga_match[] = { > + { .compatible = "arm,vexpress-muxfpga", } > +}; > + > +static struct platform_driver vexpress_muxfpga_driver = { > + .driver = { > + .name = "vexpress-muxfpga", > + .of_match_table = of_match_ptr(vexpress_muxfpga_match), > + }, > + .probe = vexpress_muxfpga_probe, > +}; > + > +builtin_platform_driver(vexpress_muxfpga_driver); LD [M] drivers/gpu/drm/pl111/pl111_drm.o drivers/gpu/drm/pl111/pl111_vexpress.o: In function `vexpress_muxfpga_driver_init': /home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_vexpress.c:125: multiple definition of `init_module' drivers/gpu/drm/pl111/pl111_drv.o:/home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_drv.c:427: first defined here make[4]: *** [scripts/Makefile.build:570: drivers/gpu/drm/pl111/pl111_drm.o] Error 1 make[3]: *** [scripts/Makefile.build:583: drivers/gpu/drm/pl111] Error 2 make[3]: *** Waiting for unfinished jobs.... Using the default drm-misc configs. Please fix asap, and please compile-test before pushing using these default configs so others aren't blocked. I've disabled the pl111 driver in there for now, please also re-enable. Thanks, Daniel > diff --git a/drivers/gpu/drm/pl111/pl111_vexpress.h b/drivers/gpu/drm/pl111/pl111_vexpress.h > new file mode 100644 > index 000000000000..49876417f7b6 > --- /dev/null > +++ b/drivers/gpu/drm/pl111/pl111_vexpress.h > @@ -0,0 +1,22 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +struct device; > +struct pl111_drm_dev_private; > +struct regmap; > + > +#ifdef CONFIG_ARCH_VEXPRESS > + > +int pl111_vexpress_clcd_init(struct device *dev, > + struct pl111_drm_dev_private *priv, > + struct regmap *map); > + > +#else > + > +static int inline pl111_vexpress_clcd_init(struct device *dev, > + struct pl111_drm_dev_private *priv, > + struct regmap *map) > +{ > + return -ENODEV; > +} > + > +#endif > -- > 2.17.0 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
On Thu, May 3, 2018 at 11:41 AM, Daniel Vetter <daniel@ffwll.ch> wrote: >Me: (...) >> ChangeLog v4->v5: >> - Collect Robin's Tested-by >> - Switch to builtin_platform_driver() for the muxfpga as this >> file is always built as "-y" for the arch and we need to >> avoid module collisions with the main PL111 driver. >> +builtin_platform_driver(vexpress_muxfpga_driver); > > LD [M] drivers/gpu/drm/pl111/pl111_drm.o > drivers/gpu/drm/pl111/pl111_vexpress.o: In function `vexpress_muxfpga_driver_init': > /home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_vexpress.c:125: multiple definition of `init_module' > drivers/gpu/drm/pl111/pl111_drv.o:/home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_drv.c:427: first defined here > make[4]: *** [scripts/Makefile.build:570: drivers/gpu/drm/pl111/pl111_drm.o] Error 1 > make[3]: *** [scripts/Makefile.build:583: drivers/gpu/drm/pl111] Error 2 > make[3]: *** Waiting for unfinished jobs.... > > Using the default drm-misc configs. > > Please fix asap, and please compile-test before pushing using these > default configs so others aren't blocked. I've disabled the pl111 driver > in there for now, please also re-enable. That's typical. As you see in the ChangeLog I really tried to address exactly this. I got that build error from the zeroday build with v4, changed it to a builtin driver and pushed, then it did not give me the problem again. I guess the zeroday build robot isn't using the same configs... Hm, I will take suggestions on how to actually solve it, I guess this is due to the initcall infrastructure only allowing one initcall per module? In that case I guess I should either: - Break out the vexpress file into its own module - Call the vexpress init hooks from the initcalls in the main module I guess I will go for the latter even if it litters the driver with more cross-calls. Yours, Linus Walleij
On Thu, May 3, 2018 at 11:58 AM, Linus Walleij <linus.walleij@linaro.org> wrote: > On Thu, May 3, 2018 at 11:41 AM, Daniel Vetter <daniel@ffwll.ch> wrote: >>Me: > (...) >>> ChangeLog v4->v5: >>> - Collect Robin's Tested-by >>> - Switch to builtin_platform_driver() for the muxfpga as this >>> file is always built as "-y" for the arch and we need to >>> avoid module collisions with the main PL111 driver. >>> +builtin_platform_driver(vexpress_muxfpga_driver); >> >> LD [M] drivers/gpu/drm/pl111/pl111_drm.o >> drivers/gpu/drm/pl111/pl111_vexpress.o: In function `vexpress_muxfpga_driver_init': >> /home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_vexpress.c:125: multiple definition of `init_module' >> drivers/gpu/drm/pl111/pl111_drv.o:/home/daniel/linux/aarch64/drivers/gpu/drm/pl111/pl111_drv.c:427: first defined here >> make[4]: *** [scripts/Makefile.build:570: drivers/gpu/drm/pl111/pl111_drm.o] Error 1 >> make[3]: *** [scripts/Makefile.build:583: drivers/gpu/drm/pl111] Error 2 >> make[3]: *** Waiting for unfinished jobs.... >> >> Using the default drm-misc configs. >> >> Please fix asap, and please compile-test before pushing using these >> default configs so others aren't blocked. I've disabled the pl111 driver >> in there for now, please also re-enable. > > That's typical. As you see in the ChangeLog I really tried to address > exactly this. I got that build error from the zeroday build with v4, > changed it to a builtin driver and pushed, then it did not give me > the problem again. > > I guess the zeroday build robot isn't using the same configs... > > Hm, I will take suggestions on how to actually solve it, I guess > this is due to the initcall infrastructure only allowing one initcall > per module? > > In that case I guess I should either: > - Break out the vexpress file into its own module > - Call the vexpress init hooks from the initcalls in the > main module > > I guess I will go for the latter even if it litters the driver with > more cross-calls. Yeah, that's what we generally do. Including #ifdef mess and all that, since separate kmod tends to be even worse (you need piles of EXPORT_SYMBOL all over). It's a bit silly that the module/initcall stuff can't allow multiple entries ... -Daniel
diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile index 9c5e8dba8ac6..19a8189dc54f 100644 --- a/drivers/gpu/drm/pl111/Makefile +++ b/drivers/gpu/drm/pl111/Makefile @@ -3,6 +3,7 @@ pl111_drm-y += pl111_display.o \ pl111_versatile.o \ pl111_drv.o +pl111_drm-$(CONFIG_ARCH_VEXPRESS) += pl111_vexpress.o pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o obj-$(CONFIG_DRM_PL111) += pl111_drm.o diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index 9302f516045e..78ddf8534fd2 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c @@ -1,12 +1,14 @@ #include <linux/amba/clcd-regs.h> #include <linux/device.h> #include <linux/of.h> +#include <linux/of_platform.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <linux/bitops.h> #include <linux/module.h> #include <drm/drmP.h> #include "pl111_versatile.h" +#include "pl111_vexpress.h" #include "pl111_drm.h" static struct regmap *versatile_syscon_map; @@ -22,6 +24,7 @@ enum versatile_clcd { REALVIEW_CLCD_PB11MP, REALVIEW_CLCD_PBA8, REALVIEW_CLCD_PBX, + VEXPRESS_CLCD_V2M, }; static const struct of_device_id versatile_clcd_of_match[] = { @@ -53,6 +56,10 @@ static const struct of_device_id versatile_clcd_of_match[] = { .compatible = "arm,realview-pbx-syscon", .data = (void *)REALVIEW_CLCD_PBX, }, + { + .compatible = "arm,vexpress-muxfpga", + .data = (void *)VEXPRESS_CLCD_V2M, + }, {}, }; @@ -286,12 +293,26 @@ static const struct pl111_variant_data pl111_realview = { .fb_bpp = 16, }; +/* + * Versatile Express PL111 variant, again we just push the maximum + * BPP to 16 to be able to get 1024x768 without saturating the memory + * bus. The clockdivider also seems broken on the Versatile Express. + */ +static const struct pl111_variant_data pl111_vexpress = { + .name = "PL111 Versatile Express", + .formats = pl111_realview_pixel_formats, + .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), + .fb_bpp = 16, + .broken_clockdivider = true, +}; + 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); @@ -301,7 +322,26 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) } versatile_clcd_type = (enum versatile_clcd)clcd_id->data; - map = syscon_node_to_regmap(np); + /* Versatile Express special handling */ + if (versatile_clcd_type == VEXPRESS_CLCD_V2M) { + struct platform_device *pdev; + + /* 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 = dev_get_drvdata(&pdev->dev); + if (!map) { + dev_err(dev, "sysreg has not yet probed\n"); + platform_device_put(pdev); + return -EPROBE_DEFER; + } + } else { + map = syscon_node_to_regmap(np); + } + if (IS_ERR(map)) { dev_err(dev, "no Versatile syscon regmap\n"); return PTR_ERR(map); @@ -340,6 +380,13 @@ 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; diff --git a/drivers/gpu/drm/pl111/pl111_vexpress.c b/drivers/gpu/drm/pl111/pl111_vexpress.c new file mode 100644 index 000000000000..c9fee625faf1 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_vexpress.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Versatile Express PL111 handling + * Copyright (C) 2018 Linus Walleij + * + * This module binds to the "arm,vexpress-muxfpga" device on the + * Versatile Express configuration bus and sets up which CLCD instance + * gets muxed out on the DVI bridge. + */ +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/vexpress.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include "pl111_drm.h" +#include "pl111_vexpress.h" + +#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00 +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 +#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 + +int pl111_vexpress_clcd_init(struct device *dev, + struct pl111_drm_dev_private *priv, + struct regmap *map) +{ + struct device_node *root; + struct device_node *child; + struct device_node *ct_clcd = NULL; + bool has_coretile_clcd = false; + bool has_coretile_hdlcd = false; + bool mux_motherboard = true; + u32 val; + int ret; + + /* + * 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; + break; + } + } + + /* + * 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; + } + + ret = regmap_write(map, 0, val); + if (ret) { + dev_err(dev, "error setting DVI muxmode\n"); + return -ENODEV; + } + + return 0; +} + +/* + * This sets up the regmap pointer that will then be retrieved by + * the detection code in pl111_versatile.c and passed in to the + * pl111_vexpress_clcd_init() function above. + */ +static int vexpress_muxfpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *map; + + map = devm_regmap_init_vexpress_config(&pdev->dev); + if (IS_ERR(map)) + return PTR_ERR(map); + dev_set_drvdata(dev, map); + + return 0; +} + +static const struct of_device_id vexpress_muxfpga_match[] = { + { .compatible = "arm,vexpress-muxfpga", } +}; + +static struct platform_driver vexpress_muxfpga_driver = { + .driver = { + .name = "vexpress-muxfpga", + .of_match_table = of_match_ptr(vexpress_muxfpga_match), + }, + .probe = vexpress_muxfpga_probe, +}; + +builtin_platform_driver(vexpress_muxfpga_driver); diff --git a/drivers/gpu/drm/pl111/pl111_vexpress.h b/drivers/gpu/drm/pl111/pl111_vexpress.h new file mode 100644 index 000000000000..49876417f7b6 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_vexpress.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +struct device; +struct pl111_drm_dev_private; +struct regmap; + +#ifdef CONFIG_ARCH_VEXPRESS + +int pl111_vexpress_clcd_init(struct device *dev, + struct pl111_drm_dev_private *priv, + struct regmap *map); + +#else + +static int inline pl111_vexpress_clcd_init(struct device *dev, + struct pl111_drm_dev_private *priv, + struct regmap *map) +{ + return -ENODEV; +} + +#endif