devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Liviu Dudau <Liviu.Dudau@arm.com>
To: Ryan Harkin <ryan.harkin@linaro.org>
Cc: "stigge@antcom.de" <stigge@antcom.de>,
	"tixy@linaro.org" <tixy@linaro.org>,
	"linux-fbdev@vger.kernel.org" <linux-fbdev@vger.kernel.org>,
	Pawel Moll <Pawel.Moll@arm.com>,
	"devicetree-discuss@lists.ozlabs.org"
	<devicetree-discuss@lists.ozlabs.org>,
	"spear-devel@list.st.com" <spear-devel@list.st.com>,
	"shiraz.hashim@st.com" <shiraz.hashim@st.com>,
	"viresh.linux@gmail.com" <viresh.linux@gmail.com>,
	"arnd.bergmann@linaro.org" <arnd.bergmann@linaro.org>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>
Subject: Re: [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver
Date: Thu, 20 Sep 2012 11:24:53 +0100	[thread overview]
Message-ID: <20120920102453.GG32603@e102652-lin.cambridge.arm.com> (raw)
In-Reply-To: <1348070666-9153-2-git-send-email-ryan.harkin@linaro.org>

On Wed, Sep 19, 2012 at 05:04:24PM +0100, Ryan Harkin wrote:
> Add support to parse the display configuration from device tree.
>
> If the board does not provide platform specific functions in the struct
> clcd_board contained with the amba device info, then defaults are provided
> by the driver.
>
> The device tree configuration can either ask for a DMA setup or provide a
> framebuffer address to be remapped into the driver.
>
> Signed-off-by: Ryan Harkin <ryan.harkin@linaro.org>
> ---
>  drivers/video/amba-clcd.c |  253 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 253 insertions(+)
>
> diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
> index 0a2cce7..01dbad1 100644
> --- a/drivers/video/amba-clcd.c
> +++ b/drivers/video/amba-clcd.c
> @@ -16,7 +16,10 @@
>  #include <linux/string.h>
>  #include <linux/slab.h>
>  #include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/memblock.h>
>  #include <linux/mm.h>
> +#include <linux/of.h>
>  #include <linux/fb.h>
>  #include <linux/init.h>
>  #include <linux/ioport.h>
> @@ -391,6 +394,19 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
>       }
>       return 0;
>  }
> +int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
> +{
> +     return dma_mmap_writecombine(&fb->dev->dev, vma,
> +                                  fb->fb.screen_base,
> +                                  fb->fb.fix.smem_start,
> +                                  fb->fb.fix.smem_len);
> +}
> +
> +void clcdfb_remove_dma(struct clcd_fb *fb)
> +{
> +     dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
> +                           fb->fb.screen_base, fb->fb.fix.smem_start);
> +}
>
>  static int clcdfb_mmap(struct fb_info *info,
>                      struct vm_area_struct *vma)
> @@ -542,12 +558,249 @@ static int clcdfb_register(struct clcd_fb *fb)
>       return ret;
>  }
>
> +struct string_lookup {
> +     const char *string;
> +     const u32       val;
> +};
> +
> +static struct string_lookup vmode_lookups[] = {
> +     { "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
> +     { "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
> +     { "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
> +     { "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
> +     { NULL, 0 },
> +};
> +
> +static struct string_lookup tim2_lookups[] = {
> +     { "TIM2_CLKSEL", TIM2_CLKSEL},
> +     { "TIM2_IVS",    TIM2_IVS},
> +     { "TIM2_IHS",    TIM2_IHS},
> +     { "TIM2_IPC",    TIM2_IPC},
> +     { "TIM2_IOE",    TIM2_IOE},
> +     { "TIM2_BCD",    TIM2_BCD},
> +     { NULL, 0},
> +};
> +static struct string_lookup cntl_lookups[] = {
> +     {"CNTL_LCDEN",        CNTL_LCDEN},
> +     {"CNTL_LCDBPP1",      CNTL_LCDBPP1},
> +     {"CNTL_LCDBPP2",      CNTL_LCDBPP2},
> +     {"CNTL_LCDBPP4",      CNTL_LCDBPP4},
> +     {"CNTL_LCDBPP8",      CNTL_LCDBPP8},
> +     {"CNTL_LCDBPP16",     CNTL_LCDBPP16},
> +     {"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
> +     {"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
> +     {"CNTL_LCDBPP24",     CNTL_LCDBPP24},
> +     {"CNTL_LCDBW",        CNTL_LCDBW},
> +     {"CNTL_LCDTFT",       CNTL_LCDTFT},
> +     {"CNTL_LCDMONO8",     CNTL_LCDMONO8},
> +     {"CNTL_LCDDUAL",      CNTL_LCDDUAL},
> +     {"CNTL_BGR",          CNTL_BGR},
> +     {"CNTL_BEBO",         CNTL_BEBO},
> +     {"CNTL_BEPO",         CNTL_BEPO},
> +     {"CNTL_LCDPWR",       CNTL_LCDPWR},
> +     {"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
> +     {"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
> +     {"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
> +     {"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
> +     {"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
> +     {"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
> +     {"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
> +     {"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
> +     {"CNTL_WATERMARK",    CNTL_WATERMARK},
> +     { NULL, 0},
> +};
> +static struct string_lookup caps_lookups[] = {
> +     {"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
> +     {"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
> +     {"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
> +     {"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
> +     {"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
> +     {"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
> +     {"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
> +     {"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
> +     {"CLCD_CAP_444",     CLCD_CAP_444},
> +     {"CLCD_CAP_5551",    CLCD_CAP_5551},
> +     {"CLCD_CAP_565",     CLCD_CAP_565},
> +     {"CLCD_CAP_888",     CLCD_CAP_888},
> +     {"CLCD_CAP_RGB",     CLCD_CAP_RGB},
> +     {"CLCD_CAP_BGR",     CLCD_CAP_BGR},
> +     {"CLCD_CAP_ALL",     CLCD_CAP_ALL},
> +     { NULL, 0},
> +};
> +
> +u32 parse_setting(struct string_lookup *lookup, const char *name)
> +{
> +     int i = 0;
> +     while (lookup[i].string != NULL) {
> +             if (strcmp(lookup[i].string, name) == 0)
> +                     return lookup[i].val;
> +             ++i;
> +     }
> +     return -EINVAL;
> +}
> +
> +u32 get_string_lookup(struct device_node *node, const char *name,
> +                   struct string_lookup *lookup)
> +{

I have this feeling that swapping the names of the two functions above
would reflect better their actual functionality.

> +     const char *string;
> +     int count, i, ret = 0;
> +
> +     count = of_property_count_strings(node, name);
> +     if (count >= 0)
> +             for (i = 0; i < count; i++)
> +                     if (of_property_read_string_index(node, name, i,
> +                                     &string) == 0)
> +                             ret |= parse_setting(lookup, string);
> +     return ret;
> +}
> +
> +int get_val(struct device_node *node, const char *string)
> +{
> +     u32 ret = 0;
> +
> +     if (of_property_read_u32(node, string, &ret))
> +             ret = -1;
> +     return ret;
> +}
> +
> +struct clcd_panel *getPanel(struct device_node *node)
> +{
> +     static struct clcd_panel panel;
> +
> +     panel.mode.refresh      = get_val(node, "refresh");
> +     panel.mode.xres         = get_val(node, "xres");
> +     panel.mode.yres         = get_val(node, "yres");
> +     panel.mode.pixclock     = get_val(node, "pixclock");
> +     panel.mode.left_margin  = get_val(node, "left_margin");
> +     panel.mode.right_margin = get_val(node, "right_margin");
> +     panel.mode.upper_margin = get_val(node, "upper_margin");
> +     panel.mode.lower_margin = get_val(node, "lower_margin");
> +     panel.mode.hsync_len    = get_val(node, "hsync_len");
> +     panel.mode.vsync_len    = get_val(node, "vsync_len");
> +     panel.mode.sync         = get_val(node, "sync");
> +     panel.bpp               = get_val(node, "bpp");
> +     panel.width             = (signed short) get_val(node, "width");
> +     panel.height            = (signed short) get_val(node, "height");
> +
> +     panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
> +     panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
> +     panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
> +     panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
> +
> +     return &panel;
> +}
> +
> +struct clcd_panel *clcdfb_get_panel(const char *name)
> +{
> +     struct device_node *node = NULL;
> +     const char *mode;
> +     struct clcd_panel *panel = NULL;
> +
> +     do {
> +             node = of_find_compatible_node(node, NULL, "panel");
> +             if (node)
> +                     if (of_property_read_string(node, "mode", &mode) == 0)
> +                             if (strcmp(mode, name) == 0) {
> +                                     panel = getPanel(node);
> +                                     panel->mode.name = name;
> +                             }
> +     } while (node != NULL);
> +
> +     return panel;
> +}
> +
> +#ifdef CONFIG_OF

shouldn't this #ifdef be earlier? you are calling of_property_read_string()
and while there are empty definitions if CONFIG_OF is not defined, the code
will do nothing in that case. Is that intended? The clcdfb_get_panel()
function only gets called if CONFIG_OF *is* defined.


> +static int clcdfb_dt_init(struct clcd_fb *fb)
> +{
> +     int err = 0;
> +     struct device_node *node;
> +     const char *mode;
> +     dma_addr_t dma;
> +     u32 use_dma;
> +     const __be32 *prop;
> +     int len, na, ns;
> +     phys_addr_t fb_base, fb_size;
> +
> +     node = fb->dev->dev.of_node;
> +     if (!node)
> +             return -ENODEV;
> +
> +     na = of_n_addr_cells(node);
> +     ns = of_n_size_cells(node);
> +
> +     if (WARN_ON(of_property_read_string(node, "mode", &mode)))
> +             return -ENODEV;
> +
> +     fb->panel = clcdfb_get_panel(mode);
> +     if (!fb->panel)
> +             return -EINVAL;
> +     fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
> +
> +     if (of_property_read_u32(node, "use_dma", &use_dma))

I haven't seen any documentation for this property. What's the intended use?

> +             use_dma = 0;
> +     if (use_dma) {
> +             fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
> +                     fb->fb.fix.smem_len, &dma, GFP_KERNEL);
> +             if (!fb->fb.screen_base) {
> +                     pr_err("CLCD: unable to map framebuffer\n");
> +                     err = -ENOMEM;
> +             } else
> +                     fb->fb.fix.smem_start   = dma;
> +     } else {
> +             prop = of_get_property(node, "framebuffer", &len);
> +             if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
> +                     return -EINVAL;
> +             fb_base = of_read_number(prop, na);
> +             fb_size = of_read_number(prop + na, ns);
> +
> +             if (memblock_remove(fb_base, fb_size) != 0)
> +                     return -EINVAL;
> +
> +             fb->fb.fix.smem_start = fb_base;
> +             fb->fb.screen_base = ioremap_wc(fb->fb.fix.smem_start, fb_size);
> +     }
> +     return err;
> +}
> +#endif /* CONFIG_OF */
> +
>  static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
>  {
>       struct clcd_board *board = dev->dev.platform_data;
>       struct clcd_fb *fb;
>       int ret;
>
> +#ifdef CONFIG_OF
> +     if (dev->dev.of_node) {
> +             const __be32 *prop;
> +             int len, na, ns;
> +             phys_addr_t reg_base;
> +
> +             na = of_n_addr_cells(dev->dev.of_node);
> +             ns = of_n_size_cells(dev->dev.of_node);
> +
> +             prop = of_get_property(dev->dev.of_node, "reg", &len);
> +             if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
> +                     return -EINVAL;
> +             reg_base = of_read_number(prop, na);
> +
> +             if (dev->res.start != reg_base)
> +                     return -EINVAL;
> +
> +             if (!board) {
> +                     board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
> +                     if (!board)
> +                             return -EINVAL;
> +                     board->name    = "Device Tree CLCD PL111";
> +                     board->caps    = CLCD_CAP_5551 | CLCD_CAP_565;
> +                     board->check   = clcdfb_check;
> +                     board->decode  = clcdfb_decode;
> +                     board->setup   = clcdfb_dt_init;
> +                     board->mmap    = clcdfb_mmap_dma;
> +                     board->remove  = clcdfb_remove_dma;
> +             }
> +     }
> +#endif /* CONFIG_OF */
> +
>       if (!board)
>               return -EINVAL;
>
> --
> 1.7.9.5
>
>

--
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium.  Thank you.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2012-09-20 10:24 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-19 16:04 [RFC PATCH 0/3] amba-clcd: add device tree support Ryan Harkin
2012-09-19 16:04 ` [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver Ryan Harkin
2012-09-20 10:24   ` Liviu Dudau [this message]
     [not found]     ` <20120920102453.GG32603-CibnQJhq84/ZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
2012-09-21 10:35       ` Ryan Harkin
2012-09-21 10:44         ` Pawel Moll
     [not found]   ` <1348070666-9153-2-git-send-email-ryan.harkin-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2012-09-21 11:02     ` Russell King - ARM Linux
2012-09-21 11:43     ` Sascha Hauer
     [not found]       ` <20120921114345.GE24458-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2012-09-21 12:19         ` Russell King - ARM Linux
     [not found]           ` <20120921121903.GE15609-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2012-09-24  7:07             ` Ryan Harkin
2012-10-10 10:13   ` Jon Medhurst (Tixy)
2012-09-19 16:04 ` [RFC PATCH 2/3] ARM: vexpress: Add device tree support for CLCD driver Ryan Harkin
2012-09-19 16:11   ` Pawel Moll
2012-09-19 16:04 ` [RFC PATCH 3/3] ARM: vexpress: configure CLCD driver device tree support for A9 CoreTile Ryan Harkin
2012-09-20 10:29   ` Liviu Dudau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120920102453.GG32603@e102652-lin.cambridge.arm.com \
    --to=liviu.dudau@arm.com \
    --cc=Pawel.Moll@arm.com \
    --cc=arnd.bergmann@linaro.org \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=ryan.harkin@linaro.org \
    --cc=shiraz.hashim@st.com \
    --cc=spear-devel@list.st.com \
    --cc=stigge@antcom.de \
    --cc=tixy@linaro.org \
    --cc=viresh.linux@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).