* Re: [PATCH v4 05/11] drm/sun4i: abstract a engine type
From: Icenowy Zheng @ 2017-04-18 11:05 UTC (permalink / raw)
To: Maxime Ripard
Cc: Rob Herring, Chen-Yu Tsai, David Airlie, Jernej Skrabec,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170418085548.4cisone2yfcuizcp@lukather>
于 2017年4月18日 GMT+08:00 下午4:55:48, Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 写到:
>Hi,
>
>Thanks for that rework.
>
>On Sun, Apr 16, 2017 at 08:08:43PM +0800, Icenowy Zheng wrote:
>> As we are going to add support for the Allwinner DE2 engine in
>sun4i-drm
>> driver, we will finally have two types of display engines -- the DE1
>> backend and the DE2 mixer. They both do some display blending and
>feed
>> graphics data to TCON, so I choose to call them both "engine" here.
>>
>> Abstract the engine type to void * and a ops struct, which contains
>> functions that should be called outside the engine-specified code (in
>> TCON, CRTC or TV Encoder code).
>>
>> A dedicated Kconfig option is also added to control whether
>> sun4i-backend-specified code (sun4i_backend.c and sun4i_layer.c)
>should
>> be built. As we removed the codes in CRTC code that directly call the
>> layer code, we can now extract the layer part and combine it with the
>> backend part into a new module, sun4i-backend.ko.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> ---
>> Changes in v4:
>> - Comments to tag the color correction functions as optional.
>> - Check before calling the optional functions.
>> - Change layers_init to satisfy new PATCH v4 04/11.
>>
>> drivers/gpu/drm/sun4i/Kconfig | 10 ++++++++++
>> drivers/gpu/drm/sun4i/Makefile | 6 ++++--
>> drivers/gpu/drm/sun4i/sun4i_backend.c | 26
>+++++++++++++++++++-------
>> drivers/gpu/drm/sun4i/sun4i_backend.h | 5 -----
>> drivers/gpu/drm/sun4i/sun4i_crtc.c | 14 +++++++-------
>> drivers/gpu/drm/sun4i/sun4i_crtc.h | 7 ++++---
>> drivers/gpu/drm/sun4i/sun4i_drv.h | 3 ++-
>> drivers/gpu/drm/sun4i/sun4i_layer.c | 2 +-
>> drivers/gpu/drm/sun4i/sun4i_layer.h | 3 ++-
>> drivers/gpu/drm/sun4i/sun4i_tcon.c | 2 +-
>> drivers/gpu/drm/sun4i/sun4i_tv.c | 11 ++++++-----
>> drivers/gpu/drm/sun4i/sunxi_engine.h | 35
>+++++++++++++++++++++++++++++++++++
>> 12 files changed, 91 insertions(+), 33 deletions(-)
>> create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h
>>
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig
>b/drivers/gpu/drm/sun4i/Kconfig
>> index a4b357db8856..5a8227f37cc4 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -12,3 +12,13 @@ config DRM_SUN4I
>> Choose this option if you have an Allwinner SoC with a
>> Display Engine. If M is selected the module will be called
>> sun4i-drm.
>> +
>> +config DRM_SUN4I_BACKEND
>> + tristate "Support for Allwinner A10 Display Engine Backend"
>> + depends on DRM_SUN4I
>> + default DRM_SUN4I
>> + help
>> + Choose this option if you have an Allwinner SoC with the
>> + original Allwinner Display Engine, which has a backend to
>> + do some alpha blending and feed graphics to TCON. If M is
>> + selected the module will be called sun4i-backend.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile
>b/drivers/gpu/drm/sun4i/Makefile
>> index 59b757350a1f..1db1068b9be1 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -5,9 +5,11 @@ sun4i-tcon-y += sun4i_tcon.o
>> sun4i-tcon-y += sun4i_rgb.o
>> sun4i-tcon-y += sun4i_dotclock.o
>> sun4i-tcon-y += sun4i_crtc.o
>> -sun4i-tcon-y += sun4i_layer.o
>> +
>> +sun4i-backend-y += sun4i_layer.o
>> +sun4i-backend-y += sun4i_backend.o
>>
>> obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o
>> -obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o
>> +obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
>> obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
>> obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c
>b/drivers/gpu/drm/sun4i/sun4i_backend.c
>> index d660741ba475..a16c96a002a4 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
>> @@ -23,6 +23,8 @@
>>
>> #include "sun4i_backend.h"
>> #include "sun4i_drv.h"
>> +#include "sun4i_layer.h"
>> +#include "sunxi_engine.h"
>>
>> static const u32 sunxi_rgb2yuv_coef[12] = {
>> 0x00000107, 0x00000204, 0x00000064, 0x00000108,
>> @@ -30,9 +32,10 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
>> 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
>> };
>>
>> -void sun4i_backend_apply_color_correction(struct sun4i_backend
>*backend)
>> +static void sun4i_backend_apply_color_correction(void *engine)
>> {
>> int i;
>> + struct sun4i_backend *backend = engine;
>
>I'm not really fond of passing an opaque pointer here, and hope that
>things will work out.
>
>I think having a common structure, holding the common thingsand a more
>specific structure for that one would work better.
>
>Something like
>
>struct sunxi_engine {
> struct regmap *regs;
>};
>
>struct sun4i_backend {
> struct sunxi_engine engine;
>
> struct clk *sat_clk;
> struct reset_control *sat_reset;
>
>};
Sounds good ;-)
>
>static void sun4i_backend_apply_color_correction(struct sunxi_engine
>*engine)
>struct sun4i_backend *backend = container_of(engine, struct
>sun4i_backend, engine);
>
>...
>
>> +static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>> + .commit = sun4i_backend_commit,
>> + .layers_init = sun4i_layers_init,
>> + .apply_color_correction = sun4i_backend_apply_color_correction,
>> + .disable_color_correction = sun4i_backend_disable_color_correction,
>
>Please align the values with tabs, like done in the other structures
>created that way in this driver.
>
>> static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>> @@ -56,7 +55,7 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc
>*crtc,
>>
>> DRM_DEBUG_DRIVER("Committing plane changes\n");
>>
>> - sun4i_backend_commit(scrtc->backend);
>> + scrtc->engine_ops->commit(scrtc->engine);
>
>You rely on the backend having setup things properly, which is pretty
>fragile. Ideally, you should have a function to check that engine_ops
>and commit is !NULL, and call it, and the consumers would use that
>function...
If it's really NULL how should the function return?
>
>> @@ -362,7 +361,9 @@ static void sun4i_tv_disable(struct drm_encoder
>*encoder)
>> regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>> SUN4I_TVE_EN_ENABLE,
>> 0);
>> - sun4i_backend_disable_color_correction(backend);
>> +
>> + if (crtc->engine_ops->disable_color_correction)
>> + crtc->engine_ops->disable_color_correction(crtc->engine);
>> }
>
>... Instead of having to do it in some cases, but not always ...
>
>> static void sun4i_tv_enable(struct drm_encoder *encoder)
>> @@ -370,11 +371,11 @@ static void sun4i_tv_enable(struct drm_encoder
>*encoder)
>> struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>> struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
>> struct sun4i_tcon *tcon = crtc->tcon;
>> - struct sun4i_backend *backend = crtc->backend;
>>
>> DRM_DEBUG_DRIVER("Enabling the TV Output\n");
>>
>> - sun4i_backend_apply_color_correction(backend);
>> + if (crtc->engine_ops->apply_color_correction)
>> + crtc->engine_ops->apply_color_correction(crtc->engine);
>>
>> regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>> SUN4I_TVE_EN_ENABLE,
>> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h
>b/drivers/gpu/drm/sun4i/sunxi_engine.h
>> new file mode 100644
>> index 000000000000..a9128abda66f
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
>> @@ -0,0 +1,35 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUNXI_ENGINE_H_
>> +#define _SUNXI_ENGINE_H_
>> +
>> +struct sun4i_crtc;
>> +
>> +struct sunxi_engine_ops {
>> + /* Commit the changes to the engine */
>> + void (*commit)(void *engine);
>> + /* Initialize layers (planes) for this engine */
>> + struct drm_plane **(*layers_init)(struct drm_device *drm,
>> + struct sun4i_crtc *crtc);
>> +
>> + /*
>> + * These are optional functions for the TV Encoder. Please check
>> + * their presence before calling them.
>> + *
>> + * The first function applies the color space correction needed
>> + * for outputing correct TV signal.
>> + *
>> + * The second function disabled the correction.
>> + */
>> + void (*apply_color_correction)(void *engine);
>> + void (*disable_color_correction)(void *engine);
>
>... And have to document it.
>
>Please also use kerneldoc for those comments.
>
>Thanks again!
>Maxime
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH v13 03/10] mux: minimal mux subsystem and gpio-based mux controller
From: Peter Rosin @ 2017-04-18 10:59 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-kernel, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, linux-i2c, devicetree,
linux-iio, linux-doc, Andrew Morton, Colin Ian King,
Paul Gortmaker, Philipp Zabel, kernel
In-Reply-To: <20170418085156.GA4773@kroah.com>
On 2017-04-18 10:51, Greg Kroah-Hartman wrote:
> On Thu, Apr 13, 2017 at 06:43:07PM +0200, Peter Rosin wrote:
>> +config MUX_GPIO
>> + tristate "GPIO-controlled Multiplexer"
>> + depends on OF && GPIOLIB
>
> Why have the gpio and mux core in the same patch?
One is not usable w/o the other. I can split them if you want to?
> And why does this depend on OF?
That's historical, I was originally using of_property_read_u32.
I'll remove the dep...
>> + help
>> + GPIO-controlled Multiplexer controller.
>> +
>> + The driver builds a single multiplexer controller using a number
>> + of gpio pins. For N pins, there will be 2^N possible multiplexer
>> + states. The GPIO pins can be connected (by the hardware) to several
>> + multiplexers, which in that case will be operated in parallel.
>> +
>> + To compile the driver as a module, choose M here: the module will
>> + be called mux-gpio.
>> +
>> +endif
>> diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
>> new file mode 100644
>> index 000000000000..bb16953f6290
>> --- /dev/null
>> +++ b/drivers/mux/Makefile
>> @@ -0,0 +1,6 @@
>> +#
>> +# Makefile for multiplexer devices.
>> +#
>> +
>> +obj-$(CONFIG_MULTIPLEXER) += mux-core.o
>> +obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
>> diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
>> new file mode 100644
>> index 000000000000..66a8bccfc3d7
>> --- /dev/null
>> +++ b/drivers/mux/mux-core.c
>> @@ -0,0 +1,422 @@
>> +/*
>> + * Multiplexer subsystem
>> + *
>> + * Copyright (C) 2017 Axentia Technologies AB
>> + *
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#define pr_fmt(fmt) "mux-core: " fmt
>> +
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/idr.h>
>> +#include <linux/init.h>
>> +#include <linux/module.h>
>> +#include <linux/mux.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/slab.h>
>> +
>> +/*
>> + * The idle-as-is "state" is not an actual state that may be selected, it
>> + * only implies that the state should not be changed. So, use that state
>> + * as indication that the cached state of the multiplexer is unknown.
>> + */
>> +#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS
>> +
>> +static struct class mux_class = {
>> + .name = "mux",
>> + .owner = THIS_MODULE,
>> +};
>
> No Documentation/ABI/ update for your sysfs files? Please do so.
Ok I'll look into it. Wasn't even aware that I added any. But there's the
new class of course...
>> +
>> +static int __init mux_init(void)
>> +{
>> + return class_register(&mux_class);
>> +}
>> +
>> +static DEFINE_IDA(mux_ida);
>
> When your module is unloaded, you forgot to clean this structure up with
> what was done with it.
I was under the impression that not providing an exit function for modules
made the module infrastructure prevent unloading (by bumping some reference
counter). Maybe that is a misconception?
>> +
>> +static void mux_chip_release(struct device *dev)
>> +{
>> + struct mux_chip *mux_chip = to_mux_chip(dev);
>> +
>> + ida_simple_remove(&mux_ida, mux_chip->id);
>> + kfree(mux_chip);
>> +}
>> +
>> +static struct device_type mux_type = {
>> + .name = "mux-chip",
>> + .release = mux_chip_release,
>> +};
>> +
>> +struct mux_chip *mux_chip_alloc(struct device *dev,
>> + unsigned int controllers, size_t sizeof_priv)
>> +{
>> + struct mux_chip *mux_chip;
>> + int i;
>> +
>> + if (WARN_ON(!dev || !controllers))
>> + return NULL;
>> +
>> + mux_chip = kzalloc(sizeof(*mux_chip) +
>> + controllers * sizeof(*mux_chip->mux) +
>> + sizeof_priv, GFP_KERNEL);
>> + if (!mux_chip)
>> + return NULL;
>
> You don't return PTR_ERR(-ENOMEM)? Ok, why not? (I'm not arguing for
> it, just curious...)
There's no particular reason. Do you think I should change it?
>> +
>> + mux_chip->mux = (struct mux_control *)(mux_chip + 1);
>> + mux_chip->dev.class = &mux_class;
>> + mux_chip->dev.type = &mux_type;
>> + mux_chip->dev.parent = dev;
>> + mux_chip->dev.of_node = dev->of_node;
>> + dev_set_drvdata(&mux_chip->dev, mux_chip);
>> +
>> + mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
>> + if (mux_chip->id < 0) {
>> + pr_err("muxchipX failed to get a device id\n");
>> + kfree(mux_chip);
>> + return NULL;
>> + }
>> + dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id);
>> +
>> + mux_chip->controllers = controllers;
>> + for (i = 0; i < controllers; ++i) {
>> + struct mux_control *mux = &mux_chip->mux[i];
>> +
>> + mux->chip = mux_chip;
>> + init_rwsem(&mux->lock);
>> + mux->cached_state = MUX_CACHE_UNKNOWN;
>> + mux->idle_state = MUX_IDLE_AS_IS;
>> + }
>> +
>> + device_initialize(&mux_chip->dev);
>
> Why are you not registering the device here as well? Why have this be a
> two step process?
Because of idle state handling. The drivers are expected to fill in
the desired idle state(s) after allocating the mux controller(s).
Then, when registering, the desired idle state is activated (if the
idle state is not idle-as-is, of course) and as a last step the mux
is "advertised".
>> +
>> + return mux_chip;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_chip_alloc);
>> +
>> +static int mux_control_set(struct mux_control *mux, int state)
>> +{
>> + int ret = mux->chip->ops->set(mux, state);
>> +
>> + mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state;
>> +
>> + return ret;
>> +}
>> +
>> +int mux_chip_register(struct mux_chip *mux_chip)
>> +{
>> + int i;
>> + int ret;
>> +
>> + for (i = 0; i < mux_chip->controllers; ++i) {
>> + struct mux_control *mux = &mux_chip->mux[i];
>> +
>> + if (mux->idle_state == mux->cached_state)
>> + continue;
>> +
>> + ret = mux_control_set(mux, mux->idle_state);
>> + if (ret < 0) {
>> + dev_err(&mux_chip->dev, "unable to set idle state\n");
>> + return ret;
>> + }
>> + }
>> +
>> + ret = device_add(&mux_chip->dev);
>> + if (ret < 0)
>> + dev_err(&mux_chip->dev,
>> + "device_add failed in mux_chip_register: %d\n", ret);
>
> Did you run checkpatch.pl in strict mode on this new file? Please do so :)
I did, and did it again just to be sure, and I do not get any complaints.
So, what's wrong?
$ scripts/checkpatch.pl --strict mux-13/0003-mux-minimal-mux-subsystem-and-gpio-based-mux-control.patch
total: 0 errors, 0 warnings, 0 checks, 860 lines checked
mux-13/0003-mux-minimal-mux-subsystem-and-gpio-based-mux-control.patch has no obvious style problems and is ready for submission.
The chackpatch warnings I am aware of are three instances of (for the
'prop', 's' and 'i' arguments):
mux-13/0006-iio-multiplexer-new-iio-category-and-iio-mux-driver.patch
---------------------------------------------------------------------
CHECK: Macro argument reuse 'prop' - possible side-effects?
#433: FILE: drivers/iio/multiplexer/iio-mux.c:326:
+#define of_property_for_each_string_index(np, propname, prop, s, i) \
+ for (prop = of_find_property(np, propname, NULL), \
+ s = of_prop_next_string(prop, NULL), \
+ i = 0; \
+ s; \
+ s = of_prop_next_string(prop, s), \
+ i++)
But those kinds of warnings are also present in the code I plagiarized,
so I don't feel too bad...
And then there are a couple of false positives about files added w/o
adding an entry to MAINTAINERS (the files are covers by wildcards).
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_chip_register);
>> +
>> +void mux_chip_unregister(struct mux_chip *mux_chip)
>> +{
>> + device_del(&mux_chip->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_chip_unregister);
>> +
>> +void mux_chip_free(struct mux_chip *mux_chip)
>> +{
>> + if (!mux_chip)
>> + return;
>> +
>> + put_device(&mux_chip->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_chip_free);
>> +
>> +static void devm_mux_chip_release(struct device *dev, void *res)
>> +{
>> + struct mux_chip *mux_chip = *(struct mux_chip **)res;
>> +
>> + mux_chip_free(mux_chip);
>> +}
>> +
>> +struct mux_chip *devm_mux_chip_alloc(struct device *dev,
>> + unsigned int controllers,
>> + size_t sizeof_priv)
>> +{
>> + struct mux_chip **ptr, *mux_chip;
>> +
>> + ptr = devres_alloc(devm_mux_chip_release, sizeof(*ptr), GFP_KERNEL);
>> + if (!ptr)
>> + return NULL;
>> +
>> + mux_chip = mux_chip_alloc(dev, controllers, sizeof_priv);
>> + if (!mux_chip) {
>> + devres_free(ptr);
>> + return NULL;
>> + }
>> +
>> + *ptr = mux_chip;
>> + devres_add(dev, ptr);
>> +
>> + return mux_chip;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_chip_alloc);
>
>
> Having devm functions that create/destroy other struct devices worries
> me, do we have other examples of this happening today? Are you sure you
> got the reference counting all correct?
drivers/iio/industrialio_core.c:devm_iio_device_alloc
Or is the iio case different in some subtle way that I'm missing?
>> +
>> +static int devm_mux_chip_match(struct device *dev, void *res, void *data)
>> +{
>> + struct mux_chip **r = res;
>> +
>> + if (WARN_ON(!r || !*r))
>
> How can this happen?
It shouldn't. I copied the pattern from the iio subsystem.
>> + return 0;
>> +
>> + return *r == data;
>> +}
>> +
>> +void devm_mux_chip_free(struct device *dev, struct mux_chip *mux_chip)
>> +{
>> + WARN_ON(devres_release(dev, devm_mux_chip_release,
>> + devm_mux_chip_match, mux_chip));
>
> What can someone do with these WARN_ON() splats in the kernel log?
Don't know. Again, I copied the pattern from the iio subsystem.
>
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_chip_free);
>> +
>> +static void devm_mux_chip_reg_release(struct device *dev, void *res)
>> +{
>> + struct mux_chip *mux_chip = *(struct mux_chip **)res;
>> +
>> + mux_chip_unregister(mux_chip);
>> +}
>> +
>> +int devm_mux_chip_register(struct device *dev,
>> + struct mux_chip *mux_chip)
>> +{
>> + struct mux_chip **ptr;
>> + int res;
>> +
>> + ptr = devres_alloc(devm_mux_chip_reg_release, sizeof(*ptr), GFP_KERNEL);
>> + if (!ptr)
>> + return -ENOMEM;
>> +
>> + res = mux_chip_register(mux_chip);
>> + if (res) {
>> + devres_free(ptr);
>> + return res;
>> + }
>> +
>> + *ptr = mux_chip;
>> + devres_add(dev, ptr);
>> +
>> + return res;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_chip_register);
>> +
>> +void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip)
>> +{
>> + WARN_ON(devres_release(dev, devm_mux_chip_reg_release,
>> + devm_mux_chip_match, mux_chip));
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_chip_unregister);
>> +
>> +int mux_control_select(struct mux_control *mux, int state)
>> +{
>> + int ret;
>> +
>> + if (down_read_trylock(&mux->lock)) {
>> + if (mux->cached_state == state)
>> + return 0;
>> +
>> + /* Sigh, the mux needs updating... */
>> + up_read(&mux->lock);
>> + }
>> +
>> + /* ...or it's just contended. */
>> + down_write(&mux->lock);
>
> Why use a read/write lock at all? Have you tested this to verify it
> really is faster and needed?
For one of the HW configuration that drove the development, the same mux
controller is used to mux both an I2C channel and a couple of ADC lines.
If there is no kind of reader/writer locking going on, there is no way to
do ADC readings concurrently with an I2C transfer even when the consumers
want the mux in the same position. With an ordinary mutex controlling the
mux position, the consumers will unconditionally get serialized, which
seems like a waste to me. Or maybe I'm missing something?
>> +
>> + if (mux->cached_state == state) {
>> + /*
>> + * Hmmm, someone else changed the mux to my liking.
>> + * That makes me wonder how long I waited for nothing?
>> + */
>> + downgrade_write(&mux->lock);
>
> Oh that always scares me... Are you _sure_ this is correct? And
> needed?
It might not be needed, and it would probably work ok to just fall
through and call mux_control_set unconditionally. What is it that
always scares you exactly? Relying on cached state to be correct?
Downgrading writer locks?
>> + return 0;
>> + }
>> +
>> + ret = mux_control_set(mux, state);
>> + if (ret < 0) {
>> + if (mux->idle_state != MUX_IDLE_AS_IS)
>> + mux_control_set(mux, mux->idle_state);
>> +
>> + up_write(&mux->lock);
>> + return ret;
>> + }
>> +
>> + downgrade_write(&mux->lock);
>> +
>> + return 1;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_select);
>> +
>> +int mux_control_deselect(struct mux_control *mux)
>> +{
>> + int ret = 0;
>> +
>> + if (mux->idle_state != MUX_IDLE_AS_IS &&
>> + mux->idle_state != mux->cached_state)
>> + ret = mux_control_set(mux, mux->idle_state);
>> +
>> + up_read(&mux->lock);
>
> You require a lock to be held for a "global" function? Without
> documentation? Or even a sparse marking? That's asking for trouble...
Documentation I can handle, but where should I look to understand how I
should add sparse markings?
The mux needs to be locked somehow. But as I stated in the cover letter
the rwsem isn't a perfect fit.
I'm using an rwsem to lock a mux, but that isn't really a
perfect fit. Is there a better locking primitive that I don't
know about that fits better? I had a mutex at one point, but
that didn't allow any concurrent accesses at all. At least
the rwsem allows concurrent access as long as all users
agree on the mux state, but I suspect that the rwsem will
degrade to the mutex situation pretty quickly if there is
any contention.
Also, the lock doesn't add anything if there is only one consumer of
a mux controller. Maybe there should be some mechanism for shortcutting
the locking for the (more common?) single-consumer case?
But again, I need the locking for my multi-consumer use case.
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_deselect);
>> +
>> +static int of_dev_node_match(struct device *dev, const void *data)
>> +{
>> + return dev->of_node == data;
>> +}
>> +
>> +static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
>> +{
>> + struct device *dev;
>> +
>> + dev = class_find_device(&mux_class, NULL, np, of_dev_node_match);
>> +
>> + return dev ? to_mux_chip(dev) : NULL;
>> +}
>> +
>> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +{
>> + struct device_node *np = dev->of_node;
>> + struct of_phandle_args args;
>> + struct mux_chip *mux_chip;
>> + unsigned int controller;
>> + int index = 0;
>> + int ret;
>> +
>> + if (mux_name) {
>> + index = of_property_match_string(np, "mux-control-names",
>> + mux_name);
>> + if (index < 0) {
>> + dev_err(dev, "mux controller '%s' not found\n",
>> + mux_name);
>> + return ERR_PTR(index);
>> + }
>> + }
>> +
>> + ret = of_parse_phandle_with_args(np,
>> + "mux-controls", "#mux-control-cells",
>> + index, &args);
>> + if (ret) {
>> + dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
>> + np->full_name, mux_name ?: "", index);
>> + return ERR_PTR(ret);
>> + }
>> +
>> + mux_chip = of_find_mux_chip_by_node(args.np);
>> + of_node_put(args.np);
>> + if (!mux_chip)
>> + return ERR_PTR(-EPROBE_DEFER);
>> +
>> + if (args.args_count > 1 ||
>> + (!args.args_count && (mux_chip->controllers > 1))) {
>> + dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
>> + np->full_name, args.np->full_name);
>> + return ERR_PTR(-EINVAL);
>> + }
>> +
>> + controller = 0;
>> + if (args.args_count)
>> + controller = args.args[0];
>> +
>> + if (controller >= mux_chip->controllers) {
>> + dev_err(dev, "%s: bad mux controller %u specified in %s\n",
>> + np->full_name, controller, args.np->full_name);
>> + return ERR_PTR(-EINVAL);
>> + }
>> +
>> + get_device(&mux_chip->dev);
>> + return &mux_chip->mux[controller];
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_get);
>> +
>> +void mux_control_put(struct mux_control *mux)
>> +{
>> + put_device(&mux->chip->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_put);
>> +
>> +static void devm_mux_control_release(struct device *dev, void *res)
>> +{
>> + struct mux_control *mux = *(struct mux_control **)res;
>> +
>> + mux_control_put(mux);
>> +}
>> +
>> +struct mux_control *devm_mux_control_get(struct device *dev,
>> + const char *mux_name)
>> +{
>> + struct mux_control **ptr, *mux;
>> +
>> + ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL);
>> + if (!ptr)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + mux = mux_control_get(dev, mux_name);
>> + if (IS_ERR(mux)) {
>> + devres_free(ptr);
>> + return mux;
>> + }
>> +
>> + *ptr = mux;
>> + devres_add(dev, ptr);
>> +
>> + return mux;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_control_get);
>> +
>> +static int devm_mux_control_match(struct device *dev, void *res, void *data)
>> +{
>> + struct mux_control **r = res;
>> +
>> + if (WARN_ON(!r || !*r))
>> + return 0;
>
> Same here, how can this happen?
Same response as above.
>> +
>> + return *r == data;
>> +}
>> +
>> +void devm_mux_control_put(struct device *dev, struct mux_control *mux)
>> +{
>> + WARN_ON(devres_release(dev, devm_mux_control_release,
>> + devm_mux_control_match, mux));
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_control_put);
>> +
>> +/*
>> + * Using subsys_initcall instead of module_init here to ensure - for the
>> + * non-modular case - that the subsystem is initialized when mux consumers
>> + * and mux controllers start to use it /without/ relying on link order.
>> + * For the modular case, the ordering is ensured with module dependencies.
>> + */
>> +subsys_initcall(mux_init);
>
> Even with subsys_initcall you are relying on link order, you do realize
> that? What about other subsystems that rely on this? :)
Yes, that is true, but if others start relying on this, that's their problem,
right? :-)
>
>> +
>> +MODULE_DESCRIPTION("Multiplexer subsystem");
>> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
>> new file mode 100644
>> index 000000000000..227d3572e6db
>> --- /dev/null
>> +++ b/drivers/mux/mux-gpio.c
>> @@ -0,0 +1,114 @@
>> +/*
>> + * GPIO-controlled multiplexer driver
>> + *
>> + * Copyright (C) 2017 Axentia Technologies AB
>> + *
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/module.h>
>> +#include <linux/mux.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/property.h>
>> +
>> +struct mux_gpio {
>> + struct gpio_descs *gpios;
>> + int *val;
>> +};
>> +
>> +static int mux_gpio_set(struct mux_control *mux, int state)
>> +{
>> + struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
>> + int i;
>> +
>> + for (i = 0; i < mux_gpio->gpios->ndescs; i++)
>> + mux_gpio->val[i] = (state >> i) & 1;
>> +
>> + gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
>> + mux_gpio->gpios->desc,
>> + mux_gpio->val);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct mux_control_ops mux_gpio_ops = {
>> + .set = mux_gpio_set,
>> +};
>> +
>> +static const struct of_device_id mux_gpio_dt_ids[] = {
>> + { .compatible = "gpio-mux", },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
>> +
>> +static int mux_gpio_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct mux_chip *mux_chip;
>> + struct mux_gpio *mux_gpio;
>> + int pins;
>> + s32 idle_state;
>> + int ret;
>> +
>> + pins = gpiod_count(dev, "mux");
>> + if (pins < 0)
>> + return pins;
>> +
>> + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>> + pins * sizeof(*mux_gpio->val));
>> + if (!mux_chip)
>> + return -ENOMEM;
>> +
>> + mux_gpio = mux_chip_priv(mux_chip);
>> + mux_gpio->val = (int *)(mux_gpio + 1);
>> + mux_chip->ops = &mux_gpio_ops;
>> +
>> + mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
>> + if (IS_ERR(mux_gpio->gpios)) {
>> + ret = PTR_ERR(mux_gpio->gpios);
>> + if (ret != -EPROBE_DEFER)
>> + dev_err(dev, "failed to get gpios\n");
>> + return ret;
>> + }
>> + WARN_ON(pins != mux_gpio->gpios->ndescs);
>> + mux_chip->mux->states = 1 << pins;
>> +
>> + ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state);
>> + if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) {
>> + if (idle_state < 0 || idle_state >= mux_chip->mux->states) {
>> + dev_err(dev, "invalid idle-state %u\n", idle_state);
>> + return -EINVAL;
>> + }
>> +
>> + mux_chip->mux->idle_state = idle_state;
>> + }
>> +
>> + ret = devm_mux_chip_register(dev, mux_chip);
>> + if (ret < 0)
>> + return ret;
>> +
>> + dev_info(dev, "%u-way mux-controller registered\n",
>> + mux_chip->mux->states);
>> +
>> + return 0;
>> +}
>> +
>> +static struct platform_driver mux_gpio_driver = {
>> + .driver = {
>> + .name = "gpio-mux",
>> + .of_match_table = of_match_ptr(mux_gpio_dt_ids),
>> + },
>> + .probe = mux_gpio_probe,
>> +};
>> +module_platform_driver(mux_gpio_driver);
>> +
>> +MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
>> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/mux.h b/include/linux/mux.h
>> new file mode 100644
>> index 000000000000..febdde4246df
>> --- /dev/null
>> +++ b/include/linux/mux.h
>> @@ -0,0 +1,252 @@
>> +/*
>> + * mux.h - definitions for the multiplexer interface
>> + *
>> + * Copyright (C) 2017 Axentia Technologies AB
>> + *
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef _LINUX_MUX_H
>> +#define _LINUX_MUX_H
>> +
>> +#include <linux/device.h>
>> +#include <linux/rwsem.h>
>> +
>> +struct mux_chip;
>> +struct mux_control;
>> +struct platform_device;
>> +
>> +/**
>> + * struct mux_control_ops - Mux controller operations for a mux chip.
>> + * @set: Set the state of the given mux controller.
>> + */
>> +struct mux_control_ops {
>> + int (*set)(struct mux_control *mux, int state);
>> +};
>> +
>> +/* These defines match the constants from the dt-bindings. On purpose. */
>
> Why on purpose?
I sure wasn't an accident? :-)
Want me to remove it?
>> +#define MUX_IDLE_AS_IS (-1)
>> +#define MUX_IDLE_DISCONNECT (-2)
>> +
>> +/**
>> + * struct mux_control - Represents a mux controller.
>> + * @lock: Protects the mux controller state.
>> + * @chip: The mux chip that is handling this mux controller.
>> + * @states: The number of mux controller states.
>> + * @cached_state: The current mux controller state, or -1 if none.
>> + * @idle_state: The mux controller state to use when inactive, or one
>> + * of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
>> + */
>> +struct mux_control {
>> + struct rw_semaphore lock; /* protects the state of the mux */
>> +
>> + struct mux_chip *chip;
>> +
>> + unsigned int states;
>> + int cached_state;
>> + int idle_state;
>> +};
>> +
>> +/**
>> + * struct mux_chip - Represents a chip holding mux controllers.
>> + * @controllers: Number of mux controllers handled by the chip.
>> + * @mux: Array of mux controllers that are handled.
>> + * @dev: Device structure.
>> + * @id: Used to identify the device internally.
>> + * @ops: Mux controller operations.
>> + */
>> +struct mux_chip {
>> + unsigned int controllers;
>> + struct mux_control *mux;
>> + struct device dev;
>> + int id;
>> +
>> + const struct mux_control_ops *ops;
>> +};
>> +
>> +#define to_mux_chip(x) container_of((x), struct mux_chip, dev)
>> +
>> +/**
>> + * mux_chip_priv() - Get the extra memory reserved by mux_chip_alloc().
>> + * @mux_chip: The mux-chip to get the private memory from.
>> + *
>> + * Return: Pointer to the private memory reserved by the allocator.
>> + */
>> +static inline void *mux_chip_priv(struct mux_chip *mux_chip)
>> +{
>> + return &mux_chip->mux[mux_chip->controllers];
>> +}
>> +
>> +/**
>> + * mux_chip_alloc() - Allocate a mux-chip.
>> + * @dev: The parent device implementing the mux interface.
>> + * @controllers: The number of mux controllers to allocate for this chip.
>> + * @sizeof_priv: Size of extra memory area for private use by the caller.
>> + *
>> + * Return: A pointer to the new mux-chip, NULL on failure.
>> + */
>> +struct mux_chip *mux_chip_alloc(struct device *dev,
>> + unsigned int controllers, size_t sizeof_priv);
>> +
>
> Don't put kernel doc comments in a .h file, they normally go into the .c
> file, next to the code itself. That makes it easier to fix up and
> realise when they need to be changed when the code changes. The .h file
> rarely changes.
I'll move the lot over.
>> +/**
>> + * mux_chip_register() - Register a mux-chip, thus readying the controllers
>> + * for use.
>> + * @mux_chip: The mux-chip to register.
>> + *
>> + * Do not retry registration of the same mux-chip on failure. You should
>> + * instead put it away with mux_chip_free() and allocate a new one, if you
>> + * for some reason would like to retry registration.
>> + *
>> + * Return: Zero on success or a negative errno on error.
>> + */
>> +int mux_chip_register(struct mux_chip *mux_chip);
>> +
>> +/**
>> + * mux_chip_unregister() - Take the mux-chip off-line.
>> + * @mux_chip: The mux-chip to unregister.
>> + *
>> + * mux_chip_unregister() reverses the effects of mux_chip_register().
>> + * But not completely, you should not try to call mux_chip_register()
>> + * on a mux-chip that has been registered before.
>> + */
>> +void mux_chip_unregister(struct mux_chip *mux_chip);
>> +
>> +/**
>> + * mux_chip_free() - Free the mux-chip for good.
>> + * @mux_chip: The mux-chip to free.
>> + *
>> + * mux_chip_free() reverses the effects of mux_chip_alloc().
>> + */
>> +void mux_chip_free(struct mux_chip *mux_chip);
>> +
>> +/**
>> + * devm_mux_chip_alloc() - Resource-managed version of mux_chip_alloc().
>> + * @dev: The parent device implementing the mux interface.
>> + * @controllers: The number of mux controllers to allocate for this chip.
>> + * @sizeof_priv: Size of extra memory area for private use by the caller.
>> + *
>> + * See mux_chip_alloc() for more details.
>> + *
>> + * Return: A pointer to the new mux-chip, NULL on failure.
>> + */
>> +struct mux_chip *devm_mux_chip_alloc(struct device *dev,
>> + unsigned int controllers,
>> + size_t sizeof_priv);
>> +
>> +/**
>> + * devm_mux_chip_register() - Resource-managed version mux_chip_register().
>> + * @dev: The parent device implementing the mux interface.
>> + * @mux_chip: The mux-chip to register.
>> + *
>> + * See mux_chip_register() for more details.
>> + *
>> + * Return: Zero on success or a negative errno on error.
>> + */
>> +int devm_mux_chip_register(struct device *dev, struct mux_chip *mux_chip);
>> +
>> +/**
>> + * devm_mux_chip_unregister() - Resource-managed version mux_chip_unregister().
>> + * @dev: The device that originally registered the mux-chip.
>> + * @mux_chip: The mux-chip to unregister.
>> + *
>> + * See mux_chip_unregister() for more details.
>> + *
>> + * Note that you do not normally need to call this function.
>
> Odd, then why is it exported???
You normally don't call the devm_foo_{free,release,unregister,etc} functions.
The intention is of course that the resourse cleans up automatically. But there
are no cases where the manual clean up is not available, at least not that I can
find?
>> + */
>> +void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip);
>> +
>> +/**
>> + * devm_mux_chip_free() - Resource-managed version mux_chip_free().
>> + * @dev: The device that originally got the mux-chip.
>> + * @mux_chip: The mux-chip to free.
>> + *
>> + * See mux_chip_free() for more details.
>> + *
>> + * Note that you do not normally need to call this function.
>> + */
>> +void devm_mux_chip_free(struct device *dev, struct mux_chip *mux_chip);
>> +
>> +/**
>> + * mux_control_select() - Select the given multiplexer state.
>> + * @mux: The mux-control to request a change of state from.
>> + * @state: The new requested state.
>> + *
>> + * Make sure to call mux_control_deselect() when the operation is complete and
>> + * the mux-control is free for others to use, but do not call
>> + * mux_control_deselect() if mux_control_select() fails.
>> + *
>> + * Return: 0 if the requested state was already active, or 1 it the
>> + * mux-control state was changed to the requested state. Or a negative
>> + * errno on error.
>> + *
>> + * Note that the difference in return value of zero or one is of
>> + * questionable value; especially if the mux-control has several independent
>> + * consumers, which is something the consumers should perhaps not be making
>> + * assumptions about.
>
> I don't understand this note, what is a user of this api supposed to do
> differently between 1 and 0? Why make the difference at all?
If the consumer somehow *knows* that it is the only user of a mux controller,
it can use the return value to shortcut (perhaps costly) actions only needed
when the mux changes. The 1/0 difference was also a "free" extra given the
current implementation of mux_control_select. But it's cheep for the consumer
to keep track of this by itself if it needs it.
It's when there are several (independent) consumers of a mux controller that
the information in the return value is questionable and can't be used to
shortcut actions only needed on mux changes.
Now that you point the finger at it and I have been made to spell out the
problem, I think it's probably wise to remove the distiction so that users
do not start to use the return value when they shouldn't. It's generally
better to keep track of the expected mux state in the consumer and use that
local information to shortcut those (perhaps costly) actions instead.
> And I agree with the comment to split this up into 2 different .h files,
> if possible.
Will split.
> thanks,
>
> greg k-h
>
I'll wait for further feedback before posting a v14.
Cheers and thanks,
peda
^ permalink raw reply
* Re: Re: [PATCH v3 02/12] arm64: allwinner: a64: add NMI controller on A64
From: Icenowy Zheng @ 2017-04-18 10:56 UTC (permalink / raw)
To: maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
Cc: Lee Jones, Rob Herring, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170418070016.qsng3qtk76bqxyc5@lukather>
于 2017年4月18日 GMT+08:00 下午3:00:16, Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 写到:
>On Mon, Apr 17, 2017 at 07:57:37PM +0800, Icenowy Zheng wrote:
>> Allwinner A64 SoC features a NMI controller, which is usually
>connected
>> to the AXP PMIC.
>>
>> Add support for it.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>> ---
>> Changes in v2:
>> - Added Chen-Yu's ACK.
>>
>> arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 8 ++++++++
>> 1 file changed, 8 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> index 05ec9fc5e81f..53c18ca372ea 100644
>> --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> @@ -403,6 +403,14 @@
>> <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
>> };
>>
>> + nmi_intc: interrupt-controller@01f00c0c {
>> + compatible = "allwinner,sun6i-a31-sc-nmi";
>> + interrupt-controller;
>> + #interrupt-cells = <2>;
>> + reg = <0x01f00c0c 0x38>;
>
>The base address is not correct, and there's uncertainty on whether
>this is this particular controller or not. Did you even test this?
Tested by axp20x-pek.
>
>Maxime
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH v3 09/12] mfd: axp20x: add axp20x-regulator cell for AXP803
From: Icenowy Zheng @ 2017-04-18 10:55 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Lee Jones, Rob Herring, Maxime Ripard, Liam Girdwood, Mark Brown,
devicetree, linux-kernel, linux-arm-kernel, linux-sunxi
In-Reply-To: <CAGb2v648fhGSjWoVYRxU+_kF5fhbnhmY2mQG16ORtBHf7pGx5w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
于 2017年4月18日 GMT+08:00 下午6:38:09, Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org> 写到:
>On Mon, Apr 17, 2017 at 7:57 PM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
>> As axp20x-regulator now supports AXP803, add a cell for it.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> ---
>> Changes in v3:
>> - Make the new cell one-liner.
>>
>> drivers/mfd/axp20x.c | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
>> index 1dc6235778eb..431b7f118606 100644
>> --- a/drivers/mfd/axp20x.c
>> +++ b/drivers/mfd/axp20x.c
>> @@ -848,7 +848,8 @@ static struct mfd_cell axp803_cells[] = {
>> .name = "axp20x-pek",
>> .num_resources =
>ARRAY_SIZE(axp803_pek_resources),
>> .resources = axp803_pek_resources,
>> - }
>> + },
>> + { .name = "axp20x-regulator" }
>
>It's best to have a trailing comma, so we don't have to change the line
>again when we add more cells, like you just did with the previous line.
Should I also add it in previous mfd patch? (and remove the addition of the comma in this patch)
>
>Otherwise,
>
>Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Sakari Ailus @ 2017-04-18 10:55 UTC (permalink / raw)
To: Pavel Machek
Cc: Philipp Zabel, Peter Rosin, Rob Herring, Mark Rutland,
Steve Longerbeam, devicetree, linux-kernel, kernel
In-Reply-To: <20170418103453.GC14505@amd>
On Tue, Apr 18, 2017 at 12:34:53PM +0200, Pavel Machek wrote:
> On Tue 2017-04-18 13:08:41, Sakari Ailus wrote:
> > Hi Philipp,
> >
> > On Tue, Apr 18, 2017 at 10:19:04AM +0200, Philipp Zabel wrote:
> > > On Thu, 2017-04-13 at 17:48 +0200, Philipp Zabel wrote:
> > > > This adds device tree binding documentation for mmio-based syscon
> > > > multiplexers controlled by a single bitfield in a syscon register
> > > > range.
> > > >
> > > > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> > > > ---
> > > > Documentation/devicetree/bindings/mux/mmio-mux.txt | 56 ++++++++++++++++++++++
> > > > 1 file changed, 56 insertions(+)
> > > > create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > > new file mode 100644
> > > > index 0000000000000..11d96f5d98583
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > > @@ -0,0 +1,56 @@
> > > > +MMIO bitfield-based multiplexer controller bindings
> > > > +
> > > > +Define a syscon bitfield to be used to control a multiplexer. The parent
> > > > +device tree node must be a syscon node to provide register access.
> > > > +
> > > > +Required properties:
> > > > +- compatible : "gpio-mux"
> > > > +- reg : register base of the register containing the control bitfield
> > > > +- bit-mask : bitmask of the control bitfield in the control register
> > > > +- bit-shift : bit offset of the control bitfield in the control register
> > > > +- #mux-control-cells : <0>
> > > > +* Standard mux-controller bindings as decribed in mux-controller.txt
> > > > +
> > > > +Optional properties:
> > > > +- idle-state : if present, the state the mux will have when idle. The
> > > > + special state MUX_IDLE_AS_IS is the default.
> > > > +
> > > > +The multiplexer state is defined as the value of the bitfield described
> > > > +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> > > > +syscon.
> > > > +
> > > > +Example:
> > > > +
> > > > + syscon {
> > > > + compatible = "syscon";
> > > > +
> > > > + mux: mux-controller@3 {
> > > > + compatible = "mmio-mux";
> > > > + reg = <0x3>;
> > > > + bit-mask = <0x1>;
> > > > + bit-shift = <5>;
> > > > + #mux-control-cells = <0>;
> > > > + };
> > > > + };
> > > > +
> > > > + video-mux {
> > > > + compatible = "video-mux";
> > > > + mux-controls = <&mux>;
> > > > +
> > > > + ports {
> > > > + /* input 0 */
> > > > + port@0 {
> > > > + reg = <0>;
> > > > + };
> > > > +
> > > > + /* input 1 */
> > > > + port@1 {
> > > > + reg = <1>;
> > > > + };
> > > > +
> > > > + /* output */
> > > > + port@2 {
> > > > + reg = <2>;
> > > > + };
> > > > + };
> > > > + };
> > >
> > > So Pavel (added to Cc:) suggested to merge these into one node for the
> > > video mux, as really we are describing a single hardware entity that
> > > happens to be multiplexing multiple video buses into one:
> >
> > Two drivers will be needed in a way or another to disconnect the dependency
> > between the video switch driver and the MUX implementation. Are there ways
> > to do that cleanly other than having two devices?
>
> Yes.
>
> Device tree describes hardware, not the driver structure.
I think you you could view the MUX control as a device, too, and that's
separate from the actual video switch.
This isn't really related to the video switch as much as it's got to do with
the MUX framework, so having Peter's opinion here would be very helpful.
--
Kind regards,
Sakari Ailus
e-mail: sakari.ailus@iki.fi XMPP: sailus@retiisi.org.uk
^ permalink raw reply
* Re: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Philipp Zabel @ 2017-04-18 10:51 UTC (permalink / raw)
To: Sakari Ailus
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pavel Machek,
Steve Longerbeam, Peter Rosin
In-Reply-To: <20170418100840.GF7456-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
On Tue, 2017-04-18 at 13:08 +0300, Sakari Ailus wrote:
> Hi Philipp,
>
> On Tue, Apr 18, 2017 at 10:19:04AM +0200, Philipp Zabel wrote:
> > On Thu, 2017-04-13 at 17:48 +0200, Philipp Zabel wrote:
> > > This adds device tree binding documentation for mmio-based syscon
> > > multiplexers controlled by a single bitfield in a syscon register
> > > range.
> > >
> > > Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> > > ---
> > > Documentation/devicetree/bindings/mux/mmio-mux.txt | 56 ++++++++++++++++++++++
> > > 1 file changed, 56 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > new file mode 100644
> > > index 0000000000000..11d96f5d98583
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > @@ -0,0 +1,56 @@
> > > +MMIO bitfield-based multiplexer controller bindings
> > > +
> > > +Define a syscon bitfield to be used to control a multiplexer. The parent
> > > +device tree node must be a syscon node to provide register access.
> > > +
> > > +Required properties:
> > > +- compatible : "gpio-mux"
> > > +- reg : register base of the register containing the control bitfield
> > > +- bit-mask : bitmask of the control bitfield in the control register
> > > +- bit-shift : bit offset of the control bitfield in the control register
> > > +- #mux-control-cells : <0>
> > > +* Standard mux-controller bindings as decribed in mux-controller.txt
> > > +
> > > +Optional properties:
> > > +- idle-state : if present, the state the mux will have when idle. The
> > > + special state MUX_IDLE_AS_IS is the default.
> > > +
> > > +The multiplexer state is defined as the value of the bitfield described
> > > +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> > > +syscon.
> > > +
> > > +Example:
> > > +
> > > + syscon {
> > > + compatible = "syscon";
> > > +
> > > + mux: mux-controller@3 {
> > > + compatible = "mmio-mux";
> > > + reg = <0x3>;
> > > + bit-mask = <0x1>;
> > > + bit-shift = <5>;
> > > + #mux-control-cells = <0>;
> > > + };
> > > + };
> > > +
> > > + video-mux {
> > > + compatible = "video-mux";
> > > + mux-controls = <&mux>;
> > > +
> > > + ports {
> > > + /* input 0 */
> > > + port@0 {
> > > + reg = <0>;
> > > + };
> > > +
> > > + /* input 1 */
> > > + port@1 {
> > > + reg = <1>;
> > > + };
> > > +
> > > + /* output */
> > > + port@2 {
> > > + reg = <2>;
> > > + };
> > > + };
> > > + };
> >
> > So Pavel (added to Cc:) suggested to merge these into one node for the
> > video mux, as really we are describing a single hardware entity that
> > happens to be multiplexing multiple video buses into one:
>
> Two drivers will be needed in a way or another to disconnect the dependency
> between the video switch driver and the MUX implementation. Are there ways
> to do that cleanly other than having two devices?
We are talking about the device tree bindings, drivers and devices
shouldn't factor into it yet. A video-mmio-mux driver could very well
create a mmio-mux platform device internally, if necessary. Or it could
just use the same library functions that the mmio-mux driver uses,
without creating a second device.
> And if there are two devices, shouldn't the video switch device be a child
> of the MUX device? I think it'd be odd to have it hanging around in a
> completely unrelated part of the device tree.
That boils down to whether you consider the connection between mux
controller and mux to be resource usage that should be described via a
phandle reference, like pwms, gpios, clocks, and so on, or whether you
consider it to be control flow in the device tree sense, which should be
described as a parent-child relationship of the nodes. The mux framework
is designed around the former.
We could embrace this and consider a syscon region that contains
multiple mux bitfields as one mux controller that controls multiple
muxes, with a binding similar to, for example, the
reset/ti-syscon-reset.txt bindings:
syscon {
compatible = "syscon";
mux: mux-controller@4 {
compatible = "mmio-mux";
/* register, bit shift, bit mask */
mux-bits = <0x4 19 0x1>, /* 0: CSI0 mux */
<0x4 20 0x1>; /* 1: CSI1 mux */
#mux-control-cells = <1>;
};
};
/* somewhere else */
csi0-mux {
compatible = "video-mux";
mux-controls = <&mux 0>;
ports {
/* ... */
};
};
csi1-mux {
compatible = "video-mux";
mux-controls = <&mux 1>;
ports {
/* ... */
};
};
regards
Philipp
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers
From: Icenowy Zheng @ 2017-04-18 10:47 UTC (permalink / raw)
To: Maxime Ripard
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Jernej Skrabec, David Airlie,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Chen-Yu Tsai,
Rob Herring, linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170418090047.7i2k6dtoqxfdqwwy@lukather>
于 2017年4月18日 GMT+08:00 下午5:00:47, Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 写到:
>On Sun, Apr 16, 2017 at 08:08:44PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which
>comes
>> with mixers to do graphic processing and feed data to TCON, like the
>old
>> backends and frontends.
>>
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest
>one.
>>
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> ---
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>>
>> drivers/gpu/drm/sun4i/Kconfig | 10 +
>> drivers/gpu/drm/sun4i/Makefile | 4 +
>> drivers/gpu/drm/sun4i/sun8i_layer.c | 142 ++++++++++++++
>> drivers/gpu/drm/sun4i/sun8i_layer.h | 36 ++++
>> drivers/gpu/drm/sun4i/sun8i_mixer.c | 381
>++++++++++++++++++++++++++++++++++++
>> drivers/gpu/drm/sun4i/sun8i_mixer.h | 131 +++++++++++++
>> 6 files changed, 704 insertions(+)
>> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>>
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig
>b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>> original Allwinner Display Engine, which has a backend to
>> do some alpha blending and feed graphics to TCON. If M is
>> selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
>> + tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> + depends on DRM_SUN4I
>> + default MACH_SUN8I
>> + help
>> + Choose this option if you have an Allwinner SoC with the
>> + Allwinner Display Engine 2.0, which has a mixer to do some
>> + graphics mixture and feed graphics to TCON, If M is
>> + selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile
>b/drivers/gpu/drm/sun4i/Makefile
>> index 1db1068b9be1..7625c2dad1bb 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
>> sun4i-backend-y += sun4i_layer.o
>> sun4i-backend-y += sun4i_backend.o
>>
>> +sun8i-mixer-y += sun8i_layer.o
>> +sun8i-mixer-y += sun8i_mixer.o
>> +
>> obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o
>> obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
>
>Please align the value using tabs.
Should I re-align existed items?
>
>> obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
>> obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c
>b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..d70a90d963b0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + * Copyright (C) 2015 Free Electrons
>> + * Copyright (C) 2015 NextThing Co
>> + *
>> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun4i_crtc.h"
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> + enum drm_plane_type type;
>> + const uint32_t *formats;
>> + uint32_t nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> + struct drm_plane_state *state)
>> +{
>> + return 0;
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane
>*plane,
>> + struct drm_plane_state *old_state)
>> +{
>> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> + struct sun8i_mixer *mixer = layer->mixer;
>> +
>> + sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> + struct drm_plane_state *old_state)
>> +{
>> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> + struct sun8i_mixer *mixer = layer->mixer;
>> +
>> + sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> + sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> + sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> + sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs
>= {
>> + .atomic_check = sun8i_mixer_layer_atomic_check,
>> + .atomic_disable = sun8i_mixer_layer_atomic_disable,
>> + .atomic_update = sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
>> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
>> + .destroy = drm_plane_cleanup,
>> + .disable_plane = drm_atomic_helper_disable_plane,
>> + .reset = drm_atomic_helper_plane_reset,
>> + .update_plane = drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> + DRM_FORMAT_RGB888,
>> + DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> + {
>> + .type = DRM_PLANE_TYPE_PRIMARY,
>> + .formats = sun8i_mixer_layer_formats,
>> + .nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> + },
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device
>*drm,
>> + struct sun8i_mixer *mixer,
>> + const struct sun8i_plane_desc *plane)
>> +{
>> + struct sun8i_layer *layer;
>> + int ret;
>> +
>> + layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> + if (!layer)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + /* possible crtcs are set later */
>> + ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> + &sun8i_mixer_layer_funcs,
>> + plane->formats, plane->nformats,
>> + plane->type, NULL);
>> + if (ret) {
>> + dev_err(drm->dev, "Couldn't initialize layer\n");
>> + return ERR_PTR(ret);
>> + }
>> +
>> + drm_plane_helper_add(&layer->plane,
>> + &sun8i_mixer_layer_helper_funcs);
>> + layer->mixer = mixer;
>> +
>> + return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> + struct sun4i_crtc *crtc)
>> +{
>> + struct drm_plane **planes;
>> + struct sun8i_mixer *mixer = crtc->engine;
>> + int i;
>> +
>> + planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> + sizeof(*planes), GFP_KERNEL);
>> + if (!planes)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> + const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> + struct sun8i_layer *layer;
>> +
>> + layer = sun8i_layer_init_one(drm, mixer, plane);
>> + if (IS_ERR(layer)) {
>> + dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> + i ? "overlay" : "primary");
>> + return ERR_CAST(layer);
>> + };
>> +
>> + layer->id = i;
>> + planes[i] = &layer->plane;
>> + };
>> +
>> + return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h
>b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..fe7e8a069d71
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + * Copyright (C) 2015 Free Electrons
>> + * Copyright (C) 2015 NextThing Co
>> + *
>> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sun4i_crtc;
>> +
>> +struct sun8i_layer {
>> + struct drm_plane plane;
>> + struct sun4i_drv *drv;
>> + struct sun8i_mixer *mixer;
>> + int id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> + return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> + struct sun4i_crtc *crtc);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
>b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..5cff3f3833a7
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,381 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + * Copyright (C) 2015 Free Electrons
>> + * Copyright (C) 2015 NextThing Co
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drmP.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_fb_cma_helper.h>
>> +#include <drm/drm_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(void *mixer)
>> +{
>> + struct sun8i_mixer *sun8i_mixer = mixer;
>> +
>> + DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> + regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> + SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> + int layer, bool enable)
>> +{
>> + u32 val;
>> + /* Currently the first UI channel is used */
>> + int chan = mixer->cfg->vi_num;
>> +
>> + DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> + if (enable)
>> + val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> + else
>> + val = 0;
>> +
>> + regmap_update_bits(mixer->regs,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> + /* Set the alpha configuration */
>> + regmap_update_bits(mixer->regs,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> + regmap_update_bits(mixer->regs,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
>
>Why do you need to export it?
Oh... not needed. This export is dead code.
>
>> +
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> + u32 format, u32 *mode)
>> +{
>> + switch (format) {
>> + case DRM_FORMAT_XRGB8888:
>> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> + break;
>> +
>> + case DRM_FORMAT_RGB888:
>> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> + break;
>> +
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane)
>> +{
>> + struct drm_plane_state *state = plane->state;
>> + struct drm_framebuffer *fb = state->fb;
>> + /* Currently the first UI channel is used */
>> + int chan = mixer->cfg->vi_num;
>> +
>> + DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> + if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> + DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H:
>%u\n",
>> + state->crtc_w, state->crtc_h);
>> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
>> + SUN8I_MIXER_SIZE(state->crtc_w,
>> + state->crtc_h));
>> + DRM_DEBUG_DRIVER("Updating blender size\n");
>> + regmap_write(mixer->regs,
>> + SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> + SUN8I_MIXER_SIZE(state->crtc_w,
>> + state->crtc_h));
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> + SUN8I_MIXER_SIZE(state->crtc_w,
>> + state->crtc_h));
>> + DRM_DEBUG_DRIVER("Updating channel size\n");
>> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> + SUN8I_MIXER_SIZE(state->crtc_w,
>> + state->crtc_h));
>> + }
>> +
>> + /* Set the line width */
>> + DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan,
>layer),
>> + fb->pitches[0]);
>> +
>> + /* Set height and width */
>> + DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> + state->crtc_w, state->crtc_h);
>> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan,
>layer),
>> + SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> + /* Set base coordinates */
>> + DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> + state->crtc_x, state->crtc_y);
>> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan,
>layer),
>> + SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane)
>> +{
>> + struct drm_plane_state *state = plane->state;
>> + struct drm_framebuffer *fb = state->fb;
>> + bool interlaced = false;
>> + u32 val;
>> + /* Currently the first UI channel is used */
>> + int chan = mixer->cfg->vi_num;
>> + int ret;
>> +
>> + if (plane->state->crtc)
>> + interlaced = plane->state->crtc->state->adjusted_mode.flags
>> + & DRM_MODE_FLAG_INTERLACE;
>> +
>> + regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
>> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> + interlaced ?
>> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> + DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> + interlaced ? "on" : "off");
>
>You're not using interlaced anywhere.
ok.
>
>> +
>> + ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> + &val);
>> + if (ret) {
>> + DRM_DEBUG_DRIVER("Invalid format\n");
>> + return ret;
>> + }
>> +
>> + regmap_update_bits(mixer->regs,
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane)
>> +{
>> + struct drm_plane_state *state = plane->state;
>> + struct drm_framebuffer *fb = state->fb;
>> + struct drm_gem_cma_object *gem;
>> + dma_addr_t paddr;
>> + uint32_t paddr_u32;
>> + /* Currently the first UI channel is used */
>> + int chan = mixer->cfg->vi_num;
>> + int bpp;
>> +
>> + /* Get the physical address of the buffer in memory */
>> + gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> + /* Compute the start of the displayed memory */
>> + bpp = fb->format->cpp[0];
>> + paddr = gem->paddr + fb->offsets[0];
>> + paddr += (state->src_x >> 16) * bpp;
>> + paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> + paddr_u32 = (uint32_t) paddr;
>
>How does that work on 64-bits systems ?
The hardware is not designed to work on 64-bit systems.
Even 64-bit A64/H5 has also 3GiB memory limit.
The address cell in mixer hardware is also only 32-bit.
So we should just keep the force conversion here. If we then really met 4GiB-capable AW SoC without changing DE2, I think we should have other way to limit CMA pool inside 4GiB.
>
>> +
>> + regmap_write(mixer->regs,
>> + SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> + paddr_u32);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> + .commit = sun8i_mixer_commit,
>> + .layers_init = sun8i_layers_init,
>
>Align with tabs.
>
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> + .reg_bits = 32,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> + .max_register = 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device
>*master,
>> + void *data)
>> +{
>> + struct platform_device *pdev = to_platform_device(dev);
>> + struct drm_device *drm = data;
>> + struct sun4i_drv *drv = drm->dev_private;
>> + struct sun8i_mixer *mixer;
>> + struct resource *res;
>> + void __iomem *regs;
>> + int i, ret;
>> +
>> + mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> + if (!mixer)
>> + return -ENOMEM;
>> + dev_set_drvdata(dev, mixer);
>> + drv->engine = mixer;
>> + drv->engine_ops = &sun8i_engine_ops;
>> +
>> + mixer->cfg = of_device_get_match_data(dev);
>> + if (!mixer->cfg)
>> + return -EINVAL;
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + regs = devm_ioremap_resource(dev, res);
>> + if (IS_ERR(regs))
>> + return PTR_ERR(regs);
>> +
>> + mixer->regs = devm_regmap_init_mmio(dev, regs,
>> + &sun8i_mixer_regmap_config);
>> + if (IS_ERR(mixer->regs)) {
>> + dev_err(dev, "Couldn't create the mixer regmap\n");
>> + return PTR_ERR(mixer->regs);
>> + }
>> +
>> + mixer->reset = devm_reset_control_get(dev, NULL);
>> + if (IS_ERR(mixer->reset)) {
>> + dev_err(dev, "Couldn't get our reset line\n");
>> + return PTR_ERR(mixer->reset);
>> + }
>> +
>> + ret = reset_control_deassert(mixer->reset);
>> + if (ret) {
>> + dev_err(dev, "Couldn't deassert our reset line\n");
>> + return ret;
>> + }
>> +
>> + mixer->bus_clk = devm_clk_get(dev, "bus");
>> + if (IS_ERR(mixer->bus_clk)) {
>> + dev_err(dev, "Couldn't get the mixer bus clock\n");
>> + ret = PTR_ERR(mixer->bus_clk);
>> + goto err_assert_reset;
>> + }
>> + clk_prepare_enable(mixer->bus_clk);
>> +
>> + mixer->mod_clk = devm_clk_get(dev, "mod");
>> + if (IS_ERR(mixer->mod_clk)) {
>> + dev_err(dev, "Couldn't get the mixer module clock\n");
>> + ret = PTR_ERR(mixer->mod_clk);
>> + goto err_disable_bus_clk;
>> + }
>> + clk_prepare_enable(mixer->mod_clk);
>> +
>> + /* Reset the registers */
>> + for (i = 0x0; i < 0x20000; i += 4)
>> + regmap_write(mixer->regs, i, 0);
>> +
>> + /* Enable the mixer */
>> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
>> + SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> + /* Initialize blender */
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> + SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> + SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> + SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
>> + SUN8I_MIXER_BLEND_MODE_DEF);
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
>> + SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> + regmap_write(mixer->regs,
>> + SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> + SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> + /* Select the first UI channel */
>> + DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> + mixer->cfg->vi_num);
>> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
>> + mixer->cfg->vi_num);
>> +
>> + return 0;
>> +
>> + clk_disable_unprepare(mixer->mod_clk);
>> +err_disable_bus_clk:
>> + clk_disable_unprepare(mixer->bus_clk);
>> +err_assert_reset:
>> + reset_control_assert(mixer->reset);
>> + return ret;
>> +}
>> +
>> +static void sun8i_mixer_unbind(struct device *dev, struct device
>*master,
>> + void *data)
>> +{
>> + struct sun8i_mixer *mixer = dev_get_drvdata(dev);
>> +
>> + clk_disable_unprepare(mixer->mod_clk);
>> + clk_disable_unprepare(mixer->bus_clk);
>> + reset_control_assert(mixer->reset);
>> +}
>> +
>> +static const struct component_ops sun8i_mixer_ops = {
>> + .bind = sun8i_mixer_bind,
>> + .unbind = sun8i_mixer_unbind,
>> +};
>> +
>> +static int sun8i_mixer_probe(struct platform_device *pdev)
>> +{
>> + return component_add(&pdev->dev, &sun8i_mixer_ops);
>> +}
>> +
>> +static int sun8i_mixer_remove(struct platform_device *pdev)
>> +{
>> + component_del(&pdev->dev, &sun8i_mixer_ops);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
>> + .vi_num = 2,
>> + .ui_num = 1,
>> +};
>> +
>> +static const struct of_device_id sun8i_mixer_of_table[] = {
>> + {
>> + .compatible = "allwinner,sun8i-v3s-de2-mixer",
>> + .data = &sun8i_v3s_mixer_cfg,
>> + },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
>> +
>> +static struct platform_driver sun8i_mixer_platform_driver = {
>> + .probe = sun8i_mixer_probe,
>> + .remove = sun8i_mixer_remove,
>> + .driver = {
>> + .name = "sun8i-mixer",
>> + .of_match_table = sun8i_mixer_of_table,
>> + },
>> +};
>> +module_platform_driver(sun8i_mixer_platform_driver);
>> +
>> +MODULE_AUTHOR("Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>");
>> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h
>b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> new file mode 100644
>> index 000000000000..a4a365ae44c9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> @@ -0,0 +1,131 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_MIXER_H_
>> +#define _SUN8I_MIXER_H_
>> +
>> +#include <linux/clk.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +
>> +#include "sun4i_layer.h"
>> +
>> +#define SUN8I_MIXER_MAX_CHAN_COUNT 4
>> +
>> +#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
>> +#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL 0x0
>> +#define SUN8I_MIXER_GLOBAL_STATUS 0x4
>> +#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
>> +#define SUN8I_MIXER_GLOBAL_SIZE 0xc
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN 0x1
>> +
>> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE 0x1
>> +
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL 0x1000
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
>> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
>> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x) (0x1004 + 0x10 * (x) + 0x8)
>> +#define SUN8I_MIXER_BLEND_ROUTE 0x1080
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
>> +#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
>> +#define SUN8I_MIXER_BLEND_OUTSIZE 0x108c
>> +#define SUN8I_MIXER_BLEND_MODE(x) (0x1090 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_CTL 0x10b0
>> +#define SUN8I_MIXER_BLEND_CK_CFG 0x10b4
>> +#define SUN8I_MIXER_BLEND_CK_MAX(x) (0x10c0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
>> +
>> +/* The following numbers are some still unknown magic numbers */
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF 0xff000000
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF 0x00000101
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF 0x0
>> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF 0xff000000
>> +#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301
>> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF 0x0
>> +
>> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
>> +
>> +/*
>> + * VI channels are not used now, but the support of them may be
>introduced in
>> + * the future.
>> + */
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
>> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
>> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) +
>0x80)
>> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) +
>0x84)
>> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) +
>0x88)
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(11, 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF (1 << 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888 (0 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888 (4 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888 (8 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF (0xff << 24)
>> +
>> +/*
>> + * These sub-engines are still unknown now, the EN registers are
>here only to
>> + * be used to disable these sub-engines.
>> + */
>> +#define SUN8I_MIXER_VSU_EN 0x20000
>> +#define SUN8I_MIXER_GSU1_EN 0x30000
>> +#define SUN8I_MIXER_GSU2_EN 0x40000
>> +#define SUN8I_MIXER_GSU3_EN 0x50000
>> +#define SUN8I_MIXER_FCE_EN 0xa0000
>> +#define SUN8I_MIXER_BWS_EN 0xa2000
>> +#define SUN8I_MIXER_LTI_EN 0xa4000
>> +#define SUN8I_MIXER_PEAK_EN 0xa6000
>> +#define SUN8I_MIXER_ASE_EN 0xa8000
>> +#define SUN8I_MIXER_FCC_EN 0xaa000
>> +#define SUN8I_MIXER_DCSC_EN 0xb0000
>> +
>> +struct sun8i_mixer_cfg {
>> + int vi_num;
>> + int ui_num;
>> +};
>> +
>> +struct sun8i_mixer {
>> + struct regmap *regs;
>> +
>> + const struct sun8i_mixer_cfg *cfg;
>> +
>> + struct reset_control *reset;
>> +
>> + struct clk *bus_clk;
>> + struct clk *mod_clk;
>> +};
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> + int layer, bool enable);
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> + int layer, struct drm_plane *plane);
>> +#endif /* _SUN8I_MIXER_H_ */
>
>Thanks,
>Maxime
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [linux-sunxi] [PATCH v3 09/12] mfd: axp20x: add axp20x-regulator cell for AXP803
From: Chen-Yu Tsai @ 2017-04-18 10:38 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Lee Jones, Rob Herring, Chen-Yu Tsai, Maxime Ripard,
Liam Girdwood, Mark Brown, devicetree, linux-kernel,
linux-arm-kernel, linux-sunxi
In-Reply-To: <20170417115747.7300-10-icenowy-h8G6r0blFSE@public.gmane.org>
On Mon, Apr 17, 2017 at 7:57 PM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
> As axp20x-regulator now supports AXP803, add a cell for it.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> ---
> Changes in v3:
> - Make the new cell one-liner.
>
> drivers/mfd/axp20x.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> index 1dc6235778eb..431b7f118606 100644
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
> @@ -848,7 +848,8 @@ static struct mfd_cell axp803_cells[] = {
> .name = "axp20x-pek",
> .num_resources = ARRAY_SIZE(axp803_pek_resources),
> .resources = axp803_pek_resources,
> - }
> + },
> + { .name = "axp20x-regulator" }
It's best to have a trailing comma, so we don't have to change the line
again when we add more cells, like you just did with the previous line.
Otherwise,
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 07/12] dt-bindings: add AXP803's regulator info
From: Chen-Yu Tsai @ 2017-04-18 10:36 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Lee Jones, Rob Herring, Chen-Yu Tsai, Maxime Ripard,
Liam Girdwood, Mark Brown, devicetree, linux-kernel,
linux-arm-kernel, linux-sunxi
In-Reply-To: <20170417115747.7300-8-icenowy-h8G6r0blFSE@public.gmane.org>
On Mon, Apr 17, 2017 at 7:57 PM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
> AXP803 have the most regulators in currently supported AXP PMICs.
>
> Add info for the regulators in the dt-bindings document.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
^ permalink raw reply
* Re: [PATCH v3 03/12] dt-bindings: make AXP20X compatible strings one per line
From: Chen-Yu Tsai @ 2017-04-18 10:35 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Lee Jones, Rob Herring, Chen-Yu Tsai, Maxime Ripard,
Liam Girdwood, Mark Brown, devicetree, linux-kernel,
linux-arm-kernel, linux-sunxi
In-Reply-To: <20170417115747.7300-4-icenowy-h8G6r0blFSE@public.gmane.org>
On Mon, Apr 17, 2017 at 7:57 PM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
> In the binding documentation of AXP20X mfd, the compatible strings used
> to be listed for three per line, which leads to some mess when trying to
> add AXP803 compatible string (as we have already AXP806 and AXP809
> compatibles, which is after AXP803 in ascending order).
>
> Make the compatible strings one per line, so that inserting a new
> compatible string will be directly a new line.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
^ permalink raw reply
* Re: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Pavel Machek @ 2017-04-18 10:34 UTC (permalink / raw)
To: Sakari Ailus
Cc: Philipp Zabel, Peter Rosin, Rob Herring, Mark Rutland,
Steve Longerbeam, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <20170418100840.GF7456-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 3369 bytes --]
On Tue 2017-04-18 13:08:41, Sakari Ailus wrote:
> Hi Philipp,
>
> On Tue, Apr 18, 2017 at 10:19:04AM +0200, Philipp Zabel wrote:
> > On Thu, 2017-04-13 at 17:48 +0200, Philipp Zabel wrote:
> > > This adds device tree binding documentation for mmio-based syscon
> > > multiplexers controlled by a single bitfield in a syscon register
> > > range.
> > >
> > > Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> > > ---
> > > Documentation/devicetree/bindings/mux/mmio-mux.txt | 56 ++++++++++++++++++++++
> > > 1 file changed, 56 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > new file mode 100644
> > > index 0000000000000..11d96f5d98583
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > > @@ -0,0 +1,56 @@
> > > +MMIO bitfield-based multiplexer controller bindings
> > > +
> > > +Define a syscon bitfield to be used to control a multiplexer. The parent
> > > +device tree node must be a syscon node to provide register access.
> > > +
> > > +Required properties:
> > > +- compatible : "gpio-mux"
> > > +- reg : register base of the register containing the control bitfield
> > > +- bit-mask : bitmask of the control bitfield in the control register
> > > +- bit-shift : bit offset of the control bitfield in the control register
> > > +- #mux-control-cells : <0>
> > > +* Standard mux-controller bindings as decribed in mux-controller.txt
> > > +
> > > +Optional properties:
> > > +- idle-state : if present, the state the mux will have when idle. The
> > > + special state MUX_IDLE_AS_IS is the default.
> > > +
> > > +The multiplexer state is defined as the value of the bitfield described
> > > +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> > > +syscon.
> > > +
> > > +Example:
> > > +
> > > + syscon {
> > > + compatible = "syscon";
> > > +
> > > + mux: mux-controller@3 {
> > > + compatible = "mmio-mux";
> > > + reg = <0x3>;
> > > + bit-mask = <0x1>;
> > > + bit-shift = <5>;
> > > + #mux-control-cells = <0>;
> > > + };
> > > + };
> > > +
> > > + video-mux {
> > > + compatible = "video-mux";
> > > + mux-controls = <&mux>;
> > > +
> > > + ports {
> > > + /* input 0 */
> > > + port@0 {
> > > + reg = <0>;
> > > + };
> > > +
> > > + /* input 1 */
> > > + port@1 {
> > > + reg = <1>;
> > > + };
> > > +
> > > + /* output */
> > > + port@2 {
> > > + reg = <2>;
> > > + };
> > > + };
> > > + };
> >
> > So Pavel (added to Cc:) suggested to merge these into one node for the
> > video mux, as really we are describing a single hardware entity that
> > happens to be multiplexing multiple video buses into one:
>
> Two drivers will be needed in a way or another to disconnect the dependency
> between the video switch driver and the MUX implementation. Are there ways
> to do that cleanly other than having two devices?
Yes.
Device tree describes hardware, not the driver structure.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/3] ARM: dts: rockchip: Add support for phyCORE-RK3288 SoM
From: Jacob Chen @ 2017-04-18 10:15 UTC (permalink / raw)
To: Wadim Egorov
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
Heiko Stuebner, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1491483866-18368-1-git-send-email-w.egorov-guT5V/WYfQezQB+pC5nmwQ@public.gmane.org>
Hi wadim,
2017-04-06 21:04 GMT+08:00 Wadim Egorov <w.egorov-guT5V/WYfQezQB+pC5nmwQ@public.gmane.org>:
> The phyCORE-RK3288 is a SoM (System on Module) containing a RK3288 SoC.
> The module can be connected to different carrier boards.
> It can be also equipped with different RAM, SPI flash and eMMC variants.
> The Rapid Development Kit option is using the following setup:
>
> - 1 GB DDR3 RAM (2 Banks)
> - 1x 4 KB EEPROM
> - DP83867 Gigabit Ethernet PHY
> - 16 MB SPI Flash
> - 4 GB eMMC Flash
>
> Signed-off-by: Wadim Egorov <w.egorov-guT5V/WYfQezQB+pC5nmwQ@public.gmane.org>
> ---
> Changes in v2:
> - Added a dual license which is used for all rk3288 based boards.
>
> Include minor changes from Heiko Stübner:
> - moved phy-handle property up a bit
> - switches compatible and #address+#size-cells in mdio0
> - dropped rockchip,grf from &io_domains (grf is a simple-mfd and can
> get the grf syscon on its own via its parent)
> - vdd_cpu: regulator@60 (from fan53555@60)
> - serial_flash: flash@0 (from m25p80@0)
> Nodes should be named after their "category" not the actual device
>
> ---
> arch/arm/boot/dts/rk3288-phycore-som.dtsi | 497 ++++++++++++++++++++++++++++++
> 1 file changed, 497 insertions(+)
> create mode 100644 arch/arm/boot/dts/rk3288-phycore-som.dtsi
>
> diff --git a/arch/arm/boot/dts/rk3288-phycore-som.dtsi b/arch/arm/boot/dts/rk3288-phycore-som.dtsi
> new file mode 100644
> index 0000000..26cd3ad
> --- /dev/null
> +++ b/arch/arm/boot/dts/rk3288-phycore-som.dtsi
> @@ -0,0 +1,497 @@
> +/*
> + * Device tree file for Phytec phyCORE-RK3288 SoM
> + * Copyright (C) 2017 PHYTEC Messtechnik GmbH
> + * Author: Wadim Egorov <w.egorov-guT5V/WYfQezQB+pC5nmwQ@public.gmane.org>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This file is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <dt-bindings/net/ti-dp83867.h>
> +#include "rk3288.dtsi"
> +
> +/ {
> + model = "Phytec RK3288 phyCORE";
> + compatible = "phytec,rk3288-phycore-som", "rockchip,rk3288";
> +
> + /*
> + * Set the minimum memory size here and
> + * let the bootloader set the real size.
> + */
> + memory {
> + device_type = "memory";
> + reg = <0 0x8000000>;
> + };
> +
> + aliases {
> + rtc0 = &i2c_rtc;
> + rtc1 = &rk818;
> + };
> +
> + ext_gmac: external-gmac-clock {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <125000000>;
> + clock-output-names = "ext_gmac";
> + };
> +
> + leds: user-leds {
> + compatible = "gpio-leds";
> + pinctrl-names = "default";
> + pinctrl-0 = <&user_led>;
> +
> + user {
> + label = "green_led";
> + gpios = <&gpio7 2 GPIO_ACTIVE_HIGH>;
> + linux,default-trigger = "heartbeat";
> + default-state = "keep";
> + };
> + };
> +
> + vdd_emmc_io: vdd-emmc-io {
> + compatible = "regulator-fixed";
> + regulator-name = "vdd_emmc_io";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + vin-supply = <&vdd_3v3_io>;
> + };
> +
> + vdd_in_otg_out: vdd-in-otg-out {
> + compatible = "regulator-fixed";
> + regulator-name = "vdd_in_otg_out";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + };
> +
> + vdd_misc_1v8: vdd-misc-1v8 {
> + compatible = "regulator-fixed";
> + regulator-name = "vdd_misc_1v8";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + };
> +};
> +
> +&cpu0 {
> + cpu0-supply = <&vdd_cpu>;
> + operating-points = <
> + /* KHz uV */
> + 1800000 1400000
> + 1608000 1350000
> + 1512000 1300000
> + 1416000 1200000
> + 1200000 1100000
> + 1008000 1050000
> + 816000 1000000
> + 696000 950000
> + 600000 900000
> + 408000 900000
> + 312000 900000
> + 216000 900000
> + 126000 900000
> + >;
> +};
> +
> +&emmc {
> + status = "okay";
> + bus-width = <8>;
> + cap-mmc-highspeed;
> + disable-wp;
> + non-removable;
> + num-slots = <1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>;
> + vmmc-supply = <&vdd_3v3_io>;
> + vqmmc-supply = <&vdd_emmc_io>;
> +};
> +
> +&gmac {
> + assigned-clocks = <&cru SCLK_MAC>;
> + assigned-clock-parents = <&ext_gmac>;
> + clock_in_out = "input";
> + pinctrl-names = "default";
> + pinctrl-0 = <&rgmii_pins &phy_rst &phy_int>;
> + phy-handle = <&phy0>;
> + phy-supply = <&vdd_eth_2v5>;
> + phy-mode = "rgmii-id";
> + snps,reset-active-low;
> + snps,reset-delays-us = <0 10000 1000000>;
> + snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_HIGH>;
> + tx_delay = <0x0>;
> + rx_delay = <0x0>;
> +
> + mdio0 {
> + compatible = "snps,dwmac-mdio";
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + phy0: ethernet-phy@0 {
> + compatible = "ethernet-phy-ieee802.3-c22";
> + reg = <0>;
> + interrupt-parent = <&gpio4>;
> + interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
> + ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
> + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
> + enet-phy-lane-no-swap;
> + };
> + };
> +};
> +
> +&hdmi {
> + ddc-i2c-bus = <&i2c5>;
> +};
> +
> +&io_domains {
> + status = "okay";
> + sdcard-supply = <&vdd_io_sd>;
> + flash0-supply = <&vdd_emmc_io>;
> + flash1-supply = <&vdd_misc_1v8>;
> + gpio1830-supply = <&vdd_3v3_io>;
> + gpio30-supply = <&vdd_3v3_io>;
> + bb-supply = <&vdd_3v3_io>;
> + dvp-supply = <&vdd_3v3_io>;
> + lcdc-supply = <&vdd_3v3_io>;
> + wifi-supply = <&vdd_3v3_io>;
> + audio-supply = <&vdd_3v3_io>;
> +};
> +
> +&i2c0 {
> + status = "okay";
> + clock-frequency = <400000>;
> +
> + rk818: pmic@1c {
> + compatible = "rockchip,rk818";
> + reg = <0x1c>;
> + interrupt-parent = <&gpio0>;
> + interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pmic_int>;
> + rockchip,system-power-controller;
> + wakeup-source;
> + #clock-cells = <1>;
> +
I think you miss "clock-output-names = "xin32k" here.
> + vcc1-supply = <&vdd_sys>;
> + vcc2-supply = <&vdd_sys>;
> + vcc3-supply = <&vdd_sys>;
> + vcc4-supply = <&vdd_sys>;
> + boost-supply = <&vdd_in_otg_out>;
> + vcc6-supply = <&vdd_sys>;
> + vcc7-supply = <&vdd_misc_1v8>;
> + vcc8-supply = <&vdd_misc_1v8>;
> + vcc9-supply = <&vdd_3v3_io>;
> + vddio-supply = <&vdd_3v3_io>;
> +
> + regulators {
> + vdd_log: DCDC_REG1 {
> + regulator-name = "vdd_log";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1100000>;
> + regulator-max-microvolt = <1100000>;
> + regulator-state-mem {
> + regulator-off-in-suspend;
> + };
> + };
> +
> + vdd_gpu: DCDC_REG2 {
> + regulator-name = "vdd_gpu";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <800000>;
> + regulator-max-microvolt = <1250000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <1000000>;
> + };
> + };
> +
> + vcc_ddr: DCDC_REG3 {
> + regulator-name = "vcc_ddr";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + };
> + };
> +
> + vdd_3v3_io: DCDC_REG4 {
> + regulator-name = "vdd_3v3_io";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <3300000>;
> + };
> + };
> +
> + vdd_sys: DCDC_BOOST {
> + regulator-name = "vdd_sys";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <5000000>;
> + };
> + };
> +
> + /* vcc9 */
> + vdd_sd: SWITCH_REG {
> + regulator-name = "vdd_sd";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-state-mem {
> + regulator-off-in-suspend;
> + };
> + };
> +
> + /* vcc6 */
> + vdd_eth_2v5: LDO_REG2 {
> + regulator-name = "vdd_eth_2v5";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <2500000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <2500000>;
> + };
> + };
> +
> + /* vcc7 */
> + vdd_1v0: LDO_REG3 {
> + regulator-name = "vdd_1v0";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1000000>;
> + regulator-max-microvolt = <1000000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <1000000>;
> + };
> + };
> +
> + /* vcc8 */
> + vdd_1v8_lcd_ldo: LDO_REG4 {
> + regulator-name = "vdd_1v8_lcd_ldo";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <1800000>;
> + };
> + };
> +
> + /* vcc8 */
> + vdd_1v0_lcd: LDO_REG6 {
> + regulator-name = "vdd_1v0_lcd";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1000000>;
> + regulator-max-microvolt = <1000000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <1000000>;
> + };
> + };
> +
> + /* vcc7 */
> + vdd_1v8_ldo: LDO_REG7 {
> + regulator-name = "vdd_1v8_ldo";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + regulator-state-mem {
> + regulator-off-in-suspend;
> + regulator-suspend-microvolt = <1800000>;
> + };
> + };
> +
> + /* vcc9 */
> + vdd_io_sd: LDO_REG9 {
> + regulator-name = "vdd_io_sd";
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-state-mem {
> + regulator-on-in-suspend;
> + regulator-suspend-microvolt = <3300000>;
> + };
> + };
> + };
> + };
> +
> + /* M24C32-D */
> + i2c_eeprom: eeprom@50 {
> + compatible = "atmel,24c32";
> + reg = <0x50>;
> + pagesize = <32>;
> + };
> +
> + vdd_cpu: regulator@60 {
> + compatible = "fcs,fan53555";
> + reg = <0x60>;
> + fcs,suspend-voltage-selector = <1>;
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-enable-ramp-delay = <300>;
> + regulator-name = "vdd_cpu";
> + regulator-min-microvolt = <800000>;
> + regulator-max-microvolt = <1430000>;
> + regulator-ramp-delay = <8000>;
> + vin-supply = <&vdd_sys>;
> + };
> +};
> +
> +&pinctrl {
> + pcfg_output_high: pcfg-output-high {
> + output-high;
> + };
> +
> + emmc {
> + /*
> + * We run eMMC at max speed; bump up drive strength.
> + * We also have external pulls, so disable the internal ones.
> + */
> + emmc_clk: emmc-clk {
> + rockchip,pins = <3 18 RK_FUNC_2 &pcfg_pull_none_12ma>;
> + };
> +
> + emmc_cmd: emmc-cmd {
> + rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_none_12ma>;
> + };
> +
> + emmc_bus8: emmc-bus8 {
> + rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 1 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 2 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 3 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 4 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 5 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 6 RK_FUNC_2 &pcfg_pull_none_12ma>,
> + <3 7 RK_FUNC_2 &pcfg_pull_none_12ma>;
> + };
> + };
> +
> + gmac {
> + phy_int: phy-int {
> + rockchip,pins = <4 2 RK_FUNC_GPIO &pcfg_pull_up>;
> + };
> +
> + phy_rst: phy-rst {
> + rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
> + };
> + };
> +
> + leds {
> + user_led: user-led {
> + rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_output_high>;
> + };
> + };
> +
> + pmic {
> + pmic_int: pmic-int {
> + rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
> + };
> +
> + /* Pin for switching state between sleep and non-sleep state */
> + pmic_sleep: pmic-sleep {
> + rockchip,pins = <RK_GPIO0 0 RK_FUNC_GPIO &pcfg_pull_up>;
> + };
> + };
> +};
> +
> +&pwm1 {
> + status = "okay";
> +};
> +
> +&saradc {
> + status = "okay";
> + vref-supply = <&vdd_1v8_ldo>;
> +};
> +
> +&spi2 {
> + status = "okay";
> +
> + serial_flash: flash@0 {
> + compatible = "micron,n25q128a13", "jedec,spi-nor";
> + reg = <0x0>;
> + spi-max-frequency = <50000000>;
> + m25p,fast-read;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + status = "okay";
> + };
> +};
> +
> +&tsadc {
> + status = "okay";
> + rockchip,hw-tshut-mode = <0>;
> + rockchip,hw-tshut-polarity = <0>;
> +};
> +
> +&vopb {
> + status = "okay";
> +};
> +
> +&vopb_mmu {
> + status = "okay";
> +};
> +
> +&vopl {
> + status = "okay";
> +};
> +
> +&vopl_mmu {
> + status = "okay";
> +};
> +
> +&wdt {
> + status = "okay";
> +};
> --
> 1.9.1
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 3/3] mmc: sdio: mediatek: Support SDIO feature
From: Yong Mao @ 2017-04-18 10:13 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring
Cc: Linus Walleij, Daniel Kurtz, Chaotian Jing, yong mao, Eddie Huang,
linux-mmc, srv_heupstream, linux-mediatek, linux-kernel,
linux-arm-kernel, devicetree
In-Reply-To: <1492510391-704-1-git-send-email-yong.mao@mediatek.com>
From: yong mao <yong.mao@mediatek.com>
1. Add irqlock to protect accessing the shared register
2. Implement enable_sdio_irq interface
3. Add msdc_recheck_sdio_irq mechanism to make sure all interrupts
can be processed immediately
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
drivers/mmc/host/mtk-sd.c | 182 +++++++++++++++++++++++++++++++++++----------
1 file changed, 143 insertions(+), 39 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 07f3236..fdae197 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -118,6 +118,7 @@
#define MSDC_PS_CDSTS (0x1 << 1) /* R */
#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */
#define MSDC_PS_DAT (0xff << 16) /* R */
+#define MSDC_PS_DATA1 (0x1 << 17) /* R */
#define MSDC_PS_CMD (0x1 << 24) /* R */
#define MSDC_PS_WP (0x1 << 31) /* R */
@@ -312,6 +313,7 @@ struct msdc_host {
int cmd_rsp;
spinlock_t lock;
+ spinlock_t irqlock; /* irq lock */
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
@@ -330,12 +332,14 @@ struct msdc_host {
struct pinctrl_state *pins_uhs;
struct delayed_work req_timeout;
int irq; /* host interrupt */
+ bool irq_thread_alive;
struct clk *src_clk; /* msdc source clock */
struct clk *h_clk; /* msdc h_clk */
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
u32 sclk; /* SD/MS bus clock frequency */
+ bool clock_on;
unsigned char timing;
bool vqmmc_enabled;
u32 hs400_ds_delay;
@@ -343,6 +347,7 @@ struct msdc_host {
u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
bool hs400_cmd_resp_sel_rising;
/* cmd response sample selection for HS400 */
+ u32 clk_pad_delay;
bool hs400_mode; /* current eMMC will run at hs400 mode */
struct msdc_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */
@@ -399,6 +404,7 @@ static void msdc_reset_hw(struct msdc_host *host)
static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd);
+static void msdc_recheck_sdio_irq(struct msdc_host *host);
static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
@@ -525,6 +531,7 @@ static void msdc_gate_clock(struct msdc_host *host)
{
clk_disable_unprepare(host->src_clk);
clk_disable_unprepare(host->h_clk);
+ host->clock_on = false;
}
static void msdc_ungate_clock(struct msdc_host *host)
@@ -533,6 +540,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
clk_prepare_enable(host->src_clk);
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax();
+ host->clock_on = true;
}
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
@@ -541,6 +549,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
u32 flags;
u32 div;
u32 sclk;
+ unsigned long irq_flags;
if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n");
@@ -549,8 +558,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
return;
}
+ spin_lock_irqsave(&host->irqlock, irq_flags);
flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags);
+ spin_unlock_irqrestore(&host->irqlock, irq_flags);
+
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
if (timing == MMC_TIMING_UHS_DDR50 ||
timing == MMC_TIMING_MMC_DDR52 ||
@@ -600,7 +612,10 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
host->timing = timing;
/* need because clk changed. */
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
+
+ spin_lock_irqsave(&host->irqlock, irq_flags);
sdr_set_bits(host->base + MSDC_INTEN, flags);
+ spin_unlock_irqrestore(&host->irqlock, irq_flags);
/*
* mmc_select_hs400() will drop to 50Mhz and High speed mode,
@@ -708,6 +723,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq,
struct mmc_command *cmd, struct mmc_data *data)
{
+ unsigned long flags;
bool read;
WARN_ON(host->data);
@@ -716,8 +732,12 @@ static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq,
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
msdc_dma_setup(host, &host->dma, data);
+
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_set_bits(host->base + MSDC_INTEN, data_ints_mask);
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
dev_dbg(host->dev, "DMA start\n");
dev_dbg(host->dev, "%s: cmd=%d DMA data: %d blocks; read=%d\n",
__func__, cmd->opcode, data->blocks, read);
@@ -774,6 +794,8 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
if (mrq->data)
msdc_unprepare_data(host, mrq);
mmc_request_done(host->mmc, mrq);
+
+ msdc_recheck_sdio_irq(host);
}
/* returns true if command is fully handled; returns false otherwise */
@@ -797,15 +819,17 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
| MSDC_INT_CMDTMO)))
return done;
- spin_lock_irqsave(&host->lock, flags);
done = !host->cmd;
+ spin_lock_irqsave(&host->lock, flags);
host->cmd = NULL;
spin_unlock_irqrestore(&host->lock, flags);
if (done)
return true;
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -883,6 +907,7 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host,
static void msdc_start_command(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd)
{
+ unsigned long flags;
u32 rawcmd;
WARN_ON(host->cmd);
@@ -901,7 +926,10 @@ static void msdc_start_command(struct msdc_host *host,
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
writel(cmd->arg, host->base + SDC_ARG);
writel(rawcmd, host->base + SDC_CMD);
}
@@ -993,8 +1021,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
| MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR
| MSDC_INT_DMA_PROTECT);
- spin_lock_irqsave(&host->lock, flags);
done = !host->data;
+ spin_lock_irqsave(&host->lock, flags);
if (check_data)
host->data = NULL;
spin_unlock_irqrestore(&host->lock, flags);
@@ -1009,7 +1037,11 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
1);
while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS)
cpu_relax();
+
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
dev_dbg(host->dev, "DMA stop\n");
if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) {
@@ -1123,44 +1155,47 @@ static void msdc_request_timeout(struct work_struct *work)
static irqreturn_t msdc_irq(int irq, void *dev_id)
{
+ unsigned long flags;
struct msdc_host *host = (struct msdc_host *) dev_id;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 events, event_mask;
+
+ spin_lock_irqsave(&host->irqlock, flags);
+ events = readl(host->base + MSDC_INT);
+ event_mask = readl(host->base + MSDC_INTEN);
+ /* clear interrupts */
+ writel(events & event_mask, host->base + MSDC_INT);
+
+ mrq = host->mrq;
+ cmd = host->cmd;
+ data = host->data;
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
+ if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
+ mmc_signal_sdio_irq(host->mmc);
+ if (!mrq)
+ return IRQ_HANDLED;
+ }
- while (true) {
- unsigned long flags;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- u32 events, event_mask;
-
- spin_lock_irqsave(&host->lock, flags);
- events = readl(host->base + MSDC_INT);
- event_mask = readl(host->base + MSDC_INTEN);
- /* clear interrupts */
- writel(events & event_mask, host->base + MSDC_INT);
-
- mrq = host->mrq;
- cmd = host->cmd;
- data = host->data;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (!(events & event_mask))
- break;
+ if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
+ return IRQ_HANDLED;
- if (!mrq) {
- dev_err(host->dev,
- "%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
- __func__, events, event_mask);
- WARN_ON(1);
- break;
- }
+ if (!mrq) {
+ dev_err(host->dev,
+ "%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
+ __func__, events, event_mask);
+ WARN_ON(1);
+ return IRQ_HANDLED;
+ }
- dev_dbg(host->dev, "%s: events=%08X\n", __func__, events);
+ dev_dbg(host->dev, "%s: events=%08X\n", __func__, events);
- if (cmd)
- msdc_cmd_done(host, events, mrq, cmd);
- else if (data)
- msdc_data_xfer_done(host, events, mrq, data);
- }
+ if (cmd)
+ msdc_cmd_done(host, events, mrq, cmd);
+ else if (data)
+ msdc_data_xfer_done(host, events, mrq, data);
return IRQ_HANDLED;
}
@@ -1168,6 +1203,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
static void msdc_init_hw(struct msdc_host *host)
{
u32 val;
+ unsigned long flags;
/* Configure to MMC/SD mode, clock free running */
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
@@ -1179,11 +1215,14 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
/* Disable and clear all interrupts */
+ spin_lock_irqsave(&host->irqlock, flags);
writel(0, host->base + MSDC_INTEN);
val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT);
+ spin_unlock_irqrestore(&host->irqlock, flags);
- writel(0, host->base + MSDC_PAD_TUNE);
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_CLKTDLY, host->clk_pad_delay);
writel(0, host->base + MSDC_IOCON);
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
writel(0x403c0046, host->base + MSDC_PATCH_BIT);
@@ -1196,9 +1235,11 @@ static void msdc_init_hw(struct msdc_host *host)
*/
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
- /* disable detect SDIO device interrupt function */
- sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
-
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ else
+ /* disable detect SDIO device interrupt function */
+ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
/* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
@@ -1210,11 +1251,15 @@ static void msdc_init_hw(struct msdc_host *host)
static void msdc_deinit_hw(struct msdc_host *host)
{
u32 val;
+ unsigned long flags;
+
/* Disable and clear all interrupts */
+ spin_lock_irqsave(&host->irqlock, flags);
writel(0, host->base + MSDC_INTEN);
val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT);
+ spin_unlock_irqrestore(&host->irqlock, flags);
}
/* init gpd and bd list in msdc_drv_probe */
@@ -1582,6 +1627,48 @@ static void msdc_hw_reset(struct mmc_host *mmc)
sdr_clr_bits(host->base + EMMC_IOCON, 1);
}
+/**
+ * msdc_recheck_sdio_irq - recheck whether the SDIO IRQ is lost
+ * @host: The host to check.
+ *
+ * Host controller may lost interrupt in some special case.
+ * Add sdio IRQ recheck mechanism to make sure all interrupts
+ * can be processed immediately
+ */
+static void msdc_recheck_sdio_irq(struct msdc_host *host)
+{
+ u32 reg_int, reg_ps;
+
+ if (host->clock_on && (host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
+ host->irq_thread_alive) {
+ reg_int = readl(host->base + MSDC_INT);
+ reg_ps = readl(host->base + MSDC_PS);
+ if (!((reg_int & MSDC_INT_SDIOIRQ) ||
+ (reg_ps & MSDC_PS_DATA1)))
+ mmc_signal_sdio_irq(host->mmc);
+ }
+}
+
+static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ unsigned long flags;
+ struct msdc_host *host = mmc_priv(mmc);
+
+ host->irq_thread_alive = true;
+ if (enable) {
+ msdc_recheck_sdio_irq(host);
+
+ spin_lock_irqsave(&host->irqlock, flags);
+ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+ } else {
+ spin_lock_irqsave(&host->irqlock, flags);
+ sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+ }
+}
+
static struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
@@ -1593,6 +1680,7 @@ static void msdc_hw_reset(struct mmc_host *mmc)
.execute_tuning = msdc_execute_tuning,
.prepare_hs400_tuning = msdc_prepare_hs400_tuning,
.hw_reset = msdc_hw_reset,
+ .enable_sdio_irq = msdc_enable_sdio_irq,
};
static void msdc_of_property_parse(struct platform_device *pdev,
@@ -1612,6 +1700,9 @@ static void msdc_of_property_parse(struct platform_device *pdev,
host->hs400_cmd_resp_sel_rising = true;
else
host->hs400_cmd_resp_sel_rising = false;
+
+ of_property_read_u32(pdev->dev.of_node, "mediatek,clk-pad-delay",
+ &host->clk_pad_delay);
}
static int msdc_drv_probe(struct platform_device *pdev)
@@ -1705,6 +1796,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc_dev(mmc)->dma_mask = &host->dma_mask;
host->timeout_clks = 3 * 1048576;
+ host->irq_thread_alive = false;
host->dma.gpd = dma_alloc_coherent(&pdev->dev,
2 * sizeof(struct mt_gpdma_desc),
&host->dma.gpd_addr, GFP_KERNEL);
@@ -1718,6 +1810,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
msdc_init_gpd_bd(host, &host->dma);
INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout);
spin_lock_init(&host->lock);
+ spin_lock_init(&host->irqlock);
platform_set_drvdata(pdev, mmc);
msdc_ungate_clock(host);
@@ -1732,6 +1825,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(host->dev);
pm_runtime_enable(host->dev);
+
+ /* In SDIO irq mode, DATA1 slways need to be detected */
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ pm_runtime_get_sync(host->dev);
ret = mmc_add_host(mmc);
if (ret)
@@ -1821,6 +1918,10 @@ static int msdc_runtime_suspend(struct device *dev)
msdc_save_reg(host);
msdc_gate_clock(host);
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
return 0;
}
@@ -1829,6 +1930,9 @@ static int msdc_runtime_resume(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msdc_host *host = mmc_priv(mmc);
+ /* In SDIO irq mode, DATA1 slways need to be detected */
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ pm_runtime_get_sync(host->dev);
msdc_ungate_clock(host);
msdc_restore_reg(host);
return 0;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 2/3] ARM64: dts: mediatek: Enable mmc3 for supporting sdio feature
From: Yong Mao @ 2017-04-18 10:13 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring
Cc: linux-arm-kernel, devicetree, srv_heupstream, Linus Walleij,
linux-mmc, linux-kernel, yong mao, linux-mediatek, Daniel Kurtz,
Eddie Huang, Chaotian Jing
In-Reply-To: <1492510391-704-1-git-send-email-yong.mao@mediatek.com>
From: yong mao <yong.mao@mediatek.com>
Add description of mmc3 for supporting sdio feature
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 77 +++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 1c3634f..fb8fa5c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -68,6 +68,14 @@
gpio = <&pio 9 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
+
+ sdio_fixed_3v3: regulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&pio 85 GPIO_ACTIVE_HIGH>;
+ };
};
&cec {
@@ -156,6 +164,25 @@
vqmmc-supply = <&mt6397_vmc_reg>;
};
+&mmc3 {
+ status = "okay";
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&mmc3_pins_default>;
+ pinctrl-1 = <&mmc3_pins_uhs>;
+ bus-width = <4>;
+ max-frequency = <200000000>;
+ cap-sd-highspeed;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ mediatek,clk-pad-delay = <5>;
+ keep-power-in-suspend;
+ enable-sdio-wakeup;
+ cap-sdio-irq;
+ vmmc-supply = <&sdio_fixed_3v3>;
+ vqmmc-supply = <&mt6397_vgp3_reg>;
+ non-removable;
+};
+
&pio {
disp_pwm0_pins: disp_pwm0_pins {
pins1 {
@@ -261,6 +288,56 @@
};
};
+ mmc3_pins_default: mmc3default {
+ pins_dat {
+ pinmux = <MT8173_PIN_22_MSDC3_DAT0__FUNC_MSDC3_DAT0>,
+ <MT8173_PIN_23_MSDC3_DAT1__FUNC_MSDC3_DAT1>,
+ <MT8173_PIN_24_MSDC3_DAT2__FUNC_MSDC3_DAT2>,
+ <MT8173_PIN_25_MSDC3_DAT3__FUNC_MSDC3_DAT3>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_cmd {
+ pinmux = <MT8173_PIN_27_MSDC3_CMD__FUNC_MSDC3_CMD>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_clk {
+ pinmux = <MT8173_PIN_26_MSDC3_CLK__FUNC_MSDC3_CLK>;
+ bias-pull-down;
+ drive-strength = <MTK_DRIVE_8mA>;
+ };
+ };
+
+ mmc3_pins_uhs: mmc3 {
+ pins_dat {
+ pinmux = <MT8173_PIN_22_MSDC3_DAT0__FUNC_MSDC3_DAT0>,
+ <MT8173_PIN_23_MSDC3_DAT1__FUNC_MSDC3_DAT1>,
+ <MT8173_PIN_24_MSDC3_DAT2__FUNC_MSDC3_DAT2>,
+ <MT8173_PIN_25_MSDC3_DAT3__FUNC_MSDC3_DAT3>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_cmd {
+ pinmux = <MT8173_PIN_27_MSDC3_CMD__FUNC_MSDC3_CMD>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_clk {
+ pinmux = <MT8173_PIN_26_MSDC3_CLK__FUNC_MSDC3_CLK>;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+ };
+ };
+
usb_id_pins_float: usb_iddig_pull_up {
pins_iddig {
pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 1/3] mmc: dt-bindings: update Mediatek MMC bindings
From: Yong Mao @ 2017-04-18 10:13 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring
Cc: Linus Walleij, Daniel Kurtz, Chaotian Jing, yong mao, Eddie Huang,
linux-mmc, srv_heupstream, linux-mediatek, linux-kernel,
linux-arm-kernel, devicetree
In-Reply-To: <1492510391-704-1-git-send-email-yong.mao@mediatek.com>
From: yong mao <yong.mao@mediatek.com>
Add description for mediatek,clk-pad-delay
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
Documentation/devicetree/bindings/mmc/mtk-sd.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
index 4182ea3..fbb3fd6 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -30,6 +30,7 @@ Optional properties:
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
If present,HS400 command responses are sampled on rising edges.
If not present,HS400 command responses are sampled on falling edges.
+- mediatek,clk-pad-delay: clock pad delay setting
Examples:
mmc0: mmc@11230000 {
@@ -50,4 +51,5 @@ mmc0: mmc@11230000 {
mediatek,hs200-cmd-int-delay = <26>;
mediatek,hs400-cmd-int-delay = <14>;
mediatek,hs400-cmd-resp-sel-rising;
+ mediatek,clk-pad-delay = <5>;
};
--
1.7.9.5
^ permalink raw reply related
* [RESEND v2] mmc: mediatek: Support SDIO feature
From: Yong Mao @ 2017-04-18 10:13 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring
Cc: Linus Walleij, Daniel Kurtz, Chaotian Jing, yong mao, Eddie Huang,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Documentation/devicetree/bindings/mmc/mtk-sd.txt | 2 +
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 77 ++++++++++
drivers/mmc/host/mtk-sd.c | 182 ++++++++++++++++++-----
3 files changed, 222 insertions(+), 39 deletions(-)
--
1.8.1.1.dirty
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Sakari Ailus @ 2017-04-18 10:08 UTC (permalink / raw)
To: Philipp Zabel
Cc: Peter Rosin, Pavel Machek, Rob Herring, Mark Rutland,
Steve Longerbeam, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <1492503544.2432.32.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Hi Philipp,
On Tue, Apr 18, 2017 at 10:19:04AM +0200, Philipp Zabel wrote:
> On Thu, 2017-04-13 at 17:48 +0200, Philipp Zabel wrote:
> > This adds device tree binding documentation for mmio-based syscon
> > multiplexers controlled by a single bitfield in a syscon register
> > range.
> >
> > Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> > ---
> > Documentation/devicetree/bindings/mux/mmio-mux.txt | 56 ++++++++++++++++++++++
> > 1 file changed, 56 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > new file mode 100644
> > index 0000000000000..11d96f5d98583
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> > @@ -0,0 +1,56 @@
> > +MMIO bitfield-based multiplexer controller bindings
> > +
> > +Define a syscon bitfield to be used to control a multiplexer. The parent
> > +device tree node must be a syscon node to provide register access.
> > +
> > +Required properties:
> > +- compatible : "gpio-mux"
> > +- reg : register base of the register containing the control bitfield
> > +- bit-mask : bitmask of the control bitfield in the control register
> > +- bit-shift : bit offset of the control bitfield in the control register
> > +- #mux-control-cells : <0>
> > +* Standard mux-controller bindings as decribed in mux-controller.txt
> > +
> > +Optional properties:
> > +- idle-state : if present, the state the mux will have when idle. The
> > + special state MUX_IDLE_AS_IS is the default.
> > +
> > +The multiplexer state is defined as the value of the bitfield described
> > +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> > +syscon.
> > +
> > +Example:
> > +
> > + syscon {
> > + compatible = "syscon";
> > +
> > + mux: mux-controller@3 {
> > + compatible = "mmio-mux";
> > + reg = <0x3>;
> > + bit-mask = <0x1>;
> > + bit-shift = <5>;
> > + #mux-control-cells = <0>;
> > + };
> > + };
> > +
> > + video-mux {
> > + compatible = "video-mux";
> > + mux-controls = <&mux>;
> > +
> > + ports {
> > + /* input 0 */
> > + port@0 {
> > + reg = <0>;
> > + };
> > +
> > + /* input 1 */
> > + port@1 {
> > + reg = <1>;
> > + };
> > +
> > + /* output */
> > + port@2 {
> > + reg = <2>;
> > + };
> > + };
> > + };
>
> So Pavel (added to Cc:) suggested to merge these into one node for the
> video mux, as really we are describing a single hardware entity that
> happens to be multiplexing multiple video buses into one:
Two drivers will be needed in a way or another to disconnect the dependency
between the video switch driver and the MUX implementation. Are there ways
to do that cleanly other than having two devices?
And if there are two devices, shouldn't the video switch device be a child
of the MUX device? I think it'd be odd to have it hanging around in a
completely unrelated part of the device tree.
>
> syscon {
> compatible = "syscon";
>
> /* video multiplexer */
> mux: mux-controller@3 {
> compatible = "video-mmio-mux";
> reg = <0x3>;
> bit-mask = <0x1>;
> bit-shift = <5>;
> #mux-control-cells = <0>;
>
> mux-controls = <&mux>;
>
> ports {
> /* input 0 */
> port@0 {
> reg = <0>;
> };
>
> /* input 1 */
> port@1 {
> reg = <1>;
> };
>
> /* output */
> port@2 {
> reg = <2>;
> };
> };
> };
> };
>
> That would not touch on this "general purpose" mmio-mux binding itself,
> but would make it necessary to add a separate "video-mmio-mux" and a
> "video-gpio-mux" binding that mirror the "mmio-mux" and "gpio-mux"
> bindings but add the OF-graph connections.
>
> Also I think in this case the self-referencing mux-controls property
> would be superfluous, as the driver binding to this node is expected to
> control the mux according to activation of the links described by the
> OF-graph bindings.
--
Kind regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org XMPP: sailus-PCDdDYkjdNMDXYZnReoRVg@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v13 02/10] dt-bindings: document devicetree bindings for mux-controllers and gpio-mux
From: Philipp Zabel @ 2017-04-18 10:06 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Greg Kroah-Hartman,
Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
Lars-Peter Clausen, Wolfram Sang,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet,
linux-doc-u79uwXL29TY76Z2rM5mHXA, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
Paul Gortmaker, Rob Herring, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
Peter Meerwald-Stadler, Hartmut Knaack, Colin Ian King,
Andrew Morton, Jonathan Cameron
In-Reply-To: <1492101794-13444-3-git-send-email-peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On Thu, 2017-04-13 at 18:43 +0200, Peter Rosin wrote:
> Allow specifying that a single multiplexer controller can be used to
> control several parallel multiplexers, thus enabling sharing of the
> multiplexer controller by different consumers.
>
> Add a binding for a first mux controller in the form of a GPIO based mux
> controller.
>
> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> ---
> Documentation/devicetree/bindings/mux/gpio-mux.txt | 69 +++++++++
> .../devicetree/bindings/mux/mux-controller.txt | 157 +++++++++++++++++++++
> MAINTAINERS | 6 +
> include/dt-bindings/mux/mux.h | 16 +++
> 4 files changed, 248 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mux/gpio-mux.txt
> create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
> create mode 100644 include/dt-bindings/mux/mux.h
>
> diff --git a/Documentation/devicetree/bindings/mux/gpio-mux.txt b/Documentation/devicetree/bindings/mux/gpio-mux.txt
> new file mode 100644
> index 000000000000..b8f746344d80
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/gpio-mux.txt
> @@ -0,0 +1,69 @@
> +GPIO-based multiplexer controller bindings
> +
> +Define what GPIO pins are used to control a multiplexer. Or several
> +multiplexers, if the same pins control more than one multiplexer.
> +
> +Required properties:
> +- compatible : "gpio-mux"
> +- mux-gpios : list of gpios used to control the multiplexer, least
> + significant bit first.
> +- #mux-control-cells : <0>
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- idle-state : if present, the state the mux will have when idle. The
> + special state MUX_IDLE_AS_IS is the default.
> +
> +The multiplexer state is defined as the number represented by the
> +multiplexer GPIO pins, where the first pin is the least significant
> +bit. An active pin is a binary 1, an inactive pin is a binary 0.
> +
> +Example:
> +
> + mux: mux-controller {
> + compatible = "gpio-mux";
> + #mux-control-cells = <0>;
> +
> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> + <&pioA 1 GPIO_ACTIVE_HIGH>;
> + };
> +
> + adc-mux {
> + compatible = "io-channel-mux";
> + io-channels = <&adc 0>;
> + io-channel-names = "parent";
> +
> + mux-controls = <&mux>;
> +
> + channels = "sync-1", "in", "out", "sync-2";
> + };
Could you explain in more detail the reasoning behind this split between
the mux controller and the actual mux?
For SoC internal video bus muxes that are controlled by a register
bitfield, it seems a bit strange to have to split them into two device
tree nodes.
Basically I'm trying to figure out whether a video mux (which has a mux
control plus OF-graph bindings to describe its ports and connections)
would fit into the same category as an adc-mux or i2c-mux, or whether it
would be better to handle them as a specialized form of mux-controller.
regards
Philipp
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/3] ARM: sun8i: a83t: Drop leading zeroes from device node addresses
From: Chen-Yu Tsai @ 2017-04-18 9:22 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, devicetree, linux-arm-kernel, linux-kernel,
linux-sunxi
In-Reply-To: <20170418090329.odixwybrkqvp2o7z@lukather>
On Tue, Apr 18, 2017 at 5:03 PM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> On Tue, Apr 18, 2017 at 12:22:04PM +0800, Chen-Yu Tsai wrote:
>> Kbuild now complains about leading zeroes in the address portion of
>> device node names.
>>
>> Get rid of them.
>>
>> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>> ---
>> arch/arm/boot/dts/sun8i-a83t.dtsi | 10 +++++-----
>> 1 file changed, 5 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
>> index 913aacafe8d5..82cb87f21b96 100644
>> --- a/arch/arm/boot/dts/sun8i-a83t.dtsi
>> +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
>> @@ -162,7 +162,7 @@
>> #size-cells = <1>;
>> ranges;
>>
>> - pio: pinctrl@01c20800 {
>> + pio: pinctrl@1c20800 {
>
> As far as I know this breaks Uboot's auto-addition of stdout-path
You're right. It breaks as Uboot has the path to the uarts hard-coded.
That sucks. And from what I can tell, it's not easily solvable by just
switching to serial alias based references. CONS_INDEX won't line up
on the A23/A33 Q8 tablets.
Maybe we can just keep the uart device node the same for now, but fix
all the other ones. We can come back and fix the uart later once we
figure out how to fix Uboot.
Regards
ChenYu
^ permalink raw reply
* Re: [PATCH 3/3] ARM: sun8i: a83t: Rename pinmux setting names
From: Chen-Yu Tsai @ 2017-04-18 9:16 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, devicetree, linux-arm-kernel, linux-kernel,
linux-sunxi
In-Reply-To: <20170418090447.dcxinewczubf26b7@lukather>
On Tue, Apr 18, 2017 at 5:04 PM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> On Tue, Apr 18, 2017 at 12:22:05PM +0800, Chen-Yu Tsai wrote:
>> The pinmux setting nodes all have an address element in their node
>> names, however the pinctrl node does not have #address-cells.
>>
>> Rename the existing pinmux setting nodes and labels in sun8i-a83t.dtsi,
>> dropping identifiers for functions that only have one possible setting,
>> and using the pingroup name if the function is identically available on
>> different pingroups.
>>
>> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>
> Applied, and I really like the new names.
>
> Would you make the same patch for everyone?
I can. No guarantees on the schedule though.
ChenYu
^ permalink raw reply
* Re: [PATCH v2 1/5] dt-bindings: gpu: add bindings for the ARM Mali Midgard GPU
From: Guillaume Tucker @ 2017-04-18 9:15 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Heiko Stuebner,
Sjoerd Simons, Wookey, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, John Reitan,
Enric Balletbo i Serra,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170404020056.d7osj7rmog22xbjd@rob-hp-laptop>
Hi Rob,
On 04/04/17 03:00, Rob Herring wrote:
> On Sun, Apr 02, 2017 at 08:59:44AM +0100, Guillaume Tucker wrote:
>> The ARM Mali Midgard GPU family is present in a number of SoCs
>> from many different vendors such as Samsung Exynos and Rockchip.
>>
>> Import the device tree bindings documentation from the r16p0
>> release of the Mali Midgard GPU kernel driver:
>>
>> https://developer.arm.com/-/media/Files/downloads/mali-drivers/kernel/mali-midgard-gpu/TX011-SW-99002-r16p0-00rel0.tgz
>>
>> The following optional bindings have been omitted in this initial
>> version as they are only used in very specific cases:
>>
>> * snoop_enable_smc
>> * snoop_disable_smc
>> * jm_config
>> * power_model
>> * system-coherency
>> * ipa-model
>>
>> The example has been simplified accordingly.
>>
>> The compatible string definition has been limited to
>> "arm,mali-midgard" to avoid checkpatch.pl warnings and to match
>> what the driver actually expects (as of r16p0 out-of-tree).
>>
>> CC: John Reitan <john.reitan-5wv7dgnIgG8@public.gmane.org>
>> Signed-off-by: Guillaume Tucker <guillaume.tucker-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
>> ---
>> .../devicetree/bindings/gpu/arm,mali-midgard.txt | 53 ++++++++++++++++++++++
>> 1 file changed, 53 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
>>
>> diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
>> new file mode 100644
>> index 000000000000..da8fc6d21bbf
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
>> @@ -0,0 +1,53 @@
>> +#
>> +# (C) COPYRIGHT 2013-2016 ARM Limited.
>> +# Copyright (C) 2017 Collabora Ltd
>> +#
>> +# This program is free software and is provided to you under the terms of the
>> +# GNU General Public License version 2 as published by the Free Software
>> +# Foundation, and any use by you of this program is subject to the terms
>> +# of such GNU licence.
>> +#
>> +
>> +
>> +ARM Mali Midgard GPU
>> +====================
>> +
>> +Required properties:
>> +
>> +- compatible : Should be "arm,mali-midgard".
>
> As Neil said...
Sure; as discussed in my previous emails.
>> +- reg : Physical base address of the device and length of the register area.
>> +- interrupts : Contains the three IRQ lines required by Mali Midgard devices.
>> +- interrupt-names : Contains the names of IRQ resources in the order they were
>> + provided in the interrupts property. Must contain: "JOB, "MMU", "GPU".
>> +
>> +Optional:
>> +
>> +- clocks : Phandle to clock for the Mali Midgard device.
>> +- clock-names : Shall be "clk_mali".
>
> "clk_" is redundant. Actually, if there is only 1 clock, then just drop
> names. But there's not at least a core and bus clock?
Only one clock needs to be provided with the Midgard GPU
architecture. It shares the same bus and system memory as the
CPU. So I'll remove clock-names in patch v3.
>> +- mali-supply : Phandle to regulator for the Mali device. Refer to
>> + Documentation/devicetree/bindings/regulator/regulator.txt for details.
>> +- operating-points : Refer to Documentation/devicetree/bindings/power/opp.txt
>> + for details.
>
> Is this going to be sufficient vs. operating-points-v2? Or should it be
> a power domain with OPPs?
In principle, switching to operating-points-v2 should be very
straightforward. I have smoke-tested the driver with an
operating-points-v2 table and a phandle to it inside the gpu node
in place of operating-points and it seems to be working fine. At
least it parsed the OPPs and got initialised correctly.
My understanding is that operating-points (v1) are not deprecated
so we could keep the bindings as-is, but please let me know
otherwise and I can try to address that in my next patch version.
In the documentation, it should only be the case of replacing
operating-points with operating-points-v2.
>> +
>> +Example for a Mali-T602:
>> +
>> +gpu@0xfc010000 {
>
> Drop the '0x'.
OK, I'm also updating the example with lower-case IRQ names, no
clock-names etc...
Thanks,
Guillaume
^ permalink raw reply
* Re: [PATCH v6 17/39] platform: add video-multiplexer subdevice driver
From: Pavel Machek @ 2017-04-18 9:05 UTC (permalink / raw)
To: Philipp Zabel
Cc: mark.rutland, andrew-ct.chen, minghsiu.tsai, nick, songjun.wu,
hverkuil, Steve Longerbeam, robert.jarzmik, devel, markus.heiser,
laurent.pinchart+renesas, shuah, linux, geert, Steve Longerbeam,
Sascha Hauer, linux-media, devicetree, sakari.ailus, arnd,
mchehab, bparrot, robh+dt, horms+renesas, tiffany.lin,
linux-arm-kernel, niklas.soderlund+renesas, gregkh, linux-kernel,
Sakari Ailus, jean-christophe.trotin, kernel
In-Reply-To: <1492502989.2432.23.camel@pengutronix.de>
[-- Attachment #1.1: Type: text/plain, Size: 989 bytes --]
Hi!
> That self-referencing mux-controls property looks a bit superfluous:
>
> mux: video-multiplexer {
> mux-controls = <&mux>;
> };
>
> Other than that, I'm completely fine with splitting the compatible into
> something like video-mux-gpio and video-mux-mmio and reusing the
> mux-gpios property for video-mux-gpio.
Agreed, I overseen that.
> > You should be able to use code in drivers/mux as a library...
>
> This is a good idea in principle, but this requires some rework of the
> mux subsystem, and that subsystem hasn't even landed yet. For now I'd
> like to focus on getting the DT bindings right.
>
> I'd honestly prefer to not add this rework as a requirement for the i.MX
> media drivers to get into staging.
Hmm. staging/ normally accepts code with bigger design problems than
that.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
[-- Attachment #2: Type: text/plain, Size: 169 bytes --]
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
^ permalink raw reply
* Re: [PATCH 3/3] ARM: sun8i: a83t: Rename pinmux setting names
From: Maxime Ripard @ 2017-04-18 9:04 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170418042205.27894-4-wens-jdAy2FN1RRM@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 705 bytes --]
On Tue, Apr 18, 2017 at 12:22:05PM +0800, Chen-Yu Tsai wrote:
> The pinmux setting nodes all have an address element in their node
> names, however the pinctrl node does not have #address-cells.
>
> Rename the existing pinmux setting nodes and labels in sun8i-a83t.dtsi,
> dropping identifiers for functions that only have one possible setting,
> and using the pingroup name if the function is identically available on
> different pingroups.
>
> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
Applied, and I really like the new names.
Would you make the same patch for everyone?
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH 2/3] ARM: sun8i: a83t: Drop leading zeroes from device node addresses
From: Maxime Ripard @ 2017-04-18 9:03 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170418042205.27894-3-wens-jdAy2FN1RRM@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 864 bytes --]
On Tue, Apr 18, 2017 at 12:22:04PM +0800, Chen-Yu Tsai wrote:
> Kbuild now complains about leading zeroes in the address portion of
> device node names.
>
> Get rid of them.
>
> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> ---
> arch/arm/boot/dts/sun8i-a83t.dtsi | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
> index 913aacafe8d5..82cb87f21b96 100644
> --- a/arch/arm/boot/dts/sun8i-a83t.dtsi
> +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
> @@ -162,7 +162,7 @@
> #size-cells = <1>;
> ranges;
>
> - pio: pinctrl@01c20800 {
> + pio: pinctrl@1c20800 {
As far as I know this breaks Uboot's auto-addition of stdout-path
Maxime
>
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers
From: Maxime Ripard @ 2017-04-18 9:00 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Rob Herring, Chen-Yu Tsai, David Airlie, Jernej Skrabec,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170416120849.54542-7-icenowy-h8G6r0blFSE@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 26565 bytes --]
On Sun, Apr 16, 2017 at 08:08:44PM +0800, Icenowy Zheng wrote:
> Allwinner have a new "Display Engine 2.0" in their new SoCs, which comes
> with mixers to do graphic processing and feed data to TCON, like the old
> backends and frontends.
>
> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
>
> Currently a lot of functions are still missing -- more investigations
> are needed to gain enough information for them.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> ---
> Changes in v4:
> - Killed some dead code according to Jernej.
>
> drivers/gpu/drm/sun4i/Kconfig | 10 +
> drivers/gpu/drm/sun4i/Makefile | 4 +
> drivers/gpu/drm/sun4i/sun8i_layer.c | 142 ++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_layer.h | 36 ++++
> drivers/gpu/drm/sun4i/sun8i_mixer.c | 381 ++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_mixer.h | 131 +++++++++++++
> 6 files changed, 704 insertions(+)
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index 5a8227f37cc4..15557484520d 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
> original Allwinner Display Engine, which has a backend to
> do some alpha blending and feed graphics to TCON. If M is
> selected the module will be called sun4i-backend.
> +
> +config DRM_SUN4I_SUN8I_MIXER
> + tristate "Support for Allwinner Display Engine 2.0 Mixer"
> + depends on DRM_SUN4I
> + default MACH_SUN8I
> + help
> + Choose this option if you have an Allwinner SoC with the
> + Allwinner Display Engine 2.0, which has a mixer to do some
> + graphics mixture and feed graphics to TCON, If M is
> + selected the module will be called sun8i-mixer.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 1db1068b9be1..7625c2dad1bb 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
> sun4i-backend-y += sun4i_layer.o
> sun4i-backend-y += sun4i_backend.o
>
> +sun8i-mixer-y += sun8i_layer.o
> +sun8i-mixer-y += sun8i_mixer.o
> +
> obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o
> obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
Please align the value using tabs.
> obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
> obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c b/drivers/gpu/drm/sun4i/sun8i_layer.c
> new file mode 100644
> index 000000000000..d70a90d963b0
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
> @@ -0,0 +1,142 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> + *
> + * Based on sun4i_layer.h, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "sun4i_crtc.h"
> +#include "sun8i_layer.h"
> +#include "sun8i_mixer.h"
> +
> +struct sun8i_plane_desc {
> + enum drm_plane_type type;
> + const uint32_t *formats;
> + uint32_t nformats;
> +};
> +
> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + return 0;
> +}
> +
> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> + struct sun8i_mixer *mixer = layer->mixer;
> +
> + sun8i_mixer_layer_enable(mixer, layer->id, false);
> +}
> +
> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> + struct sun8i_mixer *mixer = layer->mixer;
> +
> + sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
> + sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
> + sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
> + sun8i_mixer_layer_enable(mixer, layer->id, true);
> +}
> +
> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
> + .atomic_check = sun8i_mixer_layer_atomic_check,
> + .atomic_disable = sun8i_mixer_layer_atomic_disable,
> + .atomic_update = sun8i_mixer_layer_atomic_update,
> +};
> +
> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .destroy = drm_plane_cleanup,
> + .disable_plane = drm_atomic_helper_disable_plane,
> + .reset = drm_atomic_helper_plane_reset,
> + .update_plane = drm_atomic_helper_update_plane,
> +};
> +
> +static const uint32_t sun8i_mixer_layer_formats[] = {
> + DRM_FORMAT_RGB888,
> + DRM_FORMAT_XRGB8888,
> +};
> +
> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
> + {
> + .type = DRM_PLANE_TYPE_PRIMARY,
> + .formats = sun8i_mixer_layer_formats,
> + .nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
> + },
> +};
> +
> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
> + struct sun8i_mixer *mixer,
> + const struct sun8i_plane_desc *plane)
> +{
> + struct sun8i_layer *layer;
> + int ret;
> +
> + layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
> + if (!layer)
> + return ERR_PTR(-ENOMEM);
> +
> + /* possible crtcs are set later */
> + ret = drm_universal_plane_init(drm, &layer->plane, 0,
> + &sun8i_mixer_layer_funcs,
> + plane->formats, plane->nformats,
> + plane->type, NULL);
> + if (ret) {
> + dev_err(drm->dev, "Couldn't initialize layer\n");
> + return ERR_PTR(ret);
> + }
> +
> + drm_plane_helper_add(&layer->plane,
> + &sun8i_mixer_layer_helper_funcs);
> + layer->mixer = mixer;
> +
> + return layer;
> +}
> +
> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> + struct sun4i_crtc *crtc)
> +{
> + struct drm_plane **planes;
> + struct sun8i_mixer *mixer = crtc->engine;
> + int i;
> +
> + planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
> + sizeof(*planes), GFP_KERNEL);
> + if (!planes)
> + return ERR_PTR(-ENOMEM);
> +
> + for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
> + const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
> + struct sun8i_layer *layer;
> +
> + layer = sun8i_layer_init_one(drm, mixer, plane);
> + if (IS_ERR(layer)) {
> + dev_err(drm->dev, "Couldn't initialize %s plane\n",
> + i ? "overlay" : "primary");
> + return ERR_CAST(layer);
> + };
> +
> + layer->id = i;
> + planes[i] = &layer->plane;
> + };
> +
> + return planes;
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h b/drivers/gpu/drm/sun4i/sun8i_layer.h
> new file mode 100644
> index 000000000000..fe7e8a069d71
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> + *
> + * Based on sun4i_layer.h, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN8I_LAYER_H_
> +#define _SUN8I_LAYER_H_
> +
> +struct sun4i_crtc;
> +
> +struct sun8i_layer {
> + struct drm_plane plane;
> + struct sun4i_drv *drv;
> + struct sun8i_mixer *mixer;
> + int id;
> +};
> +
> +static inline struct sun8i_layer *
> +plane_to_sun8i_layer(struct drm_plane *plane)
> +{
> + return container_of(plane, struct sun8i_layer, plane);
> +}
> +
> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> + struct sun4i_crtc *crtc);
> +#endif /* _SUN8I_LAYER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> new file mode 100644
> index 000000000000..5cff3f3833a7
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -0,0 +1,381 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> + *
> + * Based on sun4i_backend.c, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include <linux/component.h>
> +#include <linux/reset.h>
> +#include <linux/of_device.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun8i_mixer.h"
> +#include "sun8i_layer.h"
> +#include "sunxi_engine.h"
> +
> +void sun8i_mixer_commit(void *mixer)
> +{
> + struct sun8i_mixer *sun8i_mixer = mixer;
> +
> + DRM_DEBUG_DRIVER("Committing changes\n");
> +
> + regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
> + SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
> +}
> +
> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> + int layer, bool enable)
> +{
> + u32 val;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> +
> + DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
> +
> + if (enable)
> + val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
> + else
> + val = 0;
> +
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
> +
> + /* Set the alpha configuration */
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
> +}
> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
Why do you need to export it?
> +
> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
> + u32 format, u32 *mode)
> +{
> + switch (format) {
> + case DRM_FORMAT_XRGB8888:
> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
> + break;
> +
> + case DRM_FORMAT_RGB888:
> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> +
> + DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
> +
> + if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
> + DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
> + state->crtc_w, state->crtc_h);
> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + DRM_DEBUG_DRIVER("Updating blender size\n");
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + DRM_DEBUG_DRIVER("Updating channel size\n");
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + }
> +
> + /* Set the line width */
> + DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
> + fb->pitches[0]);
> +
> + /* Set height and width */
> + DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
> + state->crtc_w, state->crtc_h);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
> + SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
> +
> + /* Set base coordinates */
> + DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
> + state->crtc_x, state->crtc_y);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
> + SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
> +
> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + bool interlaced = false;
> + u32 val;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> + int ret;
> +
> + if (plane->state->crtc)
> + interlaced = plane->state->crtc->state->adjusted_mode.flags
> + & DRM_MODE_FLAG_INTERLACE;
> +
> + regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
> + interlaced ?
> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
> +
> + DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> + interlaced ? "on" : "off");
You're not using interlaced anywhere.
> +
> + ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
> + &val);
> + if (ret) {
> + DRM_DEBUG_DRIVER("Invalid format\n");
> + return ret;
> + }
> +
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
> +
> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + struct drm_gem_cma_object *gem;
> + dma_addr_t paddr;
> + uint32_t paddr_u32;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> + int bpp;
> +
> + /* Get the physical address of the buffer in memory */
> + gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> + /* Compute the start of the displayed memory */
> + bpp = fb->format->cpp[0];
> + paddr = gem->paddr + fb->offsets[0];
> + paddr += (state->src_x >> 16) * bpp;
> + paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +
> + paddr_u32 = (uint32_t) paddr;
How does that work on 64-bits systems ?
> +
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
> + paddr_u32);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
> +
> +static const struct sunxi_engine_ops sun8i_engine_ops = {
> + .commit = sun8i_mixer_commit,
> + .layers_init = sun8i_layers_init,
Align with tabs.
> +};
> +
> +static struct regmap_config sun8i_mixer_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0xbfffc, /* guessed */
> +};
> +
> +static int sun8i_mixer_bind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct drm_device *drm = data;
> + struct sun4i_drv *drv = drm->dev_private;
> + struct sun8i_mixer *mixer;
> + struct resource *res;
> + void __iomem *regs;
> + int i, ret;
> +
> + mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
> + if (!mixer)
> + return -ENOMEM;
> + dev_set_drvdata(dev, mixer);
> + drv->engine = mixer;
> + drv->engine_ops = &sun8i_engine_ops;
> +
> + mixer->cfg = of_device_get_match_data(dev);
> + if (!mixer->cfg)
> + return -EINVAL;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + mixer->regs = devm_regmap_init_mmio(dev, regs,
> + &sun8i_mixer_regmap_config);
> + if (IS_ERR(mixer->regs)) {
> + dev_err(dev, "Couldn't create the mixer regmap\n");
> + return PTR_ERR(mixer->regs);
> + }
> +
> + mixer->reset = devm_reset_control_get(dev, NULL);
> + if (IS_ERR(mixer->reset)) {
> + dev_err(dev, "Couldn't get our reset line\n");
> + return PTR_ERR(mixer->reset);
> + }
> +
> + ret = reset_control_deassert(mixer->reset);
> + if (ret) {
> + dev_err(dev, "Couldn't deassert our reset line\n");
> + return ret;
> + }
> +
> + mixer->bus_clk = devm_clk_get(dev, "bus");
> + if (IS_ERR(mixer->bus_clk)) {
> + dev_err(dev, "Couldn't get the mixer bus clock\n");
> + ret = PTR_ERR(mixer->bus_clk);
> + goto err_assert_reset;
> + }
> + clk_prepare_enable(mixer->bus_clk);
> +
> + mixer->mod_clk = devm_clk_get(dev, "mod");
> + if (IS_ERR(mixer->mod_clk)) {
> + dev_err(dev, "Couldn't get the mixer module clock\n");
> + ret = PTR_ERR(mixer->mod_clk);
> + goto err_disable_bus_clk;
> + }
> + clk_prepare_enable(mixer->mod_clk);
> +
> + /* Reset the registers */
> + for (i = 0x0; i < 0x20000; i += 4)
> + regmap_write(mixer->regs, i, 0);
> +
> + /* Enable the mixer */
> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
> + SUN8I_MIXER_GLOBAL_CTL_RT_EN);
> +
> + /* Initialize blender */
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
> + SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
> + SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
> + SUN8I_MIXER_BLEND_BKCOLOR_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
> + SUN8I_MIXER_BLEND_MODE_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
> + SUN8I_MIXER_BLEND_CK_CTL_DEF);
> +
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
> + SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
> +
> + /* Select the first UI channel */
> + DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
> + mixer->cfg->vi_num);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
> + mixer->cfg->vi_num);
> +
> + return 0;
> +
> + clk_disable_unprepare(mixer->mod_clk);
> +err_disable_bus_clk:
> + clk_disable_unprepare(mixer->bus_clk);
> +err_assert_reset:
> + reset_control_assert(mixer->reset);
> + return ret;
> +}
> +
> +static void sun8i_mixer_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct sun8i_mixer *mixer = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(mixer->mod_clk);
> + clk_disable_unprepare(mixer->bus_clk);
> + reset_control_assert(mixer->reset);
> +}
> +
> +static const struct component_ops sun8i_mixer_ops = {
> + .bind = sun8i_mixer_bind,
> + .unbind = sun8i_mixer_unbind,
> +};
> +
> +static int sun8i_mixer_probe(struct platform_device *pdev)
> +{
> + return component_add(&pdev->dev, &sun8i_mixer_ops);
> +}
> +
> +static int sun8i_mixer_remove(struct platform_device *pdev)
> +{
> + component_del(&pdev->dev, &sun8i_mixer_ops);
> +
> + return 0;
> +}
> +
> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
> + .vi_num = 2,
> + .ui_num = 1,
> +};
> +
> +static const struct of_device_id sun8i_mixer_of_table[] = {
> + {
> + .compatible = "allwinner,sun8i-v3s-de2-mixer",
> + .data = &sun8i_v3s_mixer_cfg,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
> +
> +static struct platform_driver sun8i_mixer_platform_driver = {
> + .probe = sun8i_mixer_probe,
> + .remove = sun8i_mixer_remove,
> + .driver = {
> + .name = "sun8i-mixer",
> + .of_match_table = sun8i_mixer_of_table,
> + },
> +};
> +module_platform_driver(sun8i_mixer_platform_driver);
> +
> +MODULE_AUTHOR("Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>");
> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> new file mode 100644
> index 000000000000..a4a365ae44c9
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> @@ -0,0 +1,131 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN8I_MIXER_H_
> +#define _SUN8I_MIXER_H_
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_layer.h"
> +
> +#define SUN8I_MIXER_MAX_CHAN_COUNT 4
> +
> +#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
> +#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
> +
> +#define SUN8I_MIXER_GLOBAL_CTL 0x0
> +#define SUN8I_MIXER_GLOBAL_STATUS 0x4
> +#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
> +#define SUN8I_MIXER_GLOBAL_SIZE 0xc
> +
> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN 0x1
> +
> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE 0x1
> +
> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL 0x1000
> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x) (0x1004 + 0x10 * (x) + 0x8)
> +#define SUN8I_MIXER_BLEND_ROUTE 0x1080
> +#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
> +#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
> +#define SUN8I_MIXER_BLEND_OUTSIZE 0x108c
> +#define SUN8I_MIXER_BLEND_MODE(x) (0x1090 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_CK_CTL 0x10b0
> +#define SUN8I_MIXER_BLEND_CK_CFG 0x10b4
> +#define SUN8I_MIXER_BLEND_CK_MAX(x) (0x10c0 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
> +
> +/* The following numbers are some still unknown magic numbers */
> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF 0xff000000
> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF 0x00000101
> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF 0x0
> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF 0xff000000
> +#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301
> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF 0x0
> +
> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
> +
> +/*
> + * VI channels are not used now, but the support of them may be introduced in
> + * the future.
> + */
> +
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
> +
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(11, 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF (1 << 1)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888 (0 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888 (4 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888 (8 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF (0xff << 24)
> +
> +/*
> + * These sub-engines are still unknown now, the EN registers are here only to
> + * be used to disable these sub-engines.
> + */
> +#define SUN8I_MIXER_VSU_EN 0x20000
> +#define SUN8I_MIXER_GSU1_EN 0x30000
> +#define SUN8I_MIXER_GSU2_EN 0x40000
> +#define SUN8I_MIXER_GSU3_EN 0x50000
> +#define SUN8I_MIXER_FCE_EN 0xa0000
> +#define SUN8I_MIXER_BWS_EN 0xa2000
> +#define SUN8I_MIXER_LTI_EN 0xa4000
> +#define SUN8I_MIXER_PEAK_EN 0xa6000
> +#define SUN8I_MIXER_ASE_EN 0xa8000
> +#define SUN8I_MIXER_FCC_EN 0xaa000
> +#define SUN8I_MIXER_DCSC_EN 0xb0000
> +
> +struct sun8i_mixer_cfg {
> + int vi_num;
> + int ui_num;
> +};
> +
> +struct sun8i_mixer {
> + struct regmap *regs;
> +
> + const struct sun8i_mixer_cfg *cfg;
> +
> + struct reset_control *reset;
> +
> + struct clk *bus_clk;
> + struct clk *mod_clk;
> +};
> +
> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> + int layer, bool enable);
> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +#endif /* _SUN8I_MIXER_H_ */
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox