* [PATCH] pwm-backlight: Avoid backlight flicker when probed from DT
From: Philipp Zabel @ 2015-10-29 15:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1434126377-22545-1-git-send-email-p.zabel@pengutronix.de>
If the driver is probed from the device tree, and there is a phandle
property set on it, and the enable GPIO is already configured as output,
and the backlight is currently disabled, keep it disabled.
If all these conditions are met, assume there will be some other driver
that can enable the backlight at the appropriate time.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
Changes since v2:
- Leave GPIO configuration as is (GPIOD_ASIS) when requesting,
so we can actually check the initial state.
---
drivers/video/backlight/pwm_bl.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index ae3c6b6..8e9c261 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -199,6 +199,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct backlight_properties props;
struct backlight_device *bl;
struct pwm_bl_data *pb;
+ int initial_blank = FB_BLANK_UNBLANK;
+ bool phandle;
int ret;
if (!data) {
@@ -242,7 +244,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enabled = false;
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
- GPIOD_OUT_HIGH);
+ GPIOD_ASIS);
if (IS_ERR(pb->enable_gpio)) {
ret = PTR_ERR(pb->enable_gpio);
goto err_alloc;
@@ -264,12 +266,32 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enable_gpio = gpio_to_desc(data->enable_gpio);
}
+ phandle = of_find_property(pdev->dev.of_node, "phandle", NULL) != NULL;
+
+ if (pb->enable_gpio) {
+ /*
+ * If the driver is probed from the device tree and there is a
+ * phandle link pointing to the backlight node, it is safe to
+ * assume that another driver will enable the backlight at the
+ * appropriate time. Therefore, if it is disabled, keep it so.
+ */
+ if (phandle &&
+ gpiod_get_direction(pb->enable_gpio) = GPIOF_DIR_OUT &&
+ gpiod_get_value(pb->enable_gpio) = 0)
+ initial_blank = FB_BLANK_POWERDOWN;
+ else
+ gpiod_direction_output(pb->enable_gpio, 1);
+ }
+
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);
goto err_alloc;
}
+ if (phandle && !regulator_is_enabled(pb->power_supply))
+ initial_blank = FB_BLANK_POWERDOWN;
+
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER
&& !pdev->dev.of_node) {
@@ -320,6 +342,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
}
bl->props.brightness = data->dft_brightness;
+ bl->props.power = initial_blank;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
--
2.6.1
^ permalink raw reply related
* Re: [PATCH v2] pwm-backlight: fix the panel power sequence
From: YH Huang @ 2015-10-30 7:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1446133259.3274.52.camel@pengutronix.de>
Hi Hpilipp,
On Thu, 2015-10-29 at 16:40 +0100, Philipp Zabel wrote:
> Hi YH,
>
> Am Donnerstag, den 22.10.2015, 23:12 +0800 schrieb YH Huang:
> > In the case of the panel disabled by the bootloader,
> > your patch still has the following code and always enables the backlight
> > in the probe function.
> > pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
> > - GPIOD_OUT_HIGH);
>
> You are right.
>
> > What do you think if I remove these two lines in my patch?
> > if (pb->enable_gpio)
> > gpiod_direction_output(pb->enable_gpio, 0);
>
> That won't work if the gpio is still configured as input. How about I
> add the GPIOD_ASIS change to my patch you remove that and the above from
> yours?
I revise these two lines
if (pb->enable_gpio)
gpiod_direction_output(pb->enable_gpio, 0);
into
if (pb->enable_gpio) {
if(gpiod_get_value(pb->enable_gpio) = 0)
gpiod_direction_output(pb->enable_gpio, 0);
else
gpiod_direction_output(pb->enable_gpio, 1);
}
I am not sure what "phandle" is working for.
My change is like your patch but remove the "phandle related" and
"gpiod_get_direction(pb->enable_gpio) = GPIOF_DIR_OUT".
Do we really need these?
Also, do you think it is right that I do the "pwm_enable(pb->pwm);"
before "gpiod_set_value(pb->enable_gpio, 1);" in power on function?
Regards,
YH Huang
^ permalink raw reply
* Re: [PATCH v2] pwm-backlight: fix the panel power sequence
From: Philipp Zabel @ 2015-10-30 10:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1446190900.17558.16.camel@mtksdaap41>
Am Freitag, den 30.10.2015, 15:41 +0800 schrieb YH Huang:
> > That won't work if the gpio is still configured as input. How about I
> > add the GPIOD_ASIS change to my patch you remove that and the above from
> > yours?
>
> I revise these two lines
> if (pb->enable_gpio)
> gpiod_direction_output(pb->enable_gpio, 0);
> into
> if (pb->enable_gpio) {
> if(gpiod_get_value(pb->enable_gpio) = 0)
> gpiod_direction_output(pb->enable_gpio, 0);
> else
> gpiod_direction_output(pb->enable_gpio, 1);
> }
If the GPIO is still configured as an input, the return value of
gpiod_get_value could be random.
> I am not sure what "phandle" is working for.
The reasoning is that devices where there is no phandle link pointing to
the backlight (for example from a simple-panel node), we should keep the
current default behaviour (enable during probe).
> My change is like your patch but remove the "phandle related" and
> "gpiod_get_direction(pb->enable_gpio) = GPIOF_DIR_OUT".
> Do we really need these?
See above, I wanted to be careful not to change existing behavior in
unexpected ways.
> Also, do you think it is right that I do the "pwm_enable(pb->pwm);"
> before "gpiod_set_value(pb->enable_gpio, 1);" in power on function?
That is unclear to me, because I'm sure that depends on the actual
constant current LED driver used.
I suspect EN and PWM pins are completely independent on a lot of them,
so enabling EN last should be ok to work around the problem that the PWM
pin state might not be well defined when the PWM is disabled.
For example, the STCS1A datasheet doesn't mention any order for enabling
EN and PWM. In the LP8545 datasheet, the modes of operation state
diagram suggests that enabling EN first is the proper way, on the other
hand the PWM interface characteristics table also lists a startup delay
for a rising EN edge while PWM is already active.
But I'm not sure that there aren't any LED drivers that somehow have a
problem with this order.
regards
Philipp
^ permalink raw reply
* [PATCH] video:fbdev:core:Calculate the buffer alignment if buffer is not IO mapped.
From: Shailendra Verma @ 2015-10-30 11:41 UTC (permalink / raw)
To: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
Cc: linux-kernel, vidushi.koul
From: Shailendra Verma <Shailendra.v@samsung.com>
Moving the instruction "align = buf->buf_align - 1" just after the
verification of the buffer if it is IP mapped or not as the buffer
alignment is not required if it is IO mapped.Thus it will save an
extra instuction execution when buffer is IO mapped.
Signed-off-by: Shailendra Verma <Shailendra.v@samsung.com>
---
linux-4.3-rc6/drivers/video/fbdev/core/fbmem.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/linux-4.3-rc6/drivers/video/fbdev/core/fbmem.c b/linux-4.3-rc6/drivers/video/fbdev/core/fbmem.c
index 0705d88..d92ec99 100644
--- a/linux-4.3-rc6/drivers/video/fbdev/core/fbmem.c
+++ b/linux-4.3-rc6/drivers/video/fbdev/core/fbmem.c
@@ -157,7 +157,7 @@ EXPORT_SYMBOL(fb_pad_unaligned_buffer);
*/
char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
{
- u32 align = buf->buf_align - 1, offset;
+ u32 align, offset;
char *addr = buf->addr;
/* If IO mapped, we need to sync before access, no sharing of
@@ -169,6 +169,8 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size
return addr;
}
+ align = buf->buf_align - 1;
+
/* See if we fit in the remaining pixmap space */
offset = buf->offset + align;
offset &= ~align;
--
1.7.9.5
^ permalink raw reply related
* [PATCH] video:fbdev:core:Calculate the size for colormap only after the validation of length for col
From: Shailendra Verma @ 2015-10-30 11:48 UTC (permalink / raw)
To: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
Cc: linux-kernel, vidushi.koul
From: Shailendra Verma <shailendra.v@samsung.com>
While allocating the memory for color map, the memory size for colors
is being calculated before the validation of length for color map.
Moved the size calculation part after the validation of color map length.
Signed-off-by: Shailendra Verma <shailendra.v@samsung.com>
---
drivers/video/fbdev/core/fbcmap.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
index f89245b..45ad567 100644
--- a/drivers/video/fbdev/core/fbcmap.c
+++ b/drivers/video/fbdev/core/fbcmap.c
@@ -91,7 +91,7 @@ static const struct fb_cmap default_16_colors = {
int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
{
- int size = len * sizeof(u16);
+ int size;
int ret = -ENOMEM;
if (cmap->len != len) {
@@ -99,6 +99,7 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
if (!len)
return 0;
+ size = len * sizeof(u16);
cmap->red = kmalloc(size, flags);
if (!cmap->red)
goto fail;
--
1.9.1
^ permalink raw reply related
* [PATCH] video:fbdev:core:Allocate the memory for video mode after the validation of edid.
From: Shailendra Verma @ 2015-10-30 11:49 UTC (permalink / raw)
To: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
Cc: linux-kernel, vidushi.koul
From: Shailendra Verma <shailendra.v@samsung.com>
In this function "fb_create_modedb" the memory for video mode is getting
allocated before the edid validation.If the validation of edid fails
then we are freeing the allocated memory for the video mode and returning.
So moving the memory allocation part after the edid validation.There is no
need to allocate the memory before edid validation check and freeing if
validation gets failed.
Signed-off-by: Shailendra Verma <shailendra.v@samsung.com>
---
drivers/video/fbdev/core/fbmon.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 47c3191..476a5fd 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -620,16 +620,16 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
int num = 0, i, first = 1;
int ver, rev;
- mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
- if (mode = NULL)
- return NULL;
-
if (edid = NULL || !edid_checksum(edid) ||
!edid_check_header(edid)) {
- kfree(mode);
return NULL;
}
+ mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
+ if (mode = NULL)
+ return NULL;
+
+
ver = edid[EDID_STRUCT_VERSION];
rev = edid[EDID_STRUCT_REVISION];
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] pwm-backlight: Avoid backlight flicker when probed from DT
From: Lee Jones @ 2015-10-30 18:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1446133906-3076-1-git-send-email-p.zabel@pengutronix.de>
On Thu, 29 Oct 2015, Philipp Zabel wrote:
> If the driver is probed from the device tree, and there is a phandle
> property set on it, and the enable GPIO is already configured as output,
> and the backlight is currently disabled, keep it disabled.
> If all these conditions are met, assume there will be some other driver
> that can enable the backlight at the appropriate time.
>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
> ---
> Changes since v2:
> - Leave GPIO configuration as is (GPIOD_ASIS) when requesting,
> so we can actually check the initial state.
> ---
> drivers/video/backlight/pwm_bl.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index ae3c6b6..8e9c261 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -199,6 +199,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> struct backlight_properties props;
> struct backlight_device *bl;
> struct pwm_bl_data *pb;
> + int initial_blank = FB_BLANK_UNBLANK;
> + bool phandle;
> int ret;
>
> if (!data) {
> @@ -242,7 +244,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> pb->enabled = false;
>
> pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
> - GPIOD_OUT_HIGH);
> + GPIOD_ASIS);
> if (IS_ERR(pb->enable_gpio)) {
> ret = PTR_ERR(pb->enable_gpio);
> goto err_alloc;
> @@ -264,12 +266,32 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> pb->enable_gpio = gpio_to_desc(data->enable_gpio);
> }
>
> + phandle = of_find_property(pdev->dev.of_node, "phandle", NULL) != NULL;
This is a little ugly.
If this is the only way to identify the probedness of a device then
you probably want to neaten it up a little. I suggest something along
the lines of:
if (of_find_property(pdev->dev.of_node, "phandle", NULL))
already_probed = true;
Also, do you also want to check for "linux,phandle", as this is always
catered for in drivers/of/*
> + if (pb->enable_gpio) {
> + /*
> + * If the driver is probed from the device tree and there is a
> + * phandle link pointing to the backlight node, it is safe to
> + * assume that another driver will enable the backlight at the
> + * appropriate time. Therefore, if it is disabled, keep it so.
> + */
> + if (phandle &&
> + gpiod_get_direction(pb->enable_gpio) = GPIOF_DIR_OUT &&
> + gpiod_get_value(pb->enable_gpio) = 0)
> + initial_blank = FB_BLANK_POWERDOWN;
> + else
> + gpiod_direction_output(pb->enable_gpio, 1);
> + }
> +
> pb->power_supply = devm_regulator_get(&pdev->dev, "power");
> if (IS_ERR(pb->power_supply)) {
> ret = PTR_ERR(pb->power_supply);
> goto err_alloc;
> }
>
> + if (phandle && !regulator_is_enabled(pb->power_supply))
> + initial_blank = FB_BLANK_POWERDOWN;
> +
> pb->pwm = devm_pwm_get(&pdev->dev, NULL);
> if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER
> && !pdev->dev.of_node) {
> @@ -320,6 +342,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> }
>
> bl->props.brightness = data->dft_brightness;
> + bl->props.power = initial_blank;
> backlight_update_status(bl);
>
> platform_set_drvdata(pdev, bl);
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [RESEND PATCH v2] backlight: pm8941-wled: Add default-brightness property
From: Lee Jones @ 2015-10-30 18:49 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Jingoo Han,
Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Rob Clark,
devicetree, linux-kernel, linux-fbdev, linux-arm-msm
In-Reply-To: <1445881508-18025-1-git-send-email-bjorn.andersson@sonymobile.com>
On Mon, 26 Oct 2015, Bjorn Andersson wrote:
> Default the brightness to 2048 and add possibility to override this in
> device tree.
>
> Suggested-by: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
> ---
>
> Resend of v2, with updated backlight dt binding location.
>
> Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt | 2 ++
In future please submit documentation as a separate patch.
> drivers/video/backlight/pm8941-wled.c | 8 ++++++++
> 2 files changed, 10 insertions(+)
Applied with Rob's Ack.
> diff --git a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt b/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt
> index 424f8444a6cd..e5b294dafc58 100644
> --- a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt
> +++ b/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt
> @@ -5,6 +5,8 @@ Required properties:
> - reg: slave address
>
> Optional properties:
> +- default-brightness: brightness value on boot, value from: 0-4095
> + default: 2048
> - label: The name of the backlight device
> - qcom,cs-out: bool; enable current sink output
> - qcom,cabc: bool; enable content adaptive backlight control
> diff --git a/drivers/video/backlight/pm8941-wled.c b/drivers/video/backlight/pm8941-wled.c
> index c704c3236034..e1298147bcbb 100644
> --- a/drivers/video/backlight/pm8941-wled.c
> +++ b/drivers/video/backlight/pm8941-wled.c
> @@ -17,6 +17,9 @@
> #include <linux/of_device.h>
> #include <linux/regmap.h>
>
> +/* From DT binding */
> +#define PM8941_WLED_DEFAULT_BRIGHTNESS 2048
> +
> #define PM8941_WLED_REG_VAL_BASE 0x40
> #define PM8941_WLED_REG_VAL_MAX 0xFFF
>
> @@ -373,6 +376,7 @@ static int pm8941_wled_probe(struct platform_device *pdev)
> struct backlight_device *bl;
> struct pm8941_wled *wled;
> struct regmap *regmap;
> + u32 val;
> int rc;
>
> regmap = dev_get_regmap(pdev->dev.parent, NULL);
> @@ -395,8 +399,12 @@ static int pm8941_wled_probe(struct platform_device *pdev)
> if (rc)
> return rc;
>
> + val = PM8941_WLED_DEFAULT_BRIGHTNESS;
> + of_property_read_u32(pdev->dev.of_node, "default-brightness", &val);
> +
> memset(&props, 0, sizeof(struct backlight_properties));
> props.type = BACKLIGHT_RAW;
> + props.brightness = val;
> props.max_brightness = PM8941_WLED_REG_VAL_MAX;
> bl = devm_backlight_device_register(&pdev->dev, wled->name,
> &pdev->dev, wled,
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re:Hi
From: hi @ 2015-10-31 3:52 UTC (permalink / raw)
To: linux-fbdev
SGkNCmdvb2QgbmV3cyBmb3IgeW91DQpkaix3YXRjaCxpcGhvbmUsc2Ftc3VuZyBwcm9kdWN0cyxn
dWx0YXIuLi4udGhlIHNoaXBwaW5nIGlzIGZyZWUsIHRoZSBwcmljZSBpcyBnb29kIA0Kc2Ftc3Vu
ZyBzNiBlZGdlKyAgMzAwZXVybw0KdyBlYjogICBwb2F6emxvIC5jb20NCg=
^ permalink raw reply
* Mobility Radeon HD 4530/4570/545v: flicker in 1920x1080
From: Pavel Machek @ 2015-10-31 20:13 UTC (permalink / raw)
To: alexander.deucher, christian.koenig, dri-devel, kernel list,
linux-fbdev
Hi!
4.3-rc7 kernel, graphics works reasonably well in 1600x1200 mode. But
my monitor is native 1920x1080, so that mode looks pretty ugly on
screen. If I go to 1920x1080, I see colored horizontal lines (often
black) as soon as there's graphics activity.
pavel@half:~$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
VGA-0 connected 1920x1080+0+0 (normal left inverted right x axis y
axis) 478mm x 268mm
1920x1080 60.00*+
1600x1200 60.00
1680x1050 59.95
1280x1024 75.02 60.02
1440x900 59.89
1024x768 75.08 60.00
800x600 75.00 60.32
640x480 75.00 60.00
720x400 70.08
pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
pavel@half:~$ xrandr --output VGA-0 --mode 1920x1080
pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
This is Acer notebook,
01:00.0 VGA compatible controller: Advanced Micro Devices,
Inc. [AMD/ATI] RV710/M92 [Mobility Radeon HD 4530/4570/545v]
Ouch, and power consumption seems to be 8W too high. (25W instead of
17W), I believe it started when I added radeon firmware, but will
check. It does not go lower even when I switch to text console.
Any ideas?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: Mobility Radeon HD 4530/4570/545v: flicker in 1920x1080
From: Christian König @ 2015-10-31 20:21 UTC (permalink / raw)
To: Pavel Machek, alexander.deucher, dri-devel, kernel list,
linux-fbdev
In-Reply-To: <20151031201344.GA30459@amd>
On 31.10.2015 21:13, Pavel Machek wrote:
> Hi!
>
> 4.3-rc7 kernel, graphics works reasonably well in 1600x1200 mode. But
> my monitor is native 1920x1080, so that mode looks pretty ugly on
> screen. If I go to 1920x1080, I see colored horizontal lines (often
> black) as soon as there's graphics activity.
>
> pavel@half:~$ xrandr
> Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
> VGA-0 connected 1920x1080+0+0 (normal left inverted right x axis y
> axis) 478mm x 268mm
> 1920x1080 60.00*+
> 1600x1200 60.00
> 1680x1050 59.95
> 1280x1024 75.02 60.02
> 1440x900 59.89
> 1024x768 75.08 60.00
> 800x600 75.00 60.32
> 640x480 75.00 60.00
> 720x400 70.08
> pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
> pavel@half:~$ xrandr --output VGA-0 --mode 1920x1080
> pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
>
>
> This is Acer notebook,
>
> 01:00.0 VGA compatible controller: Advanced Micro Devices,
> Inc. [AMD/ATI] RV710/M92 [Mobility Radeon HD 4530/4570/545v]
>
> Ouch, and power consumption seems to be 8W too high. (25W instead of
> 17W), I believe it started when I added radeon firmware, but will
> check. It does not go lower even when I switch to text console.
>
> Any ideas?
Alex probably knows more about this, but it sounds like problems with
switching the memory clocks on 3D load.
Try to disable power management completely with radeon.dpm=0 on the
kernel command line or nailing the hardware at a specific power level
using sysfs.
Power consumption would be totally awkward, but it should help nailing
down the problem.
Regards,
Christian.
>
> Pavel
^ permalink raw reply
* Re: Mobility Radeon HD 4530/4570/545v: flicker in 1920x1080
From: Pavel Machek @ 2015-10-31 21:22 UTC (permalink / raw)
To: Christian König
Cc: alexander.deucher, linux-fbdev, kernel list, dri-devel
In-Reply-To: <563522C5.1000206@amd.com>
Hi!
> >4.3-rc7 kernel, graphics works reasonably well in 1600x1200 mode. But
> >my monitor is native 1920x1080, so that mode looks pretty ugly on
> >screen. If I go to 1920x1080, I see colored horizontal lines (often
> >black) as soon as there's graphics activity.
> >
> >pavel@half:~$ xrandr
> >Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
> >VGA-0 connected 1920x1080+0+0 (normal left inverted right x axis y
> >axis) 478mm x 268mm
> > 1920x1080 60.00*+
> > 1600x1200 60.00
> > 1680x1050 59.95
> > 1280x1024 75.02 60.02
> > 1440x900 59.89
> > 1024x768 75.08 60.00
> > 800x600 75.00 60.32
> > 640x480 75.00 60.00
> > 720x400 70.08
> > pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
> > pavel@half:~$ xrandr --output VGA-0 --mode 1920x1080
> > pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
> >
> >
> >This is Acer notebook,
> >
> >01:00.0 VGA compatible controller: Advanced Micro Devices,
> >Inc. [AMD/ATI] RV710/M92 [Mobility Radeon HD 4530/4570/545v]
> >Any ideas?
>
> Alex probably knows more about this, but it sounds like problems with
> switching the memory clocks on 3D load.
> Try to disable power management completely with radeon.dpm=0 on the kernel
> command line or nailing the hardware at a specific power level using
> sysfs.
I tried that, but it still flickers.
pavel@half:~/misc/fgfs$ cat /proc/cmdline
BOOT_IMAGE=(hd0,2)/l/linux/arch/x86/boot/bzImage root=/dev/sda4
resume=/dev/sda1 radeon.dpm=0
> Power consumption would be totally awkward, but it should help nailing down
> the problem.
It seems chromium makes the flicker way worse.. even when running on
different virtual desktop. I'm not sure which sysfs settings I should
tweak (or if I should be tweaking them with .dpm=0). But sysfs says:
pavel@half:/sys/bus/pci/drivers/radeon/0000:01:00.0$ ls
backlight drm
irq
resource
boot_vga enable local_cpulist resource0
broken_parity_status firmware_node local_cpus resource0_wc
class graphics
modalias resource1
config
i2c-0 msi_bus resource2
consistent_dma_mask_bits i2c-1 power rom
d3cold_allowed i2c-2
power_method subsystem
device
i2c-3 power_profile subsystem_device
dma_mask_bits i2c-4 remove
subsystem_vendor
driver i2c-5 rescan uevent
driver_override i2c-6 reset
vendor
pavel@half:/sys/bus/pci/drivers/radeon/0000:01:00.0$ grep . *
grep: backlight: Is a directory
boot_vga:1
broken_parity_status:0
class:0x030000
Binary file config matches
consistent_dma_mask_bits:40
d3cold_allowed:1
device:0x9553
dma_mask_bits:40
grep: driver: Is a directory
driver_override:(null)
grep: drm: Is a directory
enable:1
grep: firmware_node: Is a directory
grep: graphics: Is a directory
grep: i2c-0: Is a directory
grep: i2c-1: Is a directory
grep: i2c-2: Is a directory
grep: i2c-3: Is a directory
grep: i2c-4: Is a directory
grep: i2c-5: Is a directory
grep: i2c-6: Is a directory
irq:16
local_cpulist:0-3
local_cpus:f
modalias:pci:v00001002d00009553sv00001025sd00000212bc03sc00i00
msi_bus:1
grep: power: Is a directory
power_method:profile
power_profile:default
grep: remove: Permission denied
grep: rescan: Permission denied
grep: reset: Permission denied
resource:0x00000000c0000000 0x00000000cfffffff 0x0000000000042208
resource:0x0000000000005000 0x00000000000050ff 0x0000000000040101
resource:0x00000000d6200000 0x00000000d620ffff 0x0000000000040200
resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
resource:0x00000000d6220000 0x00000000d623ffff 0x0000000000046202
grep: resource0: Permission denied
grep: resource0_wc: Permission denied
grep: resource1: Permission denied
grep: resource2: Permission denied
grep: rom: Permission denied
grep: subsystem: Is a directory
subsystem_device:0x0212
subsystem_vendor:0x1025
uevent:DRIVER=radeon
uevent:PCI_CLASS0000
uevent:PCI_ID\x1002:9553
uevent:PCI_SUBSYS_ID\x1025:0212
uevent:PCI_SLOT_NAME\000:01:00.0
uevent:MODALIAS=pci:v00001002d00009553sv00001025sd00000212bc03sc00i00
vendor:0x1002
Thanks,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH v7 12/26] powerpc: Cleanup nvram includes
From: Finn Thain @ 2015-11-01 10:42 UTC (permalink / raw)
To: linux-kernel, linux-m68k, linuxppc-dev, Benjamin Herrenschmidt,
Paul Mackerras, Michael Ellerman, Arnd Bergmann,
Greg Kroah-Hartman, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, linux-fbdev
In-Reply-To: <20151101104202.301856132@telegraphics.com.au>
The nvram_read_byte() and nvram_write_byte() definitions in asm/nvram.h
duplicate those in linux/nvram.h. Get rid of the former to prepare for
adoption of struct arch_nvram_ops (which is defined in linux/nvram.h for
general use).
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
Changes since v4:
- Fix possible git bisect build failure with CONFIG_PPC_PMAC=n.
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 1 +
drivers/char/generic_nvram.c | 1 +
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
4 files changed, 3 insertions(+), 4 deletions(-)
Index: linux/arch/powerpc/include/asm/nvram.h
=================================--- linux.orig/arch/powerpc/include/asm/nvram.h 2015-11-01 21:41:24.000000000 +1100
+++ linux/arch/powerpc/include/asm/nvram.h 2015-11-01 21:41:38.000000000 +1100
@@ -101,7 +101,4 @@ extern int nvram_write_os_partition(stru
/* Determine NVRAM size */
extern ssize_t nvram_get_size(void);
-/* Normal access to NVRAM */
-extern unsigned char nvram_read_byte(int i);
-extern void nvram_write_byte(unsigned char c, int i);
#endif /* _ASM_POWERPC_NVRAM_H */
Index: linux/arch/powerpc/kernel/setup_32.c
=================================--- linux.orig/arch/powerpc/kernel/setup_32.c 2015-11-01 21:41:24.000000000 +1100
+++ linux/arch/powerpc/kernel/setup_32.c 2015-11-01 21:41:38.000000000 +1100
@@ -16,6 +16,7 @@
#include <linux/cpu.h>
#include <linux/console.h>
#include <linux/memblock.h>
+#include <linux/nvram.h>
#include <asm/io.h>
#include <asm/prom.h>
Index: linux/drivers/video/fbdev/matrox/matroxfb_base.c
=================================--- linux.orig/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:24.000000000 +1100
+++ linux/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:38.000000000 +1100
@@ -111,12 +111,12 @@
#include "matroxfb_g450.h"
#include <linux/matroxfb.h>
#include <linux/interrupt.h>
+#include <linux/nvram.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
-unsigned char nvram_read_byte(int);
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
#endif
Index: linux/drivers/char/generic_nvram.c
=================================--- linux.orig/drivers/char/generic_nvram.c 2015-11-01 21:41:24.000000000 +1100
+++ linux/drivers/char/generic_nvram.c 2015-11-01 21:41:38.000000000 +1100
@@ -20,6 +20,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/nvram.h>
#include <asm/uaccess.h>
#include <asm/nvram.h>
#ifdef CONFIG_PPC_PMAC
^ permalink raw reply
* [PATCH v7 16/26] powerpc, fbdev: Use NV_CMODE and NV_VMODE only when CONFIG_PPC32 and CONFIG_PPC_PMA
From: Finn Thain @ 2015-11-01 10:42 UTC (permalink / raw)
To: linux-kernel, linux-m68k, linuxppc-dev,
Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
In-Reply-To: <20151101104202.301856132@telegraphics.com.au>
This patch addresses inconsistencies in Mac framebuffer drivers and their
use of Kconfig symbols relating to NVRAM, so PPC64 can use CONFIG_NVRAM.
Macintosh framebuffer drivers use default settings for color mode and
video mode that are found in NVRAM. On PCI Macs, MacOS stores display
settings in the Name Registry (NR) partition in NVRAM*. On NuBus Macs,
there is no NR partition and MacOS stores display mode settings in PRAM**.
Early model Macs are the ones most likely to benefit from these settings,
since they are more likely to have one display: a fixed-frequency monitor
connected to the built-in framebuffer device. Moreover, a single NV_CMODE
value and a single NV_VMODE value provide for only one display.
The NV_CMODE and NV_VMODE constants are apparently offsets into the NR
partition for Old World machines and not New World, which also suggests
that these defaults are not useful on later models.
All this argues for limiting NVRAM support in PowerMac fbdev drivers to
PPC32 and indeed this is already the case, since CONFIG_NVRAM cannot be
enabled on PPC64 at present.
For matroxfb, make the CONFIG_PPC32 condition explicit. That way the
driver won't crash on PPC64 when CONFIG_NVRAM becomes available there.
In imsttfb, add the missing CONFIG_NVRAM test to prevent a build failure,
since PPC64 does not implement nvram_read_byte(). Also add a missing
machine_is(powermac) check. Change the inconsistent CONFIG_PPC dependency
and the matching #ifdef tests to CONFIG_PPC_PMAC. Drop unused #includes.
In valkyriefb, for clarity and consistency with the other PowerMac fbdev
drivers, test for CONFIG_PPC_PMAC instead of !CONFIG_MAC. Remove a
bogus comment regarding PRAM.
* See GetPreferredConfiguration and SavePreferredConfiguration in
"Designing PCI Cards and Drivers for Power Macintosh Computers".
** See SetDefaultMode and GetDefaultMode in "Designing Cards and Drivers
for the Macintosh Family".
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
drivers/video/fbdev/Kconfig | 2 +-
drivers/video/fbdev/imsttfb.c | 13 +++++--------
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
drivers/video/fbdev/valkyriefb.c | 14 ++++++--------
4 files changed, 13 insertions(+), 18 deletions(-)
Index: linux/drivers/video/fbdev/Kconfig
=================================--- linux.orig/drivers/video/fbdev/Kconfig 2015-11-01 21:41:23.000000000 +1100
+++ linux/drivers/video/fbdev/Kconfig 2015-11-01 21:41:43.000000000 +1100
@@ -544,7 +544,7 @@ config FB_IMSTT
bool "IMS Twin Turbo display support"
depends on (FB = y) && PCI
select FB_CFB_IMAGEBLIT
- select FB_MACMODES if PPC
+ select FB_MACMODES if PPC_PMAC
help
The IMS Twin Turbo is a PCI-based frame buffer card bundled with
many Macintosh and compatible computers.
Index: linux/drivers/video/fbdev/imsttfb.c
=================================--- linux.orig/drivers/video/fbdev/imsttfb.c 2015-11-01 21:41:23.000000000 +1100
+++ linux/drivers/video/fbdev/imsttfb.c 2015-11-01 21:41:43.000000000 +1100
@@ -30,10 +30,8 @@
#include <asm/io.h>
#include <linux/uaccess.h>
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
#include <linux/nvram.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include "macmodes.h"
#endif
@@ -328,14 +326,13 @@ enum {
TVP = 1
};
-#define USE_NV_MODES 1
#define INIT_BPP 8
#define INIT_XRES 640
#define INIT_YRES 480
static int inverse = 0;
static char fontname[40] __initdata = { 0 };
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
static signed char init_vmode = -1, init_cmode = -1;
#endif
@@ -1391,8 +1388,8 @@ static void init_imstt(struct fb_info *i
}
}
-#if USE_NV_MODES && defined(CONFIG_PPC32)
- {
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
+ if (machine_is(powermac)) {
int vmode = init_vmode, cmode = init_cmode;
if (vmode = -1) {
@@ -1566,7 +1563,7 @@ imsttfb_setup(char *options)
inverse = 1;
fb_invert_cmaps();
}
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
else if (!strncmp(this_opt, "vmode:", 6)) {
int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
Index: linux/drivers/video/fbdev/matrox/matroxfb_base.c
=================================--- linux.orig/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:38.000000000 +1100
+++ linux/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:43.000000000 +1100
@@ -1876,7 +1876,7 @@ static int initMatrox2(struct matrox_fb_
struct fb_var_screeninfo var;
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
-#ifdef CONFIG_NVRAM
+#if defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
if (default_cmode = CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
Index: linux/drivers/video/fbdev/valkyriefb.c
=================================--- linux.orig/drivers/video/fbdev/valkyriefb.c 2015-11-01 21:41:23.000000000 +1100
+++ linux/drivers/video/fbdev/valkyriefb.c 2015-11-01 21:41:43.000000000 +1100
@@ -65,14 +65,12 @@
#include "macmodes.h"
#include "valkyriefb.h"
-#ifdef CONFIG_MAC
-/* We don't yet have functions to read the PRAM... perhaps we can
- adapt them from the PPC code? */
-static int default_vmode = VMODE_CHOOSE;
-static int default_cmode = CMODE_8;
-#else
+#ifdef CONFIG_PPC_PMAC
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
+#else
+static int default_vmode = VMODE_CHOOSE;
+static int default_cmode = CMODE_8;
#endif
struct fb_par_valkyrie {
@@ -285,7 +283,7 @@ static void __init valkyrie_choose_mode(
printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);
/* Try to pick a video mode out of NVRAM if we have one. */
-#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_vmode = VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0
@@ -298,7 +296,7 @@ static void __init valkyrie_choose_mode(
default_vmode = mac_map_monitor_sense(p->sense);
if (!valkyrie_reg_init[default_vmode - 1])
default_vmode = VMODE_640_480_67;
-#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_cmode = CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
^ permalink raw reply
* [PATCH v7 17/26] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_w
From: Finn Thain @ 2015-11-01 10:42 UTC (permalink / raw)
To: linux-kernel, linux-m68k, linuxppc-dev, Benjamin Herrenschmidt,
Paul Mackerras, Michael Ellerman, Arnd Bergmann,
Greg Kroah-Hartman, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, linux-fbdev
In-Reply-To: <20151101104202.301856132@telegraphics.com.au>
Make use of arch_nvram_ops in device drivers so that the nvram_* function
exports can be removed.
Since they are no longer global symbols, rename the PPC32 nvram_* functions
appropriately.
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
Changed since v4:
- Split off the CONFIG_PPC32, CONFIG_PPC_PMAC and CONFIG_NVRAM tests into
a separate patch.
---
arch/powerpc/kernel/setup_32.c | 8 ++++----
drivers/char/generic_nvram.c | 4 ++--
drivers/video/fbdev/controlfb.c | 4 ++--
drivers/video/fbdev/imsttfb.c | 4 ++--
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
drivers/video/fbdev/platinumfb.c | 4 ++--
drivers/video/fbdev/valkyriefb.c | 4 ++--
7 files changed, 15 insertions(+), 15 deletions(-)
Index: linux/arch/powerpc/kernel/setup_32.c
=================================--- linux.orig/arch/powerpc/kernel/setup_32.c 2015-11-01 21:41:42.000000000 +1100
+++ linux/arch/powerpc/kernel/setup_32.c 2015-11-01 21:41:45.000000000 +1100
@@ -176,20 +176,18 @@ __setup("l3cr=", ppc_setup_l3cr);
#ifdef CONFIG_GENERIC_NVRAM
-unsigned char nvram_read_byte(int addr)
+static unsigned char ppc_nvram_read_byte(int addr)
{
if (ppc_md.nvram_read_val)
return ppc_md.nvram_read_val(addr);
return 0xff;
}
-EXPORT_SYMBOL(nvram_read_byte);
-void nvram_write_byte(unsigned char val, int addr)
+static void ppc_nvram_write_byte(unsigned char val, int addr)
{
if (ppc_md.nvram_write_val)
ppc_md.nvram_write_val(addr, val);
}
-EXPORT_SYMBOL(nvram_write_byte);
static ssize_t ppc_nvram_get_size(void)
{
@@ -206,6 +204,8 @@ static long ppc_nvram_sync(void)
}
const struct nvram_ops arch_nvram_ops = {
+ .read_byte = ppc_nvram_read_byte,
+ .write_byte = ppc_nvram_write_byte,
.get_size = ppc_nvram_get_size,
.sync = ppc_nvram_sync,
};
Index: linux/drivers/char/generic_nvram.c
=================================--- linux.orig/drivers/char/generic_nvram.c 2015-11-01 21:41:42.000000000 +1100
+++ linux/drivers/char/generic_nvram.c 2015-11-01 21:41:45.000000000 +1100
@@ -63,7 +63,7 @@ static ssize_t read_nvram(struct file *f
if (*ppos >= nvram_len)
return 0;
for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
- if (__put_user(nvram_read_byte(i), p))
+ if (__put_user(arch_nvram_ops.read_byte(i), p))
return -EFAULT;
*ppos = i;
return p - buf;
@@ -83,7 +83,7 @@ static ssize_t write_nvram(struct file *
for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
if (__get_user(c, p))
return -EFAULT;
- nvram_write_byte(c, i);
+ arch_nvram_ops.write_byte(c, i);
}
*ppos = i;
return p - buf;
Index: linux/drivers/video/fbdev/controlfb.c
=================================--- linux.orig/drivers/video/fbdev/controlfb.c 2015-11-01 21:41:23.000000000 +1100
+++ linux/drivers/video/fbdev/controlfb.c 2015-11-01 21:41:45.000000000 +1100
@@ -415,7 +415,7 @@ static int __init init_control(struct fb
/* Try to pick a video mode out of NVRAM if we have one. */
#ifdef CONFIG_NVRAM
if (default_cmode = CMODE_NVRAM) {
- cmode = nvram_read_byte(NV_CMODE);
+ cmode = arch_nvram_ops.read_byte(NV_CMODE);
if(cmode < CMODE_8 || cmode > CMODE_32)
cmode = CMODE_8;
} else
@@ -423,7 +423,7 @@ static int __init init_control(struct fb
cmodeÞfault_cmode;
#ifdef CONFIG_NVRAM
if (default_vmode = VMODE_NVRAM) {
- vmode = nvram_read_byte(NV_VMODE);
+ vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (vmode < 1 || vmode > VMODE_MAX ||
control_mac_modes[vmode - 1].m[full] < cmode) {
sense = read_control_sense(p);
Index: linux/drivers/video/fbdev/imsttfb.c
=================================--- linux.orig/drivers/video/fbdev/imsttfb.c 2015-11-01 21:41:43.000000000 +1100
+++ linux/drivers/video/fbdev/imsttfb.c 2015-11-01 21:41:45.000000000 +1100
@@ -1393,12 +1393,12 @@ static void init_imstt(struct fb_info *i
int vmode = init_vmode, cmode = init_cmode;
if (vmode = -1) {
- vmode = nvram_read_byte(NV_VMODE);
+ vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (vmode <= 0 || vmode > VMODE_MAX)
vmode = VMODE_640_480_67;
}
if (cmode = -1) {
- cmode = nvram_read_byte(NV_CMODE);
+ cmode = arch_nvram_ops.read_byte(NV_CMODE);
if (cmode < CMODE_8 || cmode > CMODE_32)
cmode = CMODE_8;
}
Index: linux/drivers/video/fbdev/matrox/matroxfb_base.c
=================================--- linux.orig/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:43.000000000 +1100
+++ linux/drivers/video/fbdev/matrox/matroxfb_base.c 2015-11-01 21:41:45.000000000 +1100
@@ -1878,7 +1878,7 @@ static int initMatrox2(struct matrox_fb_
default_vmode = VMODE_640_480_60;
#if defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
if (default_cmode = CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
Index: linux/drivers/video/fbdev/platinumfb.c
=================================--- linux.orig/drivers/video/fbdev/platinumfb.c 2015-11-01 21:41:23.000000000 +1100
+++ linux/drivers/video/fbdev/platinumfb.c 2015-11-01 21:41:45.000000000 +1100
@@ -349,7 +349,7 @@ static int platinum_init_fb(struct fb_in
printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
if (default_vmode = VMODE_NVRAM) {
#ifdef CONFIG_NVRAM
- default_vmode = nvram_read_byte(NV_VMODE);
+ default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
!platinum_reg_init[default_vmode-1])
#endif
@@ -362,7 +362,7 @@ static int platinum_init_fb(struct fb_in
default_vmode = VMODE_640_480_60;
#ifdef CONFIG_NVRAM
if (default_cmode = CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
Index: linux/drivers/video/fbdev/valkyriefb.c
=================================--- linux.orig/drivers/video/fbdev/valkyriefb.c 2015-11-01 21:41:43.000000000 +1100
+++ linux/drivers/video/fbdev/valkyriefb.c 2015-11-01 21:41:45.000000000 +1100
@@ -285,7 +285,7 @@ static void __init valkyrie_choose_mode(
/* Try to pick a video mode out of NVRAM if we have one. */
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_vmode = VMODE_NVRAM) {
- default_vmode = nvram_read_byte(NV_VMODE);
+ default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (default_vmode <= 0
|| default_vmode > VMODE_MAX
|| !valkyrie_reg_init[default_vmode - 1])
@@ -298,7 +298,7 @@ static void __init valkyrie_choose_mode(
default_vmode = VMODE_640_480_67;
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_cmode = CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif
/*
^ permalink raw reply
* Re: Mobility Radeon HD 4530/4570/545v: warnings
From: Pavel Machek @ 2015-11-02 7:31 UTC (permalink / raw)
To: Christian König
Cc: alexander.deucher, linux-fbdev, kernel list, dri-devel
In-Reply-To: <563522C5.1000206@amd.com>
Hi!
One more thing: in my config, I get ton of warnings. I'm not using
modules, so everything is built-in.
Best regards,
Pavel
In file included from drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:24:0:
drivers/gpu/drm/amd/amdgpu/amdgpu.h:1754:12: warning: ‘amdgpu_mn_register’ defined but not used [-Wunused-function]
static int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
^
drivers/gpu/drm/amd/amdgpu/amdgpu.h:1758:13: warning: ‘amdgpu_mn_unregister’ defined but not used [-Wunused-function]
static void amdgpu_mn_unregister(struct amdgpu_bo *bo) {}
^
CC drivers/gpu/drm/amd/amdgpu/atombios_dp.o
In file included from drivers/gpu/drm/amd/amdgpu/atombios_dp.c:29:0:
drivers/gpu/drm/amd/amdgpu/amdgpu.h:1754:12: warning: ‘amdgpu_mn_register’ defined but not used [-Wunused-function]
static int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
^
drivers/gpu/drm/amd/amdgpu/amdgpu.h:1758:13: warning: ‘amdgpu_mn_unregister’ defined but not used [-Wunused-function]
static void amdgpu_mn_unregister(struct amdgpu_bo *bo) {}
^
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: Mobility Radeon HD 4530/4570/545v: flicker in 1920x1080
From: Alex Deucher @ 2015-11-02 15:20 UTC (permalink / raw)
To: Pavel Machek
Cc: Deucher, Alexander, linux-fbdev@vger.kernel.org,
Christian König, Maling list - DRI developers, kernel list
In-Reply-To: <20151031212259.GA6253@amd>
On Sat, Oct 31, 2015 at 5:22 PM, Pavel Machek <pavel@ucw.cz> wrote:
> Hi!
>
>> >4.3-rc7 kernel, graphics works reasonably well in 1600x1200 mode. But
>> >my monitor is native 1920x1080, so that mode looks pretty ugly on
>> >screen. If I go to 1920x1080, I see colored horizontal lines (often
>> >black) as soon as there's graphics activity.
>> >
>> >pavel@half:~$ xrandr
>> >Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
>> >VGA-0 connected 1920x1080+0+0 (normal left inverted right x axis y
>> >axis) 478mm x 268mm
>> > 1920x1080 60.00*+
>> > 1600x1200 60.00
>> > 1680x1050 59.95
>> > 1280x1024 75.02 60.02
>> > 1440x900 59.89
>> > 1024x768 75.08 60.00
>> > 800x600 75.00 60.32
>> > 640x480 75.00 60.00
>> > 720x400 70.08
>> > pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
>> > pavel@half:~$ xrandr --output VGA-0 --mode 1920x1080
>> > pavel@half:~$ xrandr --output VGA-0 --mode 1600x1200
>> >
>> >
>> >This is Acer notebook,
>> >
>> >01:00.0 VGA compatible controller: Advanced Micro Devices,
>> >Inc. [AMD/ATI] RV710/M92 [Mobility Radeon HD 4530/4570/545v]
>
>> >Any ideas?
>>
>> Alex probably knows more about this, but it sounds like problems with
>> switching the memory clocks on 3D load.
>
>> Try to disable power management completely with radeon.dpm=0 on the kernel
>> command line or nailing the hardware at a specific power level using
>> sysfs.
>
> I tried that, but it still flickers.
It's probably pll stability. There seem to be a number of regressions
since the pll code was rewritten to support matching the hdmi clocks
more closely. Does this patch help?
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c
b/drivers/gpu/drm/radeon/atombios_crtc.c
index dac78ad..b86f06a 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -569,6 +569,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
radeon_crtc->pll_flags = 0;
if (ASIC_IS_AVIVO(rdev)) {
+ radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
+
if ((rdev->family = CHIP_RS600) ||
(rdev->family = CHIP_RS690) ||
(rdev->family = CHIP_RS740))
Unfortunately, it can't be applied as is because we had a similar
patch which was reverted because it regressed a bunch of other
systems. The actual pll limits probably need to be tweaked.
Alex
>
> pavel@half:~/misc/fgfs$ cat /proc/cmdline
> BOOT_IMAGE=(hd0,2)/l/linux/arch/x86/boot/bzImage root=/dev/sda4
> resume=/dev/sda1 radeon.dpm=0
>
>> Power consumption would be totally awkward, but it should help nailing down
>> the problem.
>
> It seems chromium makes the flicker way worse.. even when running on
> different virtual desktop. I'm not sure which sysfs settings I should
> tweak (or if I should be tweaking them with .dpm=0). But sysfs says:
> pavel@half:/sys/bus/pci/drivers/radeon/0000:01:00.0$ ls
> backlight drm
> irq
> resource
> boot_vga enable local_cpulist resource0
> broken_parity_status firmware_node local_cpus resource0_wc
> class graphics
> modalias resource1
> config
> i2c-0 msi_bus resource2
> consistent_dma_mask_bits i2c-1 power rom
> d3cold_allowed i2c-2
> power_method subsystem
> device
> i2c-3 power_profile subsystem_device
> dma_mask_bits i2c-4 remove
> subsystem_vendor
> driver i2c-5 rescan uevent
> driver_override i2c-6 reset
> vendor
> pavel@half:/sys/bus/pci/drivers/radeon/0000:01:00.0$ grep . *
> grep: backlight: Is a directory
> boot_vga:1
> broken_parity_status:0
> class:0x030000
> Binary file config matches
> consistent_dma_mask_bits:40
> d3cold_allowed:1
> device:0x9553
> dma_mask_bits:40
> grep: driver: Is a directory
> driver_override:(null)
> grep: drm: Is a directory
> enable:1
> grep: firmware_node: Is a directory
> grep: graphics: Is a directory
> grep: i2c-0: Is a directory
> grep: i2c-1: Is a directory
> grep: i2c-2: Is a directory
> grep: i2c-3: Is a directory
> grep: i2c-4: Is a directory
> grep: i2c-5: Is a directory
> grep: i2c-6: Is a directory
> irq:16
> local_cpulist:0-3
> local_cpus:f
> modalias:pci:v00001002d00009553sv00001025sd00000212bc03sc00i00
> msi_bus:1
> grep: power: Is a directory
> power_method:profile
> power_profile:default
> grep: remove: Permission denied
> grep: rescan: Permission denied
> grep: reset: Permission denied
> resource:0x00000000c0000000 0x00000000cfffffff 0x0000000000042208
> resource:0x0000000000005000 0x00000000000050ff 0x0000000000040101
> resource:0x00000000d6200000 0x00000000d620ffff 0x0000000000040200
> resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
> resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
> resource:0x0000000000000000 0x0000000000000000 0x0000000000000000
> resource:0x00000000d6220000 0x00000000d623ffff 0x0000000000046202
> grep: resource0: Permission denied
> grep: resource0_wc: Permission denied
> grep: resource1: Permission denied
> grep: resource2: Permission denied
> grep: rom: Permission denied
> grep: subsystem: Is a directory
> subsystem_device:0x0212
> subsystem_vendor:0x1025
> uevent:DRIVER=radeon
> uevent:PCI_CLASS0000
> uevent:PCI_ID\x1002:9553
> uevent:PCI_SUBSYS_ID\x1025:0212
> uevent:PCI_SLOT_NAME\000:01:00.0
> uevent:MODALIAS=pci:v00001002d00009553sv00001025sd00000212bc03sc00i00
> vendor:0x1002
>
> Thanks,
> Pavel
> --
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* Re: [PATCH] pwm-backlight: Avoid backlight flicker when probed from DT
From: Philipp Zabel @ 2015-11-02 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20151030182113.GH4058@x1>
Hi Lee,
Am Freitag, den 30.10.2015, 18:21 +0000 schrieb Lee Jones:
> > @@ -264,12 +266,32 @@ static int pwm_backlight_probe(struct platform_device *pdev)
> > pb->enable_gpio = gpio_to_desc(data->enable_gpio);
> > }
> >
> > + phandle = of_find_property(pdev->dev.of_node, "phandle", NULL) != NULL;
>
> This is a little ugly.
>
> If this is the only way to identify the probedness of a device then
> you probably want to neaten it up a little. I suggest something along
> the lines of:
>
> if (of_find_property(pdev->dev.of_node, "phandle", NULL))
> already_probed = true;
>
> Also, do you also want to check for "linux,phandle", as this is always
> catered for in drivers/of/*
Thanks for pointing this out. I suppose I should just check
pdev->dev.of_node->phandle != 0 instead. That will already be
initialized by unflatten_dt_node if either property was found.
regards
Philipp
^ permalink raw reply
* [PATCH v4] pwm-backlight: Avoid backlight flicker when probed from DT
From: Philipp Zabel @ 2015-11-02 16:55 UTC (permalink / raw)
To: linux-arm-kernel
If the driver is probed from the device tree, and there is a phandle
property set on it, and the enable GPIO is already configured as output,
and the backlight is currently disabled, keep it disabled.
If all these conditions are met, assume there will be some other driver
that can enable the backlight at the appropriate time.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
Changes since v3:
- No need to call of_find_property(of_node, "phandle", NULL),
just use of_node->phandle.
- Rebased onto v4.3
---
drivers/video/backlight/pwm_bl.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index eff379b..65e57da 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -199,6 +199,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct backlight_properties props;
struct backlight_device *bl;
struct pwm_bl_data *pb;
+ phandle phandle = pdev->dev.of_node->phandle;
+ int initial_blank = FB_BLANK_UNBLANK;
int ret;
if (!data) {
@@ -242,7 +244,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enabled = false;
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
- GPIOD_OUT_HIGH);
+ GPIOD_ASIS);
if (IS_ERR(pb->enable_gpio)) {
ret = PTR_ERR(pb->enable_gpio);
goto err_alloc;
@@ -264,12 +266,30 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enable_gpio = gpio_to_desc(data->enable_gpio);
}
+ if (pb->enable_gpio) {
+ /*
+ * If the driver is probed from the device tree and there is a
+ * phandle link pointing to the backlight node, it is safe to
+ * assume that another driver will enable the backlight at the
+ * appropriate time. Therefore, if it is disabled, keep it so.
+ */
+ if (phandle &&
+ gpiod_get_direction(pb->enable_gpio) = GPIOF_DIR_OUT &&
+ gpiod_get_value(pb->enable_gpio) = 0)
+ initial_blank = FB_BLANK_POWERDOWN;
+ else
+ gpiod_direction_output(pb->enable_gpio, 1);
+ }
+
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);
goto err_alloc;
}
+ if (phandle && !regulator_is_enabled(pb->power_supply))
+ initial_blank = FB_BLANK_POWERDOWN;
+
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pb->pwm)) {
ret = PTR_ERR(pb->pwm);
@@ -321,6 +341,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
}
bl->props.brightness = data->dft_brightness;
+ bl->props.power = initial_blank;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
--
2.6.1
^ permalink raw reply related
* Re: [PATCH v2] pwm-backlight: fix the panel power sequence
From: YH Huang @ 2015-11-03 8:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1446201271.3334.22.camel@pengutronix.de>
On Fri, 2015-10-30 at 11:34 +0100, Philipp Zabel wrote:
> Am Freitag, den 30.10.2015, 15:41 +0800 schrieb YH Huang:
> > > That won't work if the gpio is still configured as input. How about I
> > > add the GPIOD_ASIS change to my patch you remove that and the above from
> > > yours?
> >
> > I revise these two lines
> > if (pb->enable_gpio)
> > gpiod_direction_output(pb->enable_gpio, 0);
> > into
> > if (pb->enable_gpio) {
> > if(gpiod_get_value(pb->enable_gpio) = 0)
> > gpiod_direction_output(pb->enable_gpio, 0);
> > else
> > gpiod_direction_output(pb->enable_gpio, 1);
> > }
>
> If the GPIO is still configured as an input, the return value of
> gpiod_get_value could be random.
>
> > I am not sure what "phandle" is working for.
>
> The reasoning is that devices where there is no phandle link pointing to
> the backlight (for example from a simple-panel node), we should keep the
> current default behaviour (enable during probe).
I have a little problem for the current default behaviour.
Should we enable during probe?
Before this patch ( http://patchwork.ozlabs.org/patch/324690/ ),
we disable "enable-gpio" in the probe function.
Do you have any idea of this?
Regards,
YH Huang
^ permalink raw reply
* Re: [PATCH v2] pwm-backlight: fix the panel power sequence
From: Philipp Zabel @ 2015-11-03 11:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1446538299.2449.8.camel@mtksdaap41>
Hi YH,
Am Dienstag, den 03.11.2015, 16:11 +0800 schrieb YH Huang:
> > The reasoning is that devices where there is no phandle link pointing to
> > the backlight (for example from a simple-panel node), we should keep the
> > current default behaviour (enable during probe).
>
> I have a little problem for the current default behaviour.
> Should we enable during probe?
Here I mean enabling the backlight (at the end of the probe function),
not enabling the GPIO already when requesting it.
> Before this patch ( http://patchwork.ozlabs.org/patch/324690/ ),
> we disable "enable-gpio" in the probe function.
While before this patch the GPIO would be initialized in the disabled
state, the call to backlight_update_status at the end of the probe
function would still enable the backlight afterwards.
regards
Philipp
^ permalink raw reply
* [PATCH 0/3] Hisilicon graphic driver
From: Rongrong Zou @ 2015-11-03 13:54 UTC (permalink / raw)
To: linux-fbdev
From: Rongrong Zou <rongrongchau@163.com>
Hi1710 chip have a graphic modue with 2d acceleration, this driver support
the graphic module.
Rongrong Zou (3):
Hisilicon graphic driver: add fbdev support to hisilicon hi1710
graphic chip
Hisilicon graphic driver: add hardware cursor support to hisilicon
hi1710 graphi chip
Hisilicon graphic driver: add 2d acceleration to hisilicon hi1710
graphic chip
MAINTAINERS | 7 +
drivers/video/fbdev/Kconfig | 14 +
drivers/video/fbdev/Makefile | 2 +-
drivers/video/fbdev/hisilicon/Makefile | 6 +
drivers/video/fbdev/hisilicon/hisi_accel.c | 382 ++++++++
drivers/video/fbdev/hisilicon/hisi_accel.h | 62 ++
drivers/video/fbdev/hisilicon/hisi_chip.c | 131 +++
drivers/video/fbdev/hisilicon/hisi_chip.h | 62 ++
drivers/video/fbdev/hisilicon/hisi_cursor.c | 121 +++
drivers/video/fbdev/hisilicon/hisi_cursor.h | 11 +
drivers/video/fbdev/hisilicon/hisi_drv.c | 1326 +++++++++++++++++++++++++++
drivers/video/fbdev/hisilicon/hisi_drv.h | 181 ++++
drivers/video/fbdev/hisilicon/hisi_help.h | 64 ++
drivers/video/fbdev/hisilicon/hisi_hw.c | 314 +++++++
drivers/video/fbdev/hisilicon/hisi_hw.h | 95 ++
drivers/video/fbdev/hisilicon/hisi_mode.c | 286 ++++++
drivers/video/fbdev/hisilicon/hisi_mode.h | 39 +
drivers/video/fbdev/hisilicon/hisi_power.c | 106 +++
drivers/video/fbdev/hisilicon/hisi_power.h | 18 +
drivers/video/fbdev/hisilicon/hisi_reg.h | 418 +++++++++
20 files changed, 3644 insertions(+), 1 deletion(-)
create mode 100644 drivers/video/fbdev/hisilicon/Makefile
create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_chip.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_chip.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_cursor.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_cursor.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_drv.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_drv.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_help.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_hw.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_hw.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_mode.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_mode.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_power.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_power.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_reg.h
--
1.9.1
^ permalink raw reply
* [PATCH 1/3] Hisilicon graphic driver: add fbdev support to hisilicon hi1710 graphic chip
From: Rongrong Zou @ 2015-11-03 13:54 UTC (permalink / raw)
To: linux-fbdev
From: Rongrong Zou <zourongrong@huawei.com>
hisi_drv.c, main file of driver, register hisilicon fb driver to kernel.
hssi_hw.c, this file implements controller's display mode.
hisi_power.c, implements power mode setting.
hisi_chip.c, some chip settings, such as pll setting.
Signed-off-by: Rongrong Zou <zourongrong@huawei.com>
---
MAINTAINERS | 7 +
drivers/video/fbdev/Kconfig | 14 +
drivers/video/fbdev/Makefile | 2 +-
drivers/video/fbdev/hisilicon/Makefile | 6 +
drivers/video/fbdev/hisilicon/hisi_chip.c | 131 ++++
drivers/video/fbdev/hisilicon/hisi_chip.h | 62 ++
drivers/video/fbdev/hisilicon/hisi_drv.c | 1118 ++++++++++++++++++++++++++++
drivers/video/fbdev/hisilicon/hisi_drv.h | 181 +++++
drivers/video/fbdev/hisilicon/hisi_help.h | 64 ++
drivers/video/fbdev/hisilicon/hisi_hw.c | 293 ++++++++
drivers/video/fbdev/hisilicon/hisi_hw.h | 95 +++
drivers/video/fbdev/hisilicon/hisi_mode.c | 286 +++++++
drivers/video/fbdev/hisilicon/hisi_mode.h | 39 +
drivers/video/fbdev/hisilicon/hisi_power.c | 106 +++
drivers/video/fbdev/hisilicon/hisi_power.h | 18 +
drivers/video/fbdev/hisilicon/hisi_reg.h | 418 +++++++++++
16 files changed, 2839 insertions(+), 1 deletion(-)
create mode 100644 drivers/video/fbdev/hisilicon/Makefile
create mode 100644 drivers/video/fbdev/hisilicon/hisi_chip.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_chip.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_drv.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_drv.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_help.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_hw.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_hw.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_mode.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_mode.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_power.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_power.h
create mode 100644 drivers/video/fbdev/hisilicon/hisi_reg.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 77ed3a0..2813be9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4973,6 +4973,13 @@ F: include/uapi/linux/if_hippi.h
F: net/802/hippi.c
F: drivers/net/hippi/
+HISILICON FRAMEBUFFER DRIVER
+M: Rongrong Zou <zourongrong@huawei.com>
+L: linux-fbdev@vger.kernel.org
+S: Maintained
+F: Documentation/fb/intelfb.txt
+F: drivers/video/fbdev/hisilicon/
+
HOST AP DRIVER
M: Jouni Malinen <j@w1.fi>
L: hostap@shmoo.com (subscribers-only)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 8b1d371..6399da3 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2489,3 +2489,17 @@ config FB_SM712
This driver is also available as a module. The module will be
called sm712fb. If you want to compile it as a module, say M
here and read <file:Documentation/kbuild/modules.txt>.
+
+config FB_HISILICON
+ tristate "Hisilicon Hi1710 framebuffer support"
+ depends on FB && PCI
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for Hisilicon Hi1710 integrited graphics chip.
+
+ This driver is also available as a module. The module will be
+ called hisiliconfb. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.txt>.
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 50ed1b4..c7383db 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -132,7 +132,7 @@ obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o
obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o
obj-$(CONFIG_FB_OPENCORES) += ocfb.o
obj-$(CONFIG_FB_SM712) += sm712fb.o
-
+obj-$(CONFIG_FB_HISILICON) += hisilicon/
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o
diff --git a/drivers/video/fbdev/hisilicon/Makefile b/drivers/video/fbdev/hisilicon/Makefile
new file mode 100644
index 0000000..540b6d2
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_FB_HISILICON) += hisiliconfb.o
+
+hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_chip.o
+hisiliconfb-y += hisi_mode.o hisi_power.o
+
+hisiliconfb-objs := $(hisiliconfb-y)
diff --git a/drivers/video/fbdev/hisilicon/hisi_chip.c b/drivers/video/fbdev/hisilicon/hisi_chip.c
new file mode 100644
index 0000000..e152f37
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_chip.c
@@ -0,0 +1,131 @@
+#include <linux/delay.h>
+#include "hisi_chip.h"
+#include "hisi_help.h"
+#include "hisi_power.h"
+#include "hisi_reg.h"
+
+void set_vclock_hisilicon(unsigned long pll)
+{
+ unsigned long tmp0, tmp1;
+
+ /* 1. outer_bypass_n=0 */
+ tmp0 = PEEK32(CRT_PLL1_HS);
+ tmp0 &= 0xBFFFFFFF;
+ POKE32(CRT_PLL1_HS, tmp0);
+
+ /* 2. pll_pd=1?inter_bypass=1 */
+ POKE32(CRT_PLL1_HS, 0x21000000);
+
+ /* 3. config pll */
+ POKE32(CRT_PLL1_HS, pll);
+
+ /* 4. delay */
+ mdelay(1);
+
+ /* 5. pll_pd =0 */
+ tmp1 = pll & ~0x01000000;
+ POKE32(CRT_PLL1_HS, tmp1);
+
+ /* 6. delay */
+ mdelay(1);
+
+ /* 7. inter_bypass=0 */
+ tmp1 &= ~0x20000000;
+ POKE32(CRT_PLL1_HS, tmp1);
+
+ /* 8. delay */
+ mdelay(1);
+
+ /* 9. outer_bypass_n=1 */
+ tmp1 |= 0x40000000;
+ POKE32(CRT_PLL1_HS, tmp1);
+}
+
+
+int hisi_init_hw(struct _initchip_param_t *p_init_param)
+{
+ unsigned int reg;
+
+ if (p_init_param->powerMode != 0)
+ p_init_param->powerMode = 0;
+ set_power_mode(p_init_param->powerMode);
+
+ /* Enable display power gate & LOCALMEM power gate*/
+ reg = PEEK32(CURRENT_GATE);
+ reg = FIELD_SET(reg, CURRENT_GATE, DISPLAY, ON);
+ reg = FIELD_SET(reg, CURRENT_GATE, LOCALMEM, ON);
+ set_current_gate(reg);
+
+ {
+#if defined(__i386__) || defined(__x86_64__)
+ /* set graphic mode via IO method */
+ outb_p(0x88, 0x3d4);
+ outb_p(0x06, 0x3d5);
+#endif
+ }
+
+ /* Reset the memory controller. If the memory controller
+ * is not reset in chip,the system might hang when sw accesses
+ * the memory.The memory should be resetted after
+ * changing the MXCLK.
+ */
+ if (p_init_param->resetMemory = 1) {
+ reg = PEEK32(MISC_CTRL);
+ reg = FIELD_SET(reg, MISC_CTRL, LOCALMEM_RESET, RESET);
+ POKE32(MISC_CTRL, reg);
+
+ reg = FIELD_SET(reg, MISC_CTRL, LOCALMEM_RESET, NORMAL);
+ POKE32(MISC_CTRL, reg);
+ }
+
+ if (p_init_param->setAllEngOff = 1) {
+ enable_2d_engine(0);
+
+ /* Disable Overlay, if a former application left it on */
+ reg = PEEK32(VIDEO_DISPLAY_CTRL);
+ reg = FIELD_SET(reg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE);
+ POKE32(VIDEO_DISPLAY_CTRL, reg);
+
+ /* Disable video alpha, if a former application left it on */
+ reg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL);
+ reg = FIELD_SET(reg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
+ POKE32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
+
+ /* Disable alpha plane, if a former application left it on */
+ reg = PEEK32(ALPHA_DISPLAY_CTRL);
+ reg = FIELD_SET(reg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
+ POKE32(ALPHA_DISPLAY_CTRL, reg);
+
+ /* Disable DMA Channel, if a former application left it on */
+ reg = PEEK32(DMA_ABORT_INTERRUPT);
+ reg = FIELD_SET(reg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
+ POKE32(DMA_ABORT_INTERRUPT, reg);
+
+ /* Disable DMA Power, if a former application left it on */
+ enable_dma(0);
+ }
+
+ /* We can add more initialization as needed. */
+
+ return 0;
+}
+
+unsigned int format_pll_reg(struct pll *ppll)
+{
+ unsigned int pllreg = 0;
+
+ /* Note that all PLL's have the same format. Here,
+ *we just use Panel PLL parameter to work out the bit
+ * fields in the register.On returning a 32 bit number, the value can
+ * be applied to any PLL in the calling function.
+ */
+ pllreg = FIELD_SET(0, PANEL_PLL_CTRL, BYPASS, OFF) |
+ FIELD_SET(0, PANEL_PLL_CTRL, POWER, ON)|
+ FIELD_SET(0, PANEL_PLL_CTRL, INPUT, OSC)|
+ FIELD_VALUE(0, PANEL_PLL_CTRL, POD, ppll->POD)|
+ FIELD_VALUE(0, PANEL_PLL_CTRL, OD, ppll->OD)|
+ FIELD_VALUE(0, PANEL_PLL_CTRL, N, ppll->N)|
+ FIELD_VALUE(0, PANEL_PLL_CTRL, M, ppll->M);
+
+ return pllreg;
+}
diff --git a/drivers/video/fbdev/hisilicon/hisi_chip.h b/drivers/video/fbdev/hisilicon/hisi_chip.h
new file mode 100644
index 0000000..b33cbfe
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_chip.h
@@ -0,0 +1,62 @@
+#ifndef HISI_CHIP_H__
+#define HISI_CHIP_H__
+
+#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */
+
+
+enum clock_type {
+ MXCLK_PLL,
+ PRIMARY_PLL,
+ SECONDARY_PLL,
+ VGA0_PLL,
+ VGA1_PLL,
+};
+
+struct pll {
+ enum clock_type clock_type;
+ unsigned long intput_freq; /* Input clock frequency to the PLL */
+
+ /* Use this when clock_type = PANEL_PLL */
+ unsigned long M;
+ unsigned long N;
+ unsigned long OD;
+ unsigned long POD;
+};
+
+/* input struct to initChipParam() function */
+struct _initchip_param_t {
+ unsigned short powerMode; /* Use power mode 0 or 1 */
+ unsigned short chipClock;
+ /* Speed of main chip clock in MHz unit
+ *0 = keep the current clock setting
+ *Others = the new main chip clock
+ */
+ unsigned short memClock;
+ /* Speed of memory clock in MHz unit
+ * 0 = keep the current clock setting
+ * Others = the new memory clock
+ */
+ unsigned short masterClock;
+ /* Speed of master clock in MHz unit
+ *0 = keep the current clock setting
+ *Others = the new master clock
+ */
+ unsigned short setAllEngOff;
+ /* 0 = leave all engine state untouched.
+ *1 = make sure they are off: 2D, Overlay,
+ *video alpha, alpha, hardware cursors
+ */
+ unsigned char resetMemory;
+ /* 0 = Do not reset the memory controller
+ *1 = Reset the memory controller
+ */
+
+ /* More initialization parameter can be added if needed */
+};
+
+
+unsigned int format_pll_reg(struct pll *pll);
+int hisi_init_hw(struct _initchip_param_t *);
+void set_vclock_hisilicon(unsigned long pll);
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_drv.c b/drivers/video/fbdev/hisilicon/hisi_drv.c
new file mode 100644
index 0000000..521a279
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_drv.c
@@ -0,0 +1,1118 @@
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include "hisi_drv.h"
+#include "hisi_hw.h"
+
+
+/* chip specific setup routine */
+static void hisi_fb_setup(struct hisi_share *share, char *src);
+static int hisifb_pci_probe(struct pci_dev *, const struct pci_device_id *);
+static void hisifb_pci_remove(struct pci_dev *);
+
+#ifdef CONFIG_PM
+static int hisifb_suspend(struct pci_dev *, pm_message_t);
+static int hisifb_resume(struct pci_dev *);
+#endif
+
+static int hisifb_set_fbinfo(struct fb_info *, int);
+static int hisifb_ops_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int hisifb_ops_set_par(struct fb_info *);
+static int hisifb_ops_setcolreg(unsigned, unsigned, unsigned,
+ unsigned, unsigned, struct fb_info *);
+static int hisifb_ops_blank(int, struct fb_info *);
+
+typedef void (*PROC_SPEC_SETUP)(struct hisi_share *, char *);
+typedef int (*PROC_SPEC_MAP)(struct hisi_share *, struct pci_dev *);
+typedef int (*PROC_SPEC_INITHW)(struct hisi_share *, struct pci_dev *);
+
+/* common var for all device */
+static int g_hwcursor = 1;
+static int g_noaccel = 1;
+#ifdef CONFIG_MTRR
+static int g_nomtrr;
+#endif
+static const char *g_fbmode[2];
+
+/*modify for hisilicon default mode*/
+static const char *g_def_fbmode = "800x600-16@60";
+static char *g_settings;
+static int g_dualview;
+
+#ifdef MODULE
+static char *g_option;
+#endif
+
+static const struct fb_videomode hisi_vedio_mode_ext[] = {
+ /*024x600-60 VESA [1.71:1]*/
+ {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /* 024x600-70 VESA */
+ {NULL, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /* 024x600-75 VESA */
+ {NULL, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /* 024x600-85 VESA */
+ {NULL, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /*20x480 */
+ {NULL, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /*280x720 [1.78:1] */
+ {NULL, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /* 1280x768@60 */
+ {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_VMODE_NONINTERLACED},
+
+ /*360 x 768 [1.77083:1] */
+ {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /*368 x 768 [1.78:1] */
+ {NULL, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /* 440 x 900 [16:10] */
+ {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /*440x960 [15:10] */
+ {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+
+ /*920x1080 [16:9] */
+ {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+};
+
+static struct pci_device_id hisi_pci_table[] = {
+ {PCI_VENDOR_ID_HIS, PCI_DEVID_HS_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+static struct pci_driver hisifb_driver = {
+ .name = _moduleName_,
+ .id_table = hisi_pci_table,
+ .probe = hisifb_pci_probe,
+ .remove = hisifb_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = hisifb_suspend,
+ .resume = hisifb_resume,
+#endif
+};
+
+static struct fb_ops hisifb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = hisifb_ops_check_var,
+ .fb_set_par = hisifb_ops_set_par,
+ .fb_setcolreg = hisifb_ops_setcolreg,
+ .fb_blank = hisifb_ops_blank,
+ /* will be hooked by hardware */
+ .fb_fillrect = cfb_fillrect,
+ .fb_imageblit = cfb_imageblit,
+ .fb_copyarea = cfb_copyarea,
+};
+
+#ifdef CONFIG_PM
+static int hisifb_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct fb_info *info;
+ struct hisi_share *share;
+ int ret;
+
+ if (mesg.event = pdev->dev.power.power_state.event)
+ return 0;
+
+ ret = 0;
+ share = pci_get_drvdata(pdev);
+ switch (mesg.event) {
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+ pdev->dev.power.power_state = mesg;
+ return 0;
+ }
+
+ console_lock();
+ if (mesg.event & PM_EVENT_SLEEP) {
+ info = share->fbinfo[0];
+ if (info)
+ fb_set_suspend(info, 1);/* 1 means do suspend*/
+
+ info = share->fbinfo[1];
+ if (info)
+ fb_set_suspend(info, 1);/* 1 means do suspend*/
+
+ ret = pci_save_state(pdev);
+ if (ret) {
+ err_msg("error:%d occurred in pci_save_state\n", ret);
+ console_unlock();
+ return ret;
+ }
+
+ pci_disable_device(pdev);
+ ret = pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
+ if (ret) {
+ err_msg("error:%d occurred in pci_set_power_state\n",
+ ret);
+ console_unlock();
+ return ret;
+ }
+ /* set chip to sleep mode */
+ if (share->suspend)
+ (*share->suspend)();
+ }
+
+ pdev->dev.power.power_state = mesg;
+ console_unlock();
+ return ret;
+}
+
+static int hisifb_resume(struct pci_dev *pdev)
+{
+ struct fb_info *info;
+ struct hisi_share *share;
+
+ struct hisifb_par *par;
+ struct hisifb_crtc *crtc;
+ struct hisi_cursor *cursor;
+
+ int ret;
+
+ ret = 0;
+ share = pci_get_drvdata(pdev);
+
+ console_lock();
+ ret = pci_set_power_state(pdev, PCI_D0);
+ if (ret != 0) {
+ err_msg("error:%d occurred in pci_set_power_state\n", ret);
+ console_lock();
+ return ret;
+ }
+
+ if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret != 0) {
+ err_msg("error:%d occurred in pci_enable_device\n",
+ ret);
+ console_lock();
+ return ret;
+ }
+ pci_set_master(pdev);
+ }
+
+ hw_hisi_inithw(share, pdev);
+
+ info = share->fbinfo[0];
+ par = info->par;
+ crtc = &par->crtc;
+ cursor = &crtc->cursor;
+
+ if (info) {
+ hisifb_ops_set_par(info);
+ fb_set_suspend(info, 0);
+ }
+
+ info = share->fbinfo[1];
+
+ if (info) {
+ hisifb_ops_set_par(info);
+ fb_set_suspend(info, 0);
+ }
+
+ if (share->resume)
+ (*share->resume)();
+
+ console_unlock();
+ return ret;
+}
+#endif
+
+static int hisifb_ops_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct hisifb_par *par;
+ struct hisifb_crtc *crtc;
+ struct hisifb_output *output;
+ struct hisi_share *share;
+ int ret;
+ resource_size_t request;
+
+ par = info->par;
+ crtc = &par->crtc;
+ output = &par->output;
+ share = par->share;
+ ret = 0;
+
+ dbg_msg("check var:%dx%d-%d\n",
+ var->xres,
+ var->yres,
+ var->bits_per_pixel);
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ case 16:
+ case 24: /* support 24 bpp for only lynx712/722/720 */
+ case 32:
+ break;
+ default:
+ err_msg("bpp %d not supported\n", var->bits_per_pixel);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 24:
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ var->height = var->width = -1;
+ var->accel_flags = FB_ACCELF_TEXT;
+
+ /* check if current fb's video memory
+ * big enought to hold the onscreen
+ */
+ request = var->xres_virtual * (var->bits_per_pixel >> 3);
+ /* defaulty crtc->channel go with par->index */
+
+ request = PADDING(crtc->line_pad, request);
+ request = request * var->yres_virtual;
+ if (crtc->vidmem_size < request) {
+ err_msg("not enough video memory for mode\n");
+ return -ENOMEM;
+ }
+
+ ret = crtc->proc_check_mode(crtc, var);
+
+exit:
+ return ret;
+}
+
+static int hisifb_ops_set_par(struct fb_info *info)
+{
+ struct hisifb_par *par;
+ struct hisi_share *share;
+ struct hisifb_crtc *crtc;
+ struct hisifb_output *output;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+ int ret;
+ unsigned int line_length;
+
+
+ if (!info)
+ return -EINVAL;
+
+ ret = 0;
+ par = info->par;
+ share = par->share;
+ crtc = &par->crtc;
+ output = &par->output;
+ var = &info->var;
+ fix = &info->fix;
+
+ /* fix structur is not so FIX ... */
+ line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ line_length = PADDING(crtc->line_pad, line_length);
+ fix->line_length = line_length;
+ dbg_msg("fix->line_length = %d\n", fix->line_length);
+
+ /* var->red,green,blue,transp are need to be set by driver
+ * and these data should be set before setcolreg routine
+ */
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 24:
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ var->height = var->width = -1;
+ var->accel_flags = FB_ACCELF_TEXT;
+
+ if (ret) {
+ err_msg("pixel bpp format not satisfied\n.");
+ return ret;
+ }
+ ret = crtc->proc_set_mode(crtc, var, fix);
+ if (!ret)
+ ret = output->proc_set_mode(output, var, fix);
+
+ return ret;
+}
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int hisifb_ops_setcolreg(unsigned regno, unsigned red,
+ unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct hisifb_par *par;
+ struct hisifb_crtc *crtc;
+ struct fb_var_screeninfo *var;
+ int ret;
+
+ par = info->par;
+ crtc = &par->crtc;
+ var = &info->var;
+ ret = 0;
+
+
+ if (regno > 256) {
+ err_msg("regno = %d\n", regno);
+ return -EINVAL;
+ }
+
+ if (info->var.grayscale)
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+
+ if (var->bits_per_pixel = 8 &&
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ret = crtc->proc_set_col_reg(crtc, regno, red, green, blue);
+ goto exit;
+ }
+
+
+ if (info->fix.visual = FB_VISUAL_TRUECOLOR && regno < 256) {
+ u32 val;
+
+ if (var->bits_per_pixel = 16 ||
+ var->bits_per_pixel = 32 ||
+ var->bits_per_pixel = 24) {
+ val = chan_to_field(red, &var->red);
+ val |= chan_to_field(green, &var->green);
+ val |= chan_to_field(blue, &var->blue);
+ par->pseudo_palette[regno] = val;
+ goto exit;
+ }
+ }
+
+ ret = -EINVAL;
+
+exit:
+ return ret;
+}
+
+static int hisifb_ops_blank(int blank, struct fb_info *info)
+{
+ return 0;
+}
+
+/*
+ * HS_F,HS_A all go through this routine
+ */
+static int hisifb_set_drv(struct hisifb_par *par)
+{
+ int ret = 0;
+ struct hisi_share *share;
+ struct hisi_a_share *spec_share;
+ struct hisifb_output *output;
+ struct hisifb_crtc *crtc;
+
+
+ share = par->share;
+ spec_share = container_of(share, struct hisi_a_share, share);
+ output = &par->output;
+ crtc = &par->crtc;
+
+ crtc->vidmem_size = (share->dual) ?
+ share->vidmem_size >> 1 : share->vidmem_size;
+
+ /* setup crtc and output member */
+ spec_share->hwcursor = g_hwcursor;
+
+ crtc->proc_set_mode = hw_hisi_crtc_setmode;
+ crtc->proc_check_mode = hw_hisi_crtc_checkmode;
+ crtc->proc_set_col_reg = hw_hisi_set_col_reg;
+ crtc->clear = NULL;
+ crtc->line_pad = 16;
+ crtc->xpanstep = crtc->ypanstep = crtc->ywrapstep = 0;
+
+ output->proc_set_mode = hw_hisi_output_setmode;
+ output->proc_check_mode = NULL;
+
+ output->proc_set_blank = hw_hisile_set_blank;
+ share->accel.de_wait = hw_hisile_dewait;
+ output->clear = NULL;
+
+ switch (spec_share->state.dataflow) {
+ case hisi_simul_pri:
+ output->paths = hisi_pnc;
+ crtc->channel = hisi_primary;
+ crtc->oscreen = 0;
+ crtc->vscreen = share->pvmem;
+ inf_msg("use simul primary mode\n");
+ break;
+ case hisi_simul_sec:
+ output->paths = hisi_pnc;
+ crtc->channel = hisi_secondary;
+ crtc->oscreen = 0;
+ crtc->vscreen = share->pvmem;
+ break;
+ case hisi_dual_normal:
+ if (par->index = 0) {
+ output->paths = hisi_panel;
+ crtc->channel = hisi_primary;
+ crtc->oscreen = 0;
+ crtc->vscreen = share->pvmem;
+ } else {
+ output->paths = hisi_crt;
+ crtc->channel = hisi_secondary;
+ /* not consider of padding stuffs for oscreen,need fix*/
+ crtc->oscreen = (share->vidmem_size >> 1);
+ crtc->vscreen = share->pvmem + crtc->oscreen;
+ }
+ break;
+ case hisi_dual_swap:
+ if (par->index = 0) {
+ output->paths = hisi_panel;
+ crtc->channel = hisi_secondary;
+ crtc->oscreen = 0;
+ crtc->vscreen = share->pvmem;
+ } else {
+ output->paths = hisi_crt;
+ crtc->channel = hisi_primary;
+ /* not consider of padding stuffs for oscreen,need fix*/
+ crtc->oscreen = (share->vidmem_size >> 1);
+ crtc->vscreen = share->pvmem + crtc->oscreen;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int hisifb_set_fbinfo(struct fb_info *info, int index)
+{
+ int i;
+ struct hisifb_par *par;
+ struct hisi_share *share;
+ struct hisifb_crtc *crtc;
+ struct hisifb_output *output;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+
+ const struct fb_videomode *pdb[] = {
+ hisi_vedio_mode_ext, NULL, vesa_modes,
+ };
+ int cdb[] = {ARRAY_SIZE(hisi_vedio_mode_ext), 0, VESA_MODEDB_SIZE};
+ static const char *const mdb_desc[] = {
+ "driver prepared modes",
+ "kernel prepared default modedb",
+ "kernel HELPERS prepared vesa_modes",
+ };
+
+ static const char *fixId[2] = {
+ "hisi_fb1", "hisi_fb2",
+ };
+
+ int ret, line_length;
+
+
+ ret = 0;
+ par = (struct hisifb_par *)info->par;
+ share = par->share;
+ crtc = &par->crtc;
+ output = &par->output;
+ var = &info->var;
+ fix = &info->fix;
+
+ /* set index */
+ par->index = index;
+ output->channel = &crtc->channel;
+ hisifb_set_drv(par);
+
+ /* set info->fbops, must be set before fb_find_mode */
+
+ info->fbops = &hisifb_ops;
+
+ if (!g_fbmode[index]) {
+ g_fbmode[index] = g_def_fbmode;
+ if (index)
+ g_fbmode[index] = g_fbmode[0];
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = fb_find_mode(var, info, g_fbmode[index],
+ pdb[i], cdb[i], NULL, 8);
+
+ if (ret = 1) {
+ inf_msg("success! use specified mode:%s in %s\n",
+ g_fbmode[index],
+ mdb_desc[i]);
+ break;
+ } else if (ret = 2) {
+ war_msg("use specified mode:%s in %s,\n"
+ "with an ignored refresh rate\n",
+ g_fbmode[index],
+ mdb_desc[i]);
+ break;
+ } else if (ret = 3) {
+ war_msg("wanna use default mode\n");
+ } else if (ret = 4) {
+ war_msg("fall back to any valid mode\n");
+ } else {
+ err_msg("ret = %d,fb_find_mode failed,with %s\n",
+ ret, mdb_desc[i]);
+ }
+ }
+
+ /* some member of info->var had been set by fb_find_mode */
+
+ inf_msg("Member of info->var is :\n"
+ "xres=%d\n"
+ "yres=%d\n"
+ "xres_virtual=%d\n"
+ "yres_virtual=%d\n"
+ "xoffset=%d\n"
+ "yoffset=%d\n"
+ "bits_per_pixel=%d\n"
+ "...\n", var->xres, var->yres, var->xres_virtual,
+ var->yres_virtual, var->xoffset, var->yoffset,
+ var->bits_per_pixel);
+
+ /* set par */
+ par->info = info;
+
+ /* set info */
+ line_length = PADDING(crtc->line_pad,
+ (var->xres_virtual * var->bits_per_pixel / 8));
+
+ info->pseudo_palette = &par->pseudo_palette[0];
+ info->screen_base = crtc->vscreen;
+ dbg_msg("screen_base vaddr = %p\n", info->screen_base);
+ info->screen_size = line_length * var->yres_virtual;
+ info->flags = FBINFO_FLAG_DEFAULT | 0;
+
+ /* set info->fix */
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->xpanstep = crtc->xpanstep;
+ fix->ypanstep = crtc->ypanstep;
+ fix->ywrapstep = crtc->ywrapstep;
+ fix->accel = FB_ACCEL_NONE;
+
+ strlcpy(fix->id, fixId[index], sizeof(fix->id));
+
+
+ fix->smem_start = crtc->oscreen + share->vidmem_start;
+ inf_msg("fix->smem_start = %lx\n", fix->smem_start);
+
+ /*
+ * according to mmap experiment from user space application,
+ * fix->mmio_len should not larger than virtual size
+ * (xres_virtual x yres_virtual x ByPP)
+ * Below line maybe buggy when user mmap fb dev node and write
+ * data into the bound over virtual size
+ */
+ fix->smem_len = crtc->vidmem_size;
+ inf_msg("fix->smem_len = %x\n", fix->smem_len);
+ fix->line_length = line_length;
+ fix->mmio_start = share->vidreg_start;
+ inf_msg("fix->mmio_start = %lx\n", fix->mmio_start);
+ fix->mmio_len = share->vidreg_size;
+ inf_msg("fix->mmio_len = %x\n", fix->mmio_len);
+ switch (var->bits_per_pixel) {
+ case 8:
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ case 16:
+ case 32:
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ break;
+ }
+
+ /* set var */
+ var->activate = FB_ACTIVATE_NOW;
+ var->accel_flags = FB_ACCELF_TEXT;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ dbg_msg("#1 show info->cmap :\n"
+ "start=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
+ info->cmap.start, info->cmap.len,
+ info->cmap.red, info->cmap.green,
+ info->cmap.blue, info->cmap.transp);
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret < 0) {
+ err_msg("Could not allcate memory for cmap.\n");
+ goto exit;
+ }
+
+ dbg_msg("#2 show info->cmap :\n"
+ "start=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
+ info->cmap.start, info->cmap.len,
+ info->cmap.red, info->cmap.green, info->cmap.blue,
+ info->cmap.transp);
+exit:
+ return ret;
+}
+
+static int hisifb_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct fb_info *info[] = {NULL, NULL};
+ struct hisi_share *share = NULL;
+
+ void *spec_share = NULL;
+ size_t spec_offset = 0;
+ int fbidx;
+
+
+ /* enable device */
+ if (pci_enable_device(pdev)) {
+ err_msg("can not enable device.\n");
+ goto err_enable;
+ }
+
+ /* though offset of share in hisi_a_share is 0,
+ * we use this marcro as the same
+ */
+ spec_offset = offsetof(struct hisi_a_share, share);
+
+
+ dbg_msg("spec_offset = %ld\n", spec_offset);
+ spec_share = kzalloc(sizeof(struct hisi_a_share), GFP_KERNEL);
+
+ if (!spec_share) {
+ err_msg("Could not allocate memory for share.\n");
+ goto err_share;
+ }
+
+ /* setting share structure */
+ share = (struct hisi_share *)(spec_share + spec_offset);
+ share->fbinfo[0] = share->fbinfo[1] = NULL;
+
+ inf_msg("share->revid = %02x\n", pdev->revision);
+ share->pdev = pdev;
+#ifdef CONFIG_MTRR
+ share->mtrr_off = g_nomtrr;
+ share->mtrr.vram = 0;
+ share->mtrr.vram_added = 0;
+#endif
+ share->accel_off = g_noaccel;
+ share->dual = g_dualview;
+
+ /* call chip specific setup routine */
+ hisi_fb_setup(share, g_settings);
+
+ /* call chip specific mmap routine */
+ if (hw_hisi_map(share, pdev)) {
+ err_msg("Memory map failed\n");
+ goto err_map;
+ }
+
+#ifdef CONFIG_MTRR
+ if (!share->mtrr_off) {
+ inf_msg("enable mtrr\n");
+ share->mtrr.vram = mtrr_add(share->vidmem_start,
+ share->vidmem_size,
+ MTRR_TYPE_WRCOMB, 1);
+ if (share->mtrr.vram < 0) {
+ /* don't block driver with the failure of MTRR */
+ err_msg("Unable to setup MTRR.\n");
+ } else {
+ share->mtrr.vram_added = 1;
+ inf_msg("MTRR added successfully\n");
+ }
+ }
+#endif
+
+ /*memset(share->pvmem,0,share->vidmem_size);*/
+
+ inf_msg("sm%3x mmio address = %p\n", pdev->device, share->pvreg);
+
+ pci_set_drvdata(pdev, share);
+
+ /* call chipInit routine */
+ hw_hisi_inithw(share, pdev);
+
+ /* allocate frame buffer info structor according to g_dualview */
+ fbidx = 0;
+ info[fbidx] = framebuffer_alloc(sizeof(struct hisifb_par), &pdev->dev);
+ if (!info[fbidx]) {
+ err_msg("Could not allocate framebuffer #%d.\n", fbidx);
+ if (fbidx = 0)
+ goto err_info0_alloc;
+ else
+ goto err_info1_alloc;
+ } else {
+ struct hisifb_par *par;
+
+ inf_msg("framebuffer #%d alloc okay\n", fbidx);
+ share->fbinfo[fbidx] = info[fbidx];
+ par = info[fbidx]->par;
+ par->share = share;
+
+ /* set fb_info structure */
+ if (hisifb_set_fbinfo(info[fbidx], fbidx)) {
+ err_msg("Failed to initial fb_info #%d.\n", fbidx);
+ if (fbidx = 0)
+ goto err_info0_set;
+ else
+ goto err_info1_set;
+ }
+
+ /* register frame buffer*/
+ inf_msg("Ready to register framebuffer #%d.\n", fbidx);
+ if (register_framebuffer(info[fbidx]) < 0) {
+ err_msg("Failed to register fb_info #%d.\n", fbidx);
+ if (fbidx = 0)
+ goto err_register0;
+ else
+ goto err_register1;
+ }
+ inf_msg("Accomplished register framebuffer #%d.\n", fbidx);
+ }
+
+ return 0;
+
+err_register1:
+err_info1_set:
+ framebuffer_release(info[1]);
+err_info1_alloc:
+ unregister_framebuffer(info[0]);
+err_register0:
+err_info0_set:
+ framebuffer_release(info[0]);
+err_info0_alloc:
+err_map:
+ kfree(spec_share);
+err_share:
+err_enable:
+ return -ENODEV;
+}
+
+static void hisifb_pci_remove(struct pci_dev *pdev)
+{
+ struct fb_info *info;
+ struct hisi_share *share;
+ void *spec_share;
+ struct hisifb_par *par;
+ int cnt;
+
+
+ cnt = 2;
+ share = pci_get_drvdata(pdev);
+
+ while (cnt-- > 0) {
+ info = share->fbinfo[cnt];
+ if (!info)
+ continue;
+ par = info->par;
+
+ unregister_framebuffer(info);
+ /* clean crtc & output allocations*/
+ par->crtc.clear(&par->crtc);
+ par->output.clear(&par->output);
+ /* release frame buffer*/
+ framebuffer_release(info);
+ }
+#ifdef CONFIG_MTRR
+ if (share->mtrr.vram_added)
+ mtrr_del(share->mtrr.vram, share->vidmem_start,
+ share->vidmem_size);
+#endif
+
+ iounmap(share->pvreg);
+ iounmap(share->pvmem);
+
+ spec_share = share;
+
+ kfree(g_settings);
+ kfree(spec_share);
+ pci_set_drvdata(pdev, NULL);
+}
+
+/*chip specific g_option configuration routine */
+static void hisi_fb_setup(struct hisi_share *share, char *src)
+{
+ struct hisi_a_share *spec_share;
+ char *opt;
+#ifdef CAP_EXPENSION
+ char *exp_res;
+#endif
+ int swap;
+
+ spec_share = container_of(share, struct hisi_a_share, share);
+#ifdef CAP_EXPENSIION
+ exp_res = NULL;
+#endif
+ swap = 0;
+
+ spec_share->state.initParm.chip_clk = 0;
+ spec_share->state.initParm.mem_clk = 0;
+ spec_share->state.initParm.master_clk = 0;
+ spec_share->state.initParm.power_mode = 0;
+ spec_share->state.initParm.all_eng_off = 0;
+ spec_share->state.initParm.reset_memory = 1;
+
+ /*defaultly turn g_hwcursor on for both view */
+ g_hwcursor = 0;
+
+ if (!src || !*src) {
+ war_msg("no specific g_option.\n");
+ goto NO_PARAM;
+ }
+
+
+ while ((opt = strsep(&src, ",")) != NULL) {
+ if (!strncmp(opt, "swap", strlen("swap")))
+ swap = 1;
+ else if (!strncmp(opt, "nocrt", strlen("nocrt")))
+ spec_share->state.nocrt = 1;
+ else if (!strncmp(opt, "36bit", strlen("36bit")))
+ spec_share->state.pnltype = TYPE_DOUBLE_TFT;
+ else if (!strncmp(opt, "18bit", strlen("18bit")))
+ spec_share->state.pnltype = TYPE_DUAL_TFT;
+ else if (!strncmp(opt, "24bit", strlen("24bit")))
+ spec_share->state.pnltype = TYPE_24TFT;
+#ifdef CAP_EXPANSION
+ else if (!strncmp(opt, "exp:", strlen("exp:")))
+ exp_res = opt + strlen("exp:");
+#endif
+ else if (!strncmp(opt, "nohwc0", strlen("nohwc0")))
+ g_hwcursor &= ~0x1;
+ else if (!strncmp(opt, "nohwc1", strlen("nohwc1")))
+ g_hwcursor &= ~0x2;
+ else if (!strncmp(opt, "nohwc", strlen("nohwc")))
+ g_hwcursor = 0;
+ else {
+ if (!g_fbmode[0]) {
+ g_fbmode[0] = opt;
+ inf_msg("find fbmode0 : %s.\n", g_fbmode[0]);
+ } else if (!g_fbmode[1]) {
+ g_fbmode[1] = opt;
+ inf_msg("find fbmode1 : %s.\n", g_fbmode[1]);
+ } else {
+ war_msg("How many view you wann set?\n");
+ }
+ }
+ }
+#ifdef CAP_EXPANSION
+ if (getExpRes(exp_res, &spec_share->state.xLCD,
+ &spec_share->state.yLCD)) {
+ /* seems exp_res is not valid*/
+ spec_share->state.xLCD = spec_share->state.yLCD = 0;
+ }
+#endif
+
+NO_PARAM:
+ if (share->dual) {
+ if (swap)
+ spec_share->state.dataflow = hisi_dual_swap;
+ else
+ spec_share->state.dataflow = hisi_dual_normal;
+ } else {
+ if (swap)
+ spec_share->state.dataflow = hisi_simul_sec;
+ else
+ spec_share->state.dataflow = hisi_simul_pri;
+ }
+
+}
+
+static int __init hisifb_setup(char *options)
+{
+ int len;
+ char *opt, *tmp;
+
+
+ if (!options || !*options) {
+ war_msg("no options.\n");
+ return 0;
+ }
+
+ inf_msg("options:%s\n", options);
+ len = strlen(options) + 1;
+ g_settings = kzalloc(len, GFP_KERNEL);
+ if (!g_settings)
+ return -ENOMEM;
+
+ tmp = g_settings;
+
+ /* Notes:
+ * char * strsep(char **s,const char * ct);
+ * @s: the string to be searched
+ * @ct :the characters to search for
+ * strsep() updates @options to pointer after the first found token
+ * it also returns the pointer ahead the token.
+ */
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ /* options that mean for any chips are configured here */
+ if (!strncmp(opt, "noaccel", strlen("noaccel")))
+ g_noaccel = 1;
+#ifdef CONFIG_MTRR
+ else if (!strncmp(opt, "nomtrr", strlen("nomtrr")))
+ g_nomtrr = 1;
+#endif
+ else if (!strncmp(opt, "dual", strlen("dual")))
+ g_dualview = 1;
+ else {
+ strcat(tmp, opt);
+ tmp += strlen(opt);
+ if (options != NULL)
+ *tmp++ = ',';
+ else
+ *tmp++ = 0;
+ }
+ }
+
+ /* misc g_settings are transport to chip specific routines */
+ inf_msg("parameter left for chip specific analysis:%s\n", g_settings);
+ return 0;
+}
+
+static void claim(void)
+{
+ inf_msg("Hisilicon Driver version: v" _version_ "\n");
+}
+
+
+static int __init hisifb_init(void)
+{
+ char *option;
+ int ret;
+
+
+ claim();
+#ifdef MODULE
+ option = g_option;
+#else
+ if (fb_get_options("hisifb", &option))
+ return -ENODEV;
+#endif
+
+ hisifb_setup(option);
+ ret = pci_register_driver(&hisifb_driver);
+ return ret;
+}
+
+module_init(hisifb_init);
+
+#ifdef MODULE
+static void __exit hisifb_exit(void)
+{
+ inf_msg(_moduleName_ " exit\n");
+ pci_unregister_driver(&hisifb_driver);
+}
+module_exit(hisifb_exit);
+
+module_param(g_option, charp, S_IRUGO);
+
+MODULE_PARM_DESC(g_option,
+"\n\t\tCommon options:\n"
+"\t\tnoaccel:disable 2d capabilities\n"
+"\t\tnomtrr:disable MTRR attribute for video memory\n"
+"\t\tdualview:dual frame buffer feature enabled\n"
+"\t\tnohwc:disable hardware cursor\n"
+"\t\tUsual example:\n"
+"\t\tinsmod ./hisiliconfb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
+"\t\tFor more detail chip specific options,please contact hisilicon\n"
+);
+#endif
+
+MODULE_AUTHOR("lixiancai<lixiancai@huawei.com>");
+MODULE_DESCRIPTION("Frame buffer driver for Hisilicon graphic device");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, hisi_pci_table);
diff --git a/drivers/video/fbdev/hisilicon/hisi_drv.h b/drivers/video/fbdev/hisilicon/hisi_drv.h
new file mode 100644
index 0000000..e859325
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_drv.h
@@ -0,0 +1,181 @@
+#ifndef HISI_DRV_H_
+#define HISI_DRV_H_
+
+#include "hisi_chip.h"
+
+
+#define _version_ "1.0.0"
+
+/* Vendor and Device id for HISILICON Graphics chip*/
+#define PCI_VENDOR_ID_HIS 0x19e5
+#define PCI_DEVID_HS_VGA 0x1711
+
+
+#define _moduleName_ "hisifb"
+#define PFX _moduleName_ ": "
+#define err_msg(fmt, args...) pr_err(PFX fmt, ## args)
+#define war_msg(fmt, args...) pr_warn(PFX fmt, ## args)
+#define inf_msg(fmt, args...) pr_info(PFX fmt, ## args)
+#define dbg_msg(fmt, args...) pr_debug(PFX fmt, ## args)
+
+#define MB(x) ((x) << 20)
+#define MHZ(x) ((x) * 1000000)
+/* align should be 2,4,8,16 */
+#define PADDING(align, data) (((data) + (align) - 1)&(~((align) - 1)))
+
+
+struct hisi_accel {
+ /* base virtual address of DPR registers */
+ unsigned char __iomem *dpr_base;
+ /* base virtual address of de data port */
+ unsigned char __iomem *dp_port_base;
+
+ /* function fointers */
+ int (*de_init)(struct hisi_accel *);
+
+ int (*de_wait)(void);/* see if hardware ready to work */
+
+ int (*de_fillrect)(struct hisi_accel *, u32, u32, u32,
+ u32, u32, u32, u32, u32, u32);
+
+ int (*de_copyarea)(struct hisi_accel *, u32, u32, u32,
+ u32, u32, u32, u32, u32, u32, u32, u32, u32);
+
+ int (*de_imageblit)(struct hisi_accel *, const char *,
+ u32, u32, u32, u32, u32, u32, u32,
+ u32, u32, u32, u32, u32);
+};
+
+/* hisi_share stands for a presentation of two frame buffer
+* that use one smi adaptor , it is similar to a basic class of C++
+*/
+struct hisi_share {
+ /* driver members */
+ struct pci_dev *pdev;
+ struct fb_info *fbinfo[2];
+ struct hisi_accel accel;
+ int accel_off;
+ int dual;
+#ifdef CONFIG_MTRR
+ int mtrr_off;
+ struct {
+ int vram;
+ int vram_added;
+ } mtrr;
+#endif
+ /* all smi graphic adaptor get below attributes */
+ resource_size_t vidmem_start;
+ resource_size_t vidreg_start;
+ resource_size_t vidmem_size;
+ resource_size_t vidreg_size;
+ unsigned char __iomem *pvreg;
+ unsigned char __iomem *pvmem;
+ /* function pointers */
+ void (*suspend)(void);
+ void (*resume)(void);
+};
+
+struct hisi_cursor {
+ /* cursor width ,height and size */
+ int w;
+ int h;
+ int size;
+ /* hardware limitation */
+ int maxW;
+ int maxH;
+ /* base virtual address and offset of cursor image */
+ char __iomem *vstart;
+ int offset;
+ /* mmio addr of hw cursor */
+ char __iomem *mmio;
+ /* the hisi_share of this adaptor */
+ struct hisi_share *share;
+ /* proc_routines */
+ void (*enable)(struct hisi_cursor *);
+ void (*disable)(struct hisi_cursor *);
+ void (*set_size)(struct hisi_cursor *, int, int);
+ void (*set_pos)(struct hisi_cursor *, int, int);
+ void (*set_color)(struct hisi_cursor *, u32, u32);
+ void (*set_data)(struct hisi_cursor *, u16, const u8*, const u8*);
+};
+
+struct hisifb_crtc {
+ unsigned char __iomem *vcursor;/*virtual address of cursor*/
+ unsigned char __iomem *vscreen;/*virtual address of on_screen*/
+ int ocursor;/*cursor address offset in vidmem*/
+ int oscreen;/*onscreen address offset in vidmem*/
+ int channel;/* which channel this crtc stands for*/
+ /* this view's video memory max size */
+ resource_size_t vidmem_size;
+
+ /* below attributes belong to info->fix,
+ * their value depends on specific adaptor
+ */
+ u16 line_pad;/* padding information:0,1,2,4,8,16,... */
+ u16 xpanstep;
+ u16 ypanstep;
+ u16 ywrapstep;
+
+ void *priv;
+
+ int (*proc_set_mode)(struct hisifb_crtc *,
+ struct fb_var_screeninfo *,
+ struct fb_fix_screeninfo *);
+ int (*proc_check_mode)(struct hisifb_crtc *,
+ struct fb_var_screeninfo*);
+ int (*proc_set_col_reg)(struct hisifb_crtc *,
+ ushort, ushort, ushort, ushort);
+ void (*clear)(struct hisifb_crtc *);
+ /* cursor information */
+ struct hisi_cursor cursor;
+};
+
+struct hisifb_output {
+ int dpms;
+ int paths;
+ /*which paths(s) this output stands for,hisi vga may not metioned:
+ * paths=1:means output for panel paths
+ * paths=2:means output for crt paths
+ * paths=3:means output for both panel and crt paths
+ */
+
+ int *channel;
+ /*which channel these outputs linked with, hisi vga may
+ * not metioned:channel=0 means primary channel
+ * channel=1 means secondary channel
+ * output->channel => &crtc->channel
+ */
+ void *priv;
+ int (*proc_set_mode)(struct hisifb_output *,
+ struct fb_var_screeninfo *,
+ struct fb_fix_screeninfo *);
+ int (*proc_check_mode)(struct hisifb_output *,
+ struct fb_var_screeninfo *);
+ int (*proc_set_blank)(struct hisifb_output *, int);
+ void (*clear)(struct hisifb_output *);
+};
+
+struct hisifb_par {
+ /* either 0 or 1 for dual head adaptor,0 is the older one registered */
+ int index;
+ unsigned int pseudo_palette[256];
+ struct hisifb_crtc crtc;
+ struct hisifb_output output;
+ struct fb_info *info;
+ struct hisi_share *share;
+};
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+
+static inline unsigned long ps_to_hz(unsigned int psvalue)
+{
+ unsigned long long numerator = 1000 * 1000 * 1000 * 1000ULL;
+ /* 10^12 / picosecond period gives frequency in Hz */
+ do_div(numerator, psvalue);
+ return (unsigned long)numerator;
+}
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_help.h b/drivers/video/fbdev/hisilicon/hisi_help.h
new file mode 100644
index 0000000..cfbd77e
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_help.h
@@ -0,0 +1,64 @@
+#ifndef HISI_HELP_H__
+#define HISI_HELP_H__
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+
+/* Internal macros */
+#define _F_START(f) (0 ? f)
+#define _F_END(f) (1 ? f)
+#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f))
+#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f))
+#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f))
+#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f))
+
+
+/* Global macros */
+#define FIELD_GET(x, reg, field) \
+( \
+ _F_NORMALIZE((x), reg ## _ ## field) \
+)
+
+#define FIELD_SET(x, reg, field, value) \
+( \
+ (x & ~_F_MASK(reg ## _ ## field)) \
+ | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
+)
+
+#define FIELD_VALUE(x, reg, field, value) \
+( \
+ (x & ~_F_MASK(reg ## _ ## field)) \
+ | _F_DENORMALIZE(value, reg ## _ ## field) \
+)
+
+#define FIELD_CLEAR(reg, field) \
+( \
+ ~_F_MASK(reg ## _ ## field) \
+)
+
+
+/* Field Macros */
+#define FIELD_START(field) (0 ? field)
+#define FIELD_END(field) (1 ? field)
+#define FIELD_SIZE(field) \
+ (1 + FIELD_END(field) - FIELD_START(field))
+#define FIELD_MASK(field) \
+ (((1 << (FIELD_SIZE(field)-1)) |\
+ ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field))
+#define FIELD_NORMALIZE(reg, field) \
+ (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
+#define FIELD_DENORMALIZE(field, value) \
+ (((value) << FIELD_START(field)) & FIELD_MASK(field))
+#define RGB(r, g, b) \
+( \
+ (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define PEEK32(addr) readl((addr)+mmio_hisi_vga)
+#define POKE32(addr, data) writel((data), (addr)+mmio_hisi_vga)
+extern unsigned char __iomem *mmio_hisi_vga;
+
+
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_hw.c b/drivers/video/fbdev/hisilicon/hisi_hw.c
new file mode 100644
index 0000000..e993f25
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_hw.c
@@ -0,0 +1,293 @@
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include "hisi_drv.h"
+#include "hisi_help.h"
+#include "hisi_hw.h"
+#include "hisi_mode.h"
+#include "hisi_power.h"
+#include "hisi_reg.h"
+
+unsigned char __iomem *mmio_hisi_vga;
+
+int hw_hisi_map(struct hisi_share *share, struct pci_dev *pdev)
+{
+ int ret;
+ struct hisi_a_share *spec_share;
+
+ spec_share = container_of(share, struct hisi_a_share, share);
+ ret = 0;
+
+ share->vidreg_start = pci_resource_start(pdev, 1);
+ share->vidreg_size = MB(2);
+
+ /* now map mmio and vidmem*/
+ share->pvreg = ioremap_nocache(share->vidreg_start, share->vidreg_size);
+ if (!share->pvreg) {
+ err_msg("mmio failed\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ share->accel.dpr_base = share->pvreg + DE_BASE_ADDR_TYPE1;
+ share->accel.dp_port_base = share->pvreg + DE_PORT_ADDR_TYPE1;
+
+ mmio_hisi_vga = share->pvreg;
+
+ share->vidmem_start = pci_resource_start(pdev, 0);
+ /* don't use pdev_resource[x].end - resource[x].start to
+ * calculate the resource size,its only the maximum available
+ * size but not the actual size,hisilicon provide 16MB buffer.
+ */
+ share->vidmem_size = MB(16);
+ inf_msg("video memory size = %llu mb\n", share->vidmem_size >> 20);
+
+ share->pvmem = ioremap(share->vidmem_start, share->vidmem_size);
+
+ if (!share->pvmem) {
+ err_msg("Map video memory failed\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ inf_msg("video memory vaddr = %p\n", share->pvmem);
+
+exit:
+ return ret;
+}
+
+int hw_hisi_inithw(struct hisi_share *share, struct pci_dev *pdev)
+{
+ struct hisi_a_share *spec_share;
+ struct init_status *parm;
+
+
+ spec_share = container_of(share, struct hisi_a_share, share);
+ parm = &spec_share->state.initParm;
+
+ if (parm->chip_clk = 0)
+ parm->chip_clk = DEFAULT_HISILE_CHIP_CLOCK;
+
+ if (parm->mem_clk = 0)
+ parm->mem_clk = parm->chip_clk;
+
+ if (parm->master_clk = 0)
+ parm->master_clk = parm->chip_clk / 3;
+
+ hisi_init_hw((struct _initchip_param_t *)&spec_share->state.initParm);
+
+ /* init 2d engine */
+ if (!share->accel_off)
+ hw_hisi_init_accel(share);
+
+ return 0;
+}
+
+int hw_hisi_output_setmode(struct hisifb_output *output,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
+{
+ u32 reg;
+
+ /* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
+ reg = PEEK32(DISPLAY_CONTROL_HISILE);
+ reg |= 0xf;
+ POKE32(DISPLAY_CONTROL_HISILE, reg);
+
+ inf_msg("set output mode done\n");
+
+ return 0;
+}
+
+int hw_hisi_crtc_checkmode(struct hisifb_crtc *crtc,
+ struct fb_var_screeninfo *var)
+{
+ switch (var->bits_per_pixel) {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+* set the controller's mode for @crtc
+* charged with @var and @fix parameters
+*/
+int hw_hisi_crtc_setmode(struct hisifb_crtc *crtc,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
+{
+ int ret;
+ u32 reg;
+ struct mode_para modparm;
+ enum clock_type clock;
+ struct hisifb_par *par;
+
+ ret = 0;
+ par = container_of(crtc, struct hisifb_par, crtc);
+ /* set timing */
+ modparm.pixel_clock = ps_to_hz(var->pixclock);
+ modparm.vsync_polarity + (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS : NEG;
+ modparm.hsync_polarity + (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS : NEG;
+ modparm.clock_phase_polarity + (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS : NEG;
+ modparm.h_display_end = var->xres;
+ modparm.h_sync_width = var->hsync_len;
+ modparm.h_sync_start = var->xres + var->right_margin;
+ modparm.horizontal_total = var->xres +
+ var->left_margin + var->right_margin + var->hsync_len;
+ modparm.v_display_end = var->yres;
+ modparm.v_sync_height = var->vsync_len;
+ modparm.v_sync_start = var->yres + var->lower_margin;
+ modparm.vertical_total = var->yres + var->upper_margin +
+ var->lower_margin + var->vsync_len;
+
+ /* choose pll */
+ clock = SECONDARY_PLL;
+
+ dbg_msg("Request pixel clock = %lu\n", modparm.pixel_clock);
+ ret = hisi_set_mode_timing(&modparm, clock);
+ if (ret) {
+ err_msg("Set mode timing failed\n");
+ goto exit;
+ }
+
+ /* not implemented now */
+ POKE32(CRT_FB_ADDRESS, crtc->oscreen);
+ reg = var->xres * (var->bits_per_pixel >> 3);
+ /* crtc->channel is not equal to
+ * par->index on numeric,be aware of that
+ */
+ reg = PADDING(crtc->line_pad, reg);
+
+ POKE32(CRT_FB_WIDTH,
+ FIELD_VALUE(0, CRT_FB_WIDTH, WIDTH, reg) |
+ FIELD_VALUE(0, CRT_FB_WIDTH, OFFSET, fix->line_length));
+
+ /* SET PIXEL FORMAT */
+ reg = PEEK32(CRT_DISPLAY_CTRL);
+ reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL,
+ FORMAT, var->bits_per_pixel >> 4);
+ POKE32(CRT_DISPLAY_CTRL, reg);
+
+exit:
+ return ret;
+}
+
+int hw_hisi_set_col_reg(struct hisifb_crtc *crtc,
+ ushort index, ushort red,
+ ushort green, ushort blue)
+{
+ static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
+
+
+ POKE32(add[crtc->channel] + index * 4,
+ (red << 16) | (green << 8) | blue);
+
+ return 0;
+}
+
+int hw_hisile_set_blank(struct hisifb_output *output, int blank)
+{
+ int dpms, crtdb;
+
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ dpms = CRT_DISPLAY_CTRL_DPMS_0;
+ crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
+ break;
+ case FB_BLANK_NORMAL:
+ dpms = CRT_DISPLAY_CTRL_DPMS_0;
+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ dpms = CRT_DISPLAY_CTRL_DPMS_2;
+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ dpms = CRT_DISPLAY_CTRL_DPMS_1;
+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
+ break;
+ case FB_BLANK_POWERDOWN:
+ dpms = CRT_DISPLAY_CTRL_DPMS_3;
+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (output->paths & hisi_crt) {
+ POKE32(CRT_DISPLAY_CTRL,
+ FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL),
+ CRT_DISPLAY_CTRL, DPMS, dpms));
+ POKE32(CRT_DISPLAY_CTRL,
+ FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL),
+ CRT_DISPLAY_CTRL, BLANK, crtdb));
+ }
+
+ return 0;
+}
+
+void hw_hisi_init_accel(struct hisi_share *share)
+{
+ u32 reg;
+
+
+ enable_2d_engine(1);
+
+ reg = PEEK32(DE_STATE1);
+ reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, ON);
+ POKE32(DE_STATE1, reg);
+
+ reg = PEEK32(DE_STATE1);
+ reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, OFF);
+ POKE32(DE_STATE1, reg);
+
+ /* call 2d init */
+ share->accel.de_init(&share->accel);
+}
+
+int hw_hisile_dewait(void)
+{
+ int i = 0x10000000;
+
+ while (i--) {
+ unsigned int dwval = PEEK32(DE_STATE2);
+
+ if ((FIELD_GET(dwval, DE_STATE2, DE_STATUS)
+ = DE_STATE2_DE_STATUS_IDLE) &&
+ (FIELD_GET(dwval, DE_STATE2, DE_FIFO)
+ = DE_STATE2_DE_FIFO_EMPTY) &&
+ (FIELD_GET(dwval, DE_STATE2, DE_MEM_FIFO)
+ = DE_STATE2_DE_MEM_FIFO_EMPTY)) {
+ return 0;
+ }
+ }
+
+ /* timeout error */
+ return -1;
+}
diff --git a/drivers/video/fbdev/hisilicon/hisi_hw.h b/drivers/video/fbdev/hisilicon/hisi_hw.h
new file mode 100644
index 0000000..c4e40b3
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_hw.h
@@ -0,0 +1,95 @@
+#ifndef HISI_HW_H__
+#define HISI_HW_H__
+
+
+#define DEFAULT_HISILE_CHIP_CLOCK 333
+
+/* notes: below address are the offset value from de_base_address (0x100000)*/
+
+/* de_base is at mmreg_1mb*/
+#define DE_BASE_ADDR_TYPE1 0x100000
+
+/* type1 data port address is at mmreg_0x110000*/
+#define DE_PORT_ADDR_TYPE1 0x110000
+
+
+
+enum hisilicon_pnltype {
+
+ TYPE_24TFT = 0,/* 24bit tft */
+
+ TYPE_DUAL_TFT = 2,/* dual 18 bit tft */
+
+ TYPE_DOUBLE_TFT = 1,/* 36 bit double pixel tft */
+};
+
+/* vga channel is not concerned */
+enum hisilicon_dataflow {
+ hisi_simul_pri,/* primary => all head */
+ hisi_simul_sec,/* secondary => all head */
+ hisi_dual_normal,/* primary => panel head and secondary => crt */
+ hisi_dual_swap,/* primary => crt head and secondary => panel */
+};
+
+
+enum hisi_channel {
+ hisi_primary = 0,
+ /* enum value equal to the register filed data */
+ hisi_secondary = 1,
+};
+
+enum hisi_display_path {
+ hisi_panel = 1,
+ hisi_crt = 2,
+ hisi_pnc = 3,/* panel and crt */
+};
+
+struct init_status {
+ ushort power_mode;
+ /* below three clocks are in unit of MHZ*/
+ ushort chip_clk;
+ ushort mem_clk;
+ ushort master_clk;
+ ushort all_eng_off;
+ ushort reset_memory;
+};
+
+struct hisi_state {
+ struct init_status initParm;
+ enum hisilicon_pnltype pnltype;
+ enum hisilicon_dataflow dataflow;
+ int nocrt;
+ int xlcd;
+ int ylcd;
+};
+
+/* hisi_a_share stands for a presentation of two frame buffer
+ * that use one hisi adaptor
+*/
+
+struct hisi_a_share {
+ /* Put hisi_share struct to the first place of hisi_a_share */
+ struct hisi_share share;
+ struct hisi_state state;
+ int hwcursor;
+ /*0: no hardware cursor
+ * 1: primary crtc hw cursor enabled,
+ * 2: secondary crtc hw cursor enabled
+ * 3: both ctrc hw cursor enabled
+ */
+};
+
+int hw_hisi_map(struct hisi_share *share, struct pci_dev *pdev);
+int hw_hisi_inithw(struct hisi_share*, struct pci_dev *);
+void hw_hisi_init_accel(struct hisi_share *);
+int hw_hisile_dewait(void);
+
+int hw_hisi_output_setmode(struct hisifb_output*, struct fb_var_screeninfo*,
+ struct fb_fix_screeninfo*);
+int hw_hisi_crtc_checkmode(struct hisifb_crtc*, struct fb_var_screeninfo*);
+int hw_hisi_crtc_setmode(struct hisifb_crtc*, struct fb_var_screeninfo*,
+ struct fb_fix_screeninfo*);
+int hw_hisi_set_col_reg(struct hisifb_crtc*, ushort, ushort, ushort, ushort);
+int hw_hisile_set_blank(struct hisifb_output*, int);
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_mode.c b/drivers/video/fbdev/hisilicon/hisi_mode.c
new file mode 100644
index 0000000..fba0e02
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_mode.c
@@ -0,0 +1,286 @@
+#include "hisi_help.h"
+#include "hisi_mode.h"
+#include "hisi_reg.h"
+
+/*
+ * Timing parameter for modes supported by Hisilicon
+ * Note that most timings in this table is made according to standard VESA
+ * parameters.
+ * It is a subset of gDefaultModeParamTable[], all timings are copy from it.
+ */
+static struct mode_para g_hisi_mode_para_table[] = {
+/* 640 x 480 [4:3] */
+{ 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG},
+
+/* 800 x 600 [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+ * taken from the VESA Monitor Timing Standard
+ */
+{1056, 800, 840, 128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, POS},
+
+/* 1024 x 768 [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+ * taken from the VESA Monitor Timing Standard
+ */
+{1344, 1024, 1048, 136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG},
+
+/* 1152 x 864 [4:3] -- Widescreen eXtended Graphics Array */
+{1475, 1152, 1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG},
+
+/* 1280 x 720 [16:9] -- HDTV (WXGA) */
+{1650, 1280, 1390, 40, POS, 750, 720, 725, 5, POS, 74250000, 45000, 60, NEG},
+
+/* 1280 x 768 [5:3] -- Not a popular mode */
+{1664, 1280, 1344, 128, POS, 798, 768, 771, 7, POS, 79500000, 47776, 60, NEG},
+
+/* 1280 x 960 [4:3] */
+/* The first commented line below are taken from SM502, the rest timing are
+ * taken from the VESA Monitor Timing Standard
+ */
+{1800, 1280, 1376, 112, POS, 1000, 960, 961, 3, POS, 108000000, 60000, 60, NEG},
+
+/* 1280 x 1024 [5:4] */
+/* GTF with C = 40, M = 600, J = 20, K = 128 */
+{1688, 1280, 1328, 112, NEG, 1066, 1024,
+ 1025, 3, POS, 108000000, 63900, 60, NEG},
+
+/* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */
+/* VESA */
+{2160, 1600, 1664, 192, POS, 1250, 1200,
+ 1201, 3, POS, 162000000, 75000, 60, NEG},
+
+/* 1920 x 1080 [16:9]. This is a make-up value, need to be proven.
+ * The Pixel clock is calculated based on the maximum resolution of
+ * "Single Link" DVI, which support a maximum 165MHz pixel clock.
+ * The second values are taken from:
+ *http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf
+ */
+{2200, 1920, 2008, 44, POS, 1125, 1080,
+ 1084, 5, POS, 148500000, 67500, 60, NEG},
+
+/* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */
+{2592, 1920, 2048, 208, NEG, 1242, 1200,
+ 1201, 3, POS, 193160000, 74522, 60, NEG},
+
+/* End of table. */
+{ 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+/*
+ * This function takes care the extra registers and bit fields required to set
+ * up a mode in board.
+ *
+ * Explanation about Display Control register:
+ * FPGA only supports 7 predefined pixel clocks, and clock select is
+ * in bit 4:0 of new register 0x802a8.
+ */
+unsigned int display_ctrl_adjust(struct mode_para *para, unsigned int ctrl)
+{
+ unsigned long x, y;
+ unsigned long pll1; /* bit[31:0] of PLL */
+ unsigned long pll2; /* bit[63:32] of PLL */
+
+ x = para->h_display_end;
+ y = para->v_display_end;
+
+ /* Hisilicon has to set up a new register for PLL control
+ *(CRT_PLL1_HS & CRT_PLL2_HS).
+ */
+ if (x = 800 && y = 600) {
+ pll1 = CRT_PLL1_HS_40MHZ;
+ pll2 = CRT_PLL2_HS_40MHZ;
+ } else if (x = 1024 && y = 768) {
+ pll1 = CRT_PLL1_HS_65MHZ;
+ pll2 = CRT_PLL2_HS_65MHZ;
+ } else if (x = 1152 && y = 864) {
+ pll1 = CRT_PLL1_HS_80MHZ_1152;
+ pll2 = CRT_PLL2_HS_80MHZ;
+ } else if (x = 1280 && y = 768) {
+ pll1 = CRT_PLL1_HS_80MHZ;
+ pll2 = CRT_PLL2_HS_80MHZ;
+ } else if (x = 1280 && y = 720) {
+ pll1 = CRT_PLL1_HS_74MHZ;
+ pll2 = CRT_PLL2_HS_74MHZ;
+ } else if (x = 1280 && y = 960) {
+ pll1 = CRT_PLL1_HS_108MHZ;
+ pll2 = CRT_PLL2_HS_108MHZ;
+ } else if (x = 1280 && y = 1024) {
+ pll1 = CRT_PLL1_HS_108MHZ;
+ pll2 = CRT_PLL2_HS_108MHZ;
+ } else if (x = 1600 && y = 1200) {
+ pll1 = CRT_PLL1_HS_162MHZ;
+ pll2 = CRT_PLL2_HS_162MHZ;
+ } else if (x = 1920 && y = 1080) {
+ pll1 = CRT_PLL1_HS_148MHZ;
+ pll2 = CRT_PLL2_HS_148MHZ;
+ } else if (x = 1920 && y = 1200) {
+ pll1 = CRT_PLL1_HS_193MHZ;
+ pll2 = CRT_PLL2_HS_193MHZ;
+ } else /* default to VGA clock */ {
+ pll1 = CRT_PLL1_HS_25MHZ;
+ pll2 = CRT_PLL2_HS_25MHZ;
+ }
+
+ POKE32(CRT_PLL2_HS, pll2);
+ set_vclock_hisilicon(pll1);
+
+
+ /* Hisilicon has to set up the top-left and bottom-right
+ * registers as well.
+ * Note that normal chip only use those two register for
+ * auto-centering mode.
+ */
+ POKE32(CRT_AUTO_CENTERING_TL,
+ FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0)
+ | FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0));
+
+ POKE32(CRT_AUTO_CENTERING_BR,
+ FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y-1)
+ | FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x-1));
+
+ /* Assume common fields in ctrl have been properly set before
+ * calling this function.
+ * This function only sets the extra fields in ctrl.
+ */
+
+ /* Set bit 25 of display controller: Select CRT or VGA clock */
+ ctrl = FIELD_SET(ctrl, CRT_DISPLAY_CTRL, CRTSELECT, CRT);
+
+ /* Set bit 14 of display controller */
+ ctrl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLOCK_PHASE);
+ if (para->clock_phase_polarity = NEG)
+ ctrl = FIELD_SET(ctrl,
+ CRT_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW);
+ else
+ ctrl = FIELD_SET(ctrl, CRT_DISPLAY_CTRL,
+ CLOCK_PHASE, ACTIVE_HIGH);
+
+ POKE32(CRT_DISPLAY_CTRL, ctrl);
+
+ return ctrl;
+}
+
+/* only timing related registers will be programed */
+static int program_mode_registers(struct mode_para *para, struct pll *pll)
+{
+ int ret = 0;
+ unsigned int val;
+
+ if (pll->clock_type = SECONDARY_PLL) {
+ /* programe secondary pixel clock */
+ POKE32(CRT_PLL_CTRL, format_pll_reg(pll));
+ POKE32(CRT_HORIZONTAL_TOTAL,
+ FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL,
+ TOTAL, para->horizontal_total - 1)|
+ FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL,
+ DISPLAY_END, para->h_display_end - 1));
+
+ POKE32(CRT_HORIZONTAL_SYNC,
+ FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH,
+ para->h_sync_width)|
+ FIELD_VALUE(0, CRT_HORIZONTAL_SYNC,
+ START, para->h_sync_start - 1));
+
+ POKE32(CRT_VERTICAL_TOTAL,
+ FIELD_VALUE(0, CRT_VERTICAL_TOTAL,
+ TOTAL, para->vertical_total - 1)|
+ FIELD_VALUE(0, CRT_VERTICAL_TOTAL,
+ DISPLAY_END, para->v_display_end - 1));
+
+ POKE32(CRT_VERTICAL_SYNC,
+ FIELD_VALUE(0, CRT_VERTICAL_SYNC,
+ HEIGHT, para->v_sync_height)|
+ FIELD_VALUE(0, CRT_VERTICAL_SYNC,
+ START, para->v_sync_start - 1));
+
+ val = FIELD_VALUE(0, CRT_DISPLAY_CTRL, VSYNC_PHASE,
+ para->vsync_polarity)|
+ FIELD_VALUE(0, CRT_DISPLAY_CTRL,
+ HSYNC_PHASE, para->hsync_polarity)|
+ FIELD_SET(0, CRT_DISPLAY_CTRL, TIMING, ENABLE)|
+ FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE);
+
+ display_ctrl_adjust(para, val);
+ } else {
+ ret = -1;
+ }
+ return ret;
+}
+
+/*
+ * find_mode_para
+ * This function locates the requested mode in the given parameter table
+ *
+ * Input:
+ * width - Mode width
+ * height - Mode height
+ * refresh_rate - Mode refresh rate
+ * index - Index that is used for multiple search of the same
+ * mode that have the same width, height, and refresh
+ * rate,but have different timing parameters.
+ *
+ * Output:
+ * Success: return a pointer to the mode_para entry.
+ * Fail: a NULL pointer.
+ */
+struct mode_para *find_mode_para(
+ unsigned long width,
+ unsigned long height,
+ unsigned long refresh_rate,
+ unsigned short index,
+ struct mode_para *para
+)
+{
+ unsigned short modeIndex = 0, tempIndex = 0;
+
+ /* Walk the entire mode table. */
+ while (para[modeIndex].pixel_clock != 0) {
+ if (((width = (unsigned long)(-1))
+ || (para[modeIndex].h_display_end = width))
+ && ((height = (unsigned long)(-1))
+ || (para[modeIndex].v_display_end = height))
+ && ((refresh_rate = (unsigned long)(-1))
+ || (para[modeIndex].vertical_freq = refresh_rate))) {
+
+ if (tempIndex < index)
+ tempIndex++;
+ else
+ return ¶[modeIndex];
+ }
+
+ /* Next entry */
+ modeIndex++;
+ }
+
+ /* No match */
+ return NULL;
+}
+
+int hisi_set_mode_timing(struct mode_para *para, enum clock_type clock)
+{
+ struct pll pll;
+ unsigned long width;
+ unsigned long height;
+ unsigned long refresh_rate;
+
+
+ pll.intput_freq = DEFAULT_INPUT_CLOCK;
+ pll.clock_type = clock;
+
+ width = para->h_display_end;
+ height = para->v_display_end;
+ refresh_rate = 60;
+
+ para = find_mode_para(width, height, refresh_rate, 0,
+ g_hisi_mode_para_table);
+
+ /* fix Segmentation fault on arm platform */
+#if defined(__i386__) || defined(__x86_64__)
+ /* set graphic mode via IO method */
+ outb_p(0x88, 0x3d4);
+ outb_p(0x06, 0x3d5);
+#endif
+
+ program_mode_registers(para, &pll);
+ return 0;
+}
diff --git a/drivers/video/fbdev/hisilicon/hisi_mode.h b/drivers/video/fbdev/hisilicon/hisi_mode.h
new file mode 100644
index 0000000..576e09a
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_mode.h
@@ -0,0 +1,39 @@
+#ifndef HISI_MODE_H__
+#define HISI_MODE_H__
+
+#include "hisi_chip.h"
+
+
+enum spolarity_t {
+ POS = 0, /* positive */
+ NEG, /* negative */
+};
+
+
+struct mode_para {
+ /* Horizontal timing. */
+ unsigned long horizontal_total;
+ unsigned long h_display_end;
+ unsigned long h_sync_start;
+ unsigned long h_sync_width;
+ enum spolarity_t hsync_polarity;
+
+ /* Vertical timing. */
+ unsigned long vertical_total;
+ unsigned long v_display_end;
+ unsigned long v_sync_start;
+ unsigned long v_sync_height;
+ enum spolarity_t vsync_polarity;
+
+ /* Refresh timing. */
+ unsigned long pixel_clock;
+ unsigned long horizontal_freq;
+ unsigned long vertical_freq;
+
+ /* Clock Phase. This clock phase only applies to Panel. */
+ enum spolarity_t clock_phase_polarity;
+};
+
+int hisi_set_mode_timing(struct mode_para *, enum clock_type);
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_power.c b/drivers/video/fbdev/hisilicon/hisi_power.c
new file mode 100644
index 0000000..0072f6b
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_power.c
@@ -0,0 +1,106 @@
+#include "hisi_help.h"
+#include "hisi_power.h"
+#include "hisi_reg.h"
+
+unsigned int get_power_mode(void)
+{
+ return FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE);
+}
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ * On hardware reset, power mode 0 is default.
+ */
+void set_power_mode(unsigned int power_mode)
+{
+ unsigned int control_value = 0;
+
+ control_value = PEEK32(POWER_MODE_CTRL);
+
+
+ switch (power_mode) {
+ case POWER_MODE_CTRL_MODE_MODE0:
+ control_value = FIELD_SET(control_value, POWER_MODE_CTRL,
+ MODE, MODE0);
+ break;
+
+ case POWER_MODE_CTRL_MODE_MODE1:
+ control_value = FIELD_SET(control_value, POWER_MODE_CTRL,
+ MODE, MODE1);
+ break;
+
+ case POWER_MODE_CTRL_MODE_SLEEP:
+ control_value = FIELD_SET(control_value, POWER_MODE_CTRL,
+ MODE, SLEEP);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Set up other fields in Power Control Register */
+ if (power_mode = POWER_MODE_CTRL_MODE_SLEEP) {
+ control_value = FIELD_SET(control_value, POWER_MODE_CTRL,
+ OSC_INPUT, OFF);
+ } else {
+ control_value = FIELD_SET(control_value, POWER_MODE_CTRL,
+ OSC_INPUT, ON);
+ }
+ /* Program new power mode. */
+ POKE32(POWER_MODE_CTRL, control_value);
+}
+
+void set_current_gate(unsigned int gate)
+{
+ unsigned int gate_reg;
+ unsigned int mode;
+
+ /* Get current power mode. */
+ mode = get_power_mode();
+
+ switch (mode) {
+ case POWER_MODE_CTRL_MODE_MODE0:
+ gate_reg = MODE0_GATE;
+ break;
+
+ case POWER_MODE_CTRL_MODE_MODE1:
+ gate_reg = MODE1_GATE;
+ break;
+
+ default:
+ gate_reg = MODE0_GATE;
+ break;
+ }
+ POKE32(gate_reg, gate);
+}
+
+/* This function enable/disable the 2D engine. */
+void enable_2d_engine(unsigned int enable)
+{
+ uint32_t gate;
+
+ gate = PEEK32(CURRENT_GATE);
+ if (enable) {
+ gate = FIELD_SET(gate, CURRENT_GATE, DE, ON);
+ gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON);
+ } else {
+ gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF);
+ gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF);
+ }
+
+ set_current_gate(gate);
+}
+
+void enable_dma(unsigned int enable)
+{
+ uint32_t gate;
+ /* Enable DMA Gate */
+ gate = PEEK32(CURRENT_GATE);
+ if (enable)
+ gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON);
+ else
+ gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF);
+
+ set_current_gate(gate);
+}
+
diff --git a/drivers/video/fbdev/hisilicon/hisi_power.h b/drivers/video/fbdev/hisilicon/hisi_power.h
new file mode 100644
index 0000000..59dc8954
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_power.h
@@ -0,0 +1,18 @@
+#ifndef HISI_POWER_H__
+#define HISI_POWER_H__
+
+
+
+unsigned int get_power_mode(void);
+
+/* This function sets the current power mode */
+void set_power_mode(unsigned int powerMode);
+
+/* This function sets current gate */
+void set_current_gate(unsigned int gate);
+
+/* This function enable/disable the 2D engine. */
+void enable_2d_engine(unsigned int enable);
+/* This function enable/disable the DMA Engine */
+void enable_dma(unsigned int enable);
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_reg.h b/drivers/video/fbdev/hisilicon/hisi_reg.h
new file mode 100644
index 0000000..ceb1ead
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_reg.h
@@ -0,0 +1,418 @@
+#ifndef HISI_REG_H__
+#define HISI_REG_H__
+
+#define F(v) v
+
+/* register definition */
+#define DE_STATE1 0x100054
+#define DE_STATE1_DE_ABORT F(0:0)
+#define DE_STATE1_DE_ABORT_OFF 0
+#define DE_STATE1_DE_ABORT_ON 1
+
+#define DE_STATE2 0x100058
+#define DE_STATE2_DE_FIFO F(3:3)
+#define DE_STATE2_DE_FIFO_NOTEMPTY 0
+#define DE_STATE2_DE_FIFO_EMPTY 1
+#define DE_STATE2_DE_STATUS F(2:2)
+#define DE_STATE2_DE_STATUS_IDLE 0
+#define DE_STATE2_DE_STATUS_BUSY 1
+#define DE_STATE2_DE_MEM_FIFO F(1:1)
+#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY 0
+#define DE_STATE2_DE_MEM_FIFO_EMPTY 1
+
+#define MISC_CTRL 0x000004
+#define MISC_CTRL_DAC_POWER F(20:20)
+#define MISC_CTRL_DAC_POWER_ON 0
+#define MISC_CTRL_DAC_POWER_OFF 1
+#define MISC_CTRL_LOCALMEM_RESET F(6:6)
+#define MISC_CTRL_LOCALMEM_RESET_RESET 0
+#define MISC_CTRL_LOCALMEM_RESET_NORMAL 1
+
+#define CURRENT_GATE 0x000040
+#define CURRENT_GATE_MCLK F(15:14)
+#define CURRENT_GATE_CSC F(4:4)
+#define CURRENT_GATE_CSC_OFF 0
+#define CURRENT_GATE_CSC_ON 1
+#define CURRENT_GATE_DE F(3:3)
+#define CURRENT_GATE_DE_OFF 0
+#define CURRENT_GATE_DE_ON 1
+#define CURRENT_GATE_DISPLAY F(2:2)
+#define CURRENT_GATE_DISPLAY_OFF 0
+#define CURRENT_GATE_DISPLAY_ON 1
+#define CURRENT_GATE_LOCALMEM F(1:1)
+#define CURRENT_GATE_LOCALMEM_OFF 0
+#define CURRENT_GATE_LOCALMEM_ON 1
+#define CURRENT_GATE_DMA F(0:0)
+#define CURRENT_GATE_DMA_OFF 0
+#define CURRENT_GATE_DMA_ON 1
+
+#define MODE0_GATE 0x000044
+
+#define MODE1_GATE 0x000048
+
+#define POWER_MODE_CTRL 0x00004C
+
+#define POWER_MODE_CTRL_OSC_INPUT F(3:3)
+#define POWER_MODE_CTRL_OSC_INPUT_OFF 0
+#define POWER_MODE_CTRL_OSC_INPUT_ON 1
+#define POWER_MODE_CTRL_ACPI F(2:2)
+#define POWER_MODE_CTRL_ACPI_OFF 0
+#define POWER_MODE_CTRL_ACPI_ON 1
+#define POWER_MODE_CTRL_MODE F(1:0)
+#define POWER_MODE_CTRL_MODE_MODE0 0
+#define POWER_MODE_CTRL_MODE_MODE1 1
+#define POWER_MODE_CTRL_MODE_SLEEP 2
+
+#define PANEL_PLL_CTRL 0x00005C
+#define PANEL_PLL_CTRL_BYPASS F(18:18)
+#define PANEL_PLL_CTRL_BYPASS_OFF 0
+#define PANEL_PLL_CTRL_BYPASS_ON 1
+#define PANEL_PLL_CTRL_POWER F(17:17)
+#define PANEL_PLL_CTRL_POWER_OFF 0
+#define PANEL_PLL_CTRL_POWER_ON 1
+#define PANEL_PLL_CTRL_INPUT F(16:16)
+#define PANEL_PLL_CTRL_INPUT_OSC 0
+#define PANEL_PLL_CTRL_INPUT_TESTCLK 1
+
+#define PANEL_PLL_CTRL_POD F(15:14)
+#define PANEL_PLL_CTRL_OD F(13:12)
+
+#define PANEL_PLL_CTRL_N F(11:8)
+#define PANEL_PLL_CTRL_M F(7:0)
+
+#define CRT_PLL_CTRL 0x000060
+/* Video Control */
+
+#define VIDEO_DISPLAY_CTRL 0x080040
+#define VIDEO_DISPLAY_CTRL_PLANE F(2:2)
+#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE 0
+#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE 1
+
+/* Video Alpha Control */
+
+#define VIDEO_ALPHA_DISPLAY_CTRL 0x080080
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE F(2:2)
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1
+
+/* Panel Cursor Control */
+#define ALPHA_DISPLAY_CTRL 0x080100
+#define ALPHA_DISPLAY_CTRL_PLANE F(2:2)
+#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0
+#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1
+
+/* CRT Graphics Control */
+#define CRT_DISPLAY_CTRL 0x080200
+#define CRT_DISPLAY_CTRL_RESERVED_1_MASK F(31:27)
+#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE 0
+#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE 0x1F
+
+/* register definition */
+#define CRT_DISPLAY_CTRL_DPMS F(31:30)
+#define CRT_DISPLAY_CTRL_DPMS_0 0
+#define CRT_DISPLAY_CTRL_DPMS_1 1
+#define CRT_DISPLAY_CTRL_DPMS_2 2
+#define CRT_DISPLAY_CTRL_DPMS_3 3
+
+/* register definition */
+#define CRT_DISPLAY_CTRL_CRTSELECT F(25:25)
+#define CRT_DISPLAY_CTRL_CRTSELECT_VGA 0
+#define CRT_DISPLAY_CTRL_CRTSELECT_CRT 1
+
+#define CRT_DISPLAY_CTRL_CLOCK_PHASE F(14:14)
+#define CRT_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH 0
+#define CRT_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW 1
+#define CRT_DISPLAY_CTRL_VSYNC_PHASE F(13:13)
+#define CRT_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH 0
+#define CRT_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW 1
+#define CRT_DISPLAY_CTRL_HSYNC_PHASE F(12:12)
+#define CRT_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH 0
+#define CRT_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW 1
+#define CRT_DISPLAY_CTRL_BLANK F(10:10)
+#define CRT_DISPLAY_CTRL_BLANK_OFF 0
+#define CRT_DISPLAY_CTRL_BLANK_ON 1
+#define CRT_DISPLAY_CTRL_TIMING F(8:8)
+#define CRT_DISPLAY_CTRL_TIMING_DISABLE 0
+#define CRT_DISPLAY_CTRL_TIMING_ENABLE 1
+#define CRT_DISPLAY_CTRL_PLANE F(2:2)
+#define CRT_DISPLAY_CTRL_PLANE_DISABLE 0
+#define CRT_DISPLAY_CTRL_PLANE_ENABLE 1
+#define CRT_DISPLAY_CTRL_FORMAT F(1:0)
+#define CRT_DISPLAY_CTRL_FORMAT_8 0
+#define CRT_DISPLAY_CTRL_FORMAT_16 1
+#define CRT_DISPLAY_CTRL_FORMAT_32 2
+#define CRT_DISPLAY_CTRL_RESERVED_BITS_MASK 0xFF000200
+
+#define CRT_FB_ADDRESS 0x080204
+#define CRT_FB_ADDRESS_STATUS F(31:31)
+#define CRT_FB_ADDRESS_STATUS_CURRENT 0
+#define CRT_FB_ADDRESS_STATUS_PENDING 1
+#define CRT_FB_ADDRESS_EXT F(27:27)
+#define CRT_FB_ADDRESS_EXT_LOCAL 0
+#define CRT_FB_ADDRESS_EXT_EXTERNAL 1
+#define CRT_FB_ADDRESS_ADDRESS F(25:0)
+
+#define CRT_FB_WIDTH 0x080208
+#define CRT_FB_WIDTH_WIDTH F(29:16)
+#define CRT_FB_WIDTH_OFFSET F(13:0)
+
+#define CRT_HORIZONTAL_TOTAL 0x08020C
+#define CRT_HORIZONTAL_TOTAL_TOTAL F(27:16)
+#define CRT_HORIZONTAL_TOTAL_DISPLAY_END F(11:0)
+
+#define CRT_HORIZONTAL_SYNC 0x080210
+#define CRT_HORIZONTAL_SYNC_WIDTH F(23:16)
+#define CRT_HORIZONTAL_SYNC_START F(11:0)
+
+#define CRT_VERTICAL_TOTAL 0x080214
+#define CRT_VERTICAL_TOTAL_TOTAL F(26:16)
+#define CRT_VERTICAL_TOTAL_DISPLAY_END F(10:0)
+
+#define CRT_VERTICAL_SYNC 0x080218
+#define CRT_VERTICAL_SYNC_HEIGHT F(21:16)
+#define CRT_VERTICAL_SYNC_START F(10:0)
+
+/* Auto Centering */
+#define CRT_AUTO_CENTERING_TL 0x080280
+#define CRT_AUTO_CENTERING_TL_TOP F(26:16)
+#define CRT_AUTO_CENTERING_TL_LEFT F(10:0)
+
+#define CRT_AUTO_CENTERING_BR 0x080284
+#define CRT_AUTO_CENTERING_BR_BOTTOM F(26:16)
+#define CRT_AUTO_CENTERING_BR_RIGHT F(10:0)
+
+/* register to control panel output */
+#define DISPLAY_CONTROL_HISILE 0x80288
+
+
+/* register and values for PLL control */
+#define CRT_PLL1_HS 0x802a8
+#define CRT_PLL1_HS_25MHZ 0x23d40f02
+#define CRT_PLL1_HS_40MHZ 0x23940801
+#define CRT_PLL1_HS_65MHZ 0x23940d01
+#define CRT_PLL1_HS_78MHZ 0x23540F82
+#define CRT_PLL1_HS_74MHZ 0x23941dc2
+#define CRT_PLL1_HS_80MHZ 0x23941001
+#define CRT_PLL1_HS_80MHZ_1152 0x23540fc2
+#define CRT_PLL1_HS_108MHZ 0x23b41b01
+#define CRT_PLL1_HS_162MHZ 0x23480681
+#define CRT_PLL1_HS_148MHZ 0x23541dc2
+#define CRT_PLL1_HS_193MHZ 0x234807c1
+
+#define CRT_PLL2_HS 0x802ac
+#define CRT_PLL2_HS_25MHZ 0x206B851E
+#define CRT_PLL2_HS_40MHZ 0x30000000
+#define CRT_PLL2_HS_65MHZ 0x40000000
+#define CRT_PLL2_HS_78MHZ 0x50E147AE
+#define CRT_PLL2_HS_74MHZ 0x602B6AE7
+#define CRT_PLL2_HS_80MHZ 0x70000000
+#define CRT_PLL2_HS_108MHZ 0x80000000
+#define CRT_PLL2_HS_162MHZ 0xA0000000
+#define CRT_PLL2_HS_148MHZ 0xB0CCCCCD
+#define CRT_PLL2_HS_193MHZ 0xC0872B02
+
+/* Palette RAM */
+
+/* Panel Palette register starts at 0x080400 ~ 0x0807FC */
+#define PANEL_PALETTE_RAM 0x080400
+
+/* Panel Palette register starts at 0x080C00 ~ 0x080FFC */
+#define CRT_PALETTE_RAM 0x080C00
+
+#define DMA_ABORT_INTERRUPT 0x0D0020
+#define DMA_ABORT_INTERRUPT_ABORT_1 F(5:5)
+#define DMA_ABORT_INTERRUPT_ABORT_1_ENABLE 0
+#define DMA_ABORT_INTERRUPT_ABORT_1_ABORT 1
+
+/* cursor control */
+#define HWC_ADDRESS 0x0
+#define HWC_ADDRESS_ENABLE F(31:31)
+#define HWC_ADDRESS_ENABLE_DISABLE 0
+#define HWC_ADDRESS_ENABLE_ENABLE 1
+#define HWC_ADDRESS_EXT F(27:27)
+#define HWC_ADDRESS_EXT_LOCAL 0
+#define HWC_ADDRESS_EXT_EXTERNAL 1
+#define HWC_ADDRESS_CS F(26:26)
+#define HWC_ADDRESS_CS_0 0
+#define HWC_ADDRESS_CS_1 1
+#define HWC_ADDRESS_ADDRESS F(25:0)
+
+#define HWC_LOCATION 0x4
+#define HWC_LOCATION_Y F(26:16)
+#define HWC_LOCATION_LEFT F(11:11)
+#define HWC_LOCATION_LEFT_INSIDE 0
+#define HWC_LOCATION_LEFT_OUTSIDE 1
+#define HWC_LOCATION_X F(10:0)
+
+#define HWC_COLOR_12 0x8
+
+#define HWC_COLOR_3 0xC
+
+/* accelate 2d graphic */
+#define DE_SOURCE 0x0
+#define DE_SOURCE_WRAP F(31:31)
+#define DE_SOURCE_WRAP_DISABLE 0
+#define DE_SOURCE_WRAP_ENABLE 1
+#define DE_SOURCE_X_K1 F(29:16)
+#define DE_SOURCE_Y_K2 F(15:0)
+#define DE_SOURCE_X_K1_MONO F(20:16)
+
+#define DE_DESTINATION 0x4
+#define DE_DESTINATION_WRAP F(31:31)
+#define DE_DESTINATION_WRAP_DISABLE 0
+#define DE_DESTINATION_WRAP_ENABLE 1
+#define DE_DESTINATION_X F(28:16)
+#define DE_DESTINATION_Y F(15:0)
+
+#define DE_DIMENSION 0x8
+#define DE_DIMENSION_X F(28:16)
+#define DE_DIMENSION_Y_ET F(15:0)
+
+#define DE_CONTROL 0xC
+#define DE_CONTROL_STATUS F(31:31)
+#define DE_CONTROL_STATUS_STOP 0
+#define DE_CONTROL_STATUS_START 1
+#define DE_CONTROL_PATTERN F(30:30)
+#define DE_CONTROL_PATTERN_MONO 0
+#define DE_CONTROL_PATTERN_COLOR 1
+#define DE_CONTROL_UPDATE_DESTINATION_X F(29:29)
+#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
+#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1
+#define DE_CONTROL_QUICK_START F(28:28)
+#define DE_CONTROL_QUICK_START_DISABLE 0
+#define DE_CONTROL_QUICK_START_ENABLE 1
+#define DE_CONTROL_DIRECTION F(27:27)
+#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0
+#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1
+#define DE_CONTROL_MAJOR F(26:26)
+#define DE_CONTROL_MAJOR_X 0
+#define DE_CONTROL_MAJOR_Y 1
+#define DE_CONTROL_STEP_X F(25:25)
+#define DE_CONTROL_STEP_X_POSITIVE 1
+#define DE_CONTROL_STEP_X_NEGATIVE 0
+#define DE_CONTROL_STEP_Y F(24:24)
+#define DE_CONTROL_STEP_Y_POSITIVE 1
+#define DE_CONTROL_STEP_Y_NEGATIVE 0
+#define DE_CONTROL_STRETCH F(23:23)
+#define DE_CONTROL_STRETCH_DISABLE 0
+#define DE_CONTROL_STRETCH_ENABLE 1
+#define DE_CONTROL_HOST F(22:22)
+#define DE_CONTROL_HOST_COLOR 0
+#define DE_CONTROL_HOST_MONO 1
+#define DE_CONTROL_LAST_PIXEL F(21:21)
+#define DE_CONTROL_LAST_PIXEL_OFF 0
+#define DE_CONTROL_LAST_PIXEL_ON 1
+#define DE_CONTROL_COMMAND F(20:16)
+#define DE_CONTROL_COMMAND_BITBLT 0
+#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1
+#define DE_CONTROL_COMMAND_DE_TILE 2
+#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3
+#define DE_CONTROL_COMMAND_ALPHA_BLEND 4
+#define DE_CONTROL_COMMAND_RLE_STRIP 5
+#define DE_CONTROL_COMMAND_SHORT_STROKE 6
+#define DE_CONTROL_COMMAND_LINE_DRAW 7
+#define DE_CONTROL_COMMAND_HOST_WRITE 8
+#define DE_CONTROL_COMMAND_HOST_READ 9
+#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
+#define DE_CONTROL_COMMAND_ROTATE 11
+#define DE_CONTROL_COMMAND_FONT 12
+#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15
+#define DE_CONTROL_ROP_SELECT F(15:15)
+#define DE_CONTROL_ROP_SELECT_ROP3 0
+#define DE_CONTROL_ROP_SELECT_ROP2 1
+#define DE_CONTROL_ROP2_SOURCE F(14:14)
+#define DE_CONTROL_ROP2_SOURCE_BITMAP 0
+#define DE_CONTROL_ROP2_SOURCE_PATTERN 1
+#define DE_CONTROL_MONO_DATA F(13:12)
+#define DE_CONTROL_MONO_DATA_NOT_PACKED 0
+#define DE_CONTROL_MONO_DATA_8_PACKED 1
+#define DE_CONTROL_MONO_DATA_16_PACKED 2
+#define DE_CONTROL_MONO_DATA_32_PACKED 3
+#define DE_CONTROL_REPEAT_ROTATE F(11:11)
+#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0
+#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1
+#define DE_CONTROL_TRANSPARENCY_MATCH F(10:10)
+#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0
+#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1
+#define DE_CONTROL_TRANSPARENCY_SELECT F(9:9)
+#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0
+#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1
+#define DE_CONTROL_TRANSPARENCY F(8:8)
+#define DE_CONTROL_TRANSPARENCY_DISABLE 0
+#define DE_CONTROL_TRANSPARENCY_ENABLE 1
+#define DE_CONTROL_ROP F(7:0)
+
+/* Pseudo fields. */
+
+#define DE_CONTROL_SHORT_STROKE_DIR F(27:24)
+#define DE_CONTROL_SHORT_STROKE_DIR_225 0
+#define DE_CONTROL_SHORT_STROKE_DIR_135 1
+#define DE_CONTROL_SHORT_STROKE_DIR_315 2
+#define DE_CONTROL_SHORT_STROKE_DIR_45 3
+#define DE_CONTROL_SHORT_STROKE_DIR_270 4
+#define DE_CONTROL_SHORT_STROKE_DIR_90 5
+#define DE_CONTROL_SHORT_STROKE_DIR_180 8
+#define DE_CONTROL_SHORT_STROKE_DIR_0 10
+#define DE_CONTROL_ROTATION F(25:24)
+#define DE_CONTROL_ROTATION_0 0
+#define DE_CONTROL_ROTATION_270 1
+#define DE_CONTROL_ROTATION_90 2
+#define DE_CONTROL_ROTATION_180 3
+
+#define DE_PITCH 0x000010
+#define DE_PITCH_DESTINATION F(28:16)
+#define DE_PITCH_SOURCE F(12:0)
+
+#define DE_FOREGROUND 0x000014
+
+#define DE_BACKGROUND 0x000018
+
+#define DE_STRETCH_FORMAT 0x00001C
+#define DE_STRETCH_FORMAT_PATTERN_XY F(30:30)
+#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0
+#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1
+#define DE_STRETCH_FORMAT_PATTERN_Y F(29:27)
+#define DE_STRETCH_FORMAT_PATTERN_X F(25:23)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT F(21:20)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3
+
+#define DE_STRETCH_FORMAT_ADDRESSING F(19:16)
+#define DE_STRETCH_FORMAT_ADDRESSING_XY 0
+#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15
+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT F(11:0)
+
+#define DE_COLOR_COMPARE 0x000020
+
+#define DE_COLOR_COMPARE_MASK 0x000024
+
+#define DE_MASKS 0x000028
+
+#define DE_CLIP_TL 0x00002C
+
+#define DE_CLIP_BR 0x000030
+
+#define DE_WINDOW_WIDTH 0x00003C
+#define DE_WINDOW_WIDTH_DESTINATION F(28:16)
+#define DE_WINDOW_WIDTH_SOURCE F(12:0)
+
+#define DE_WINDOW_SOURCE_BASE 0x000040
+#define DE_WINDOW_SOURCE_BASE_EXT F(27:27)
+#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0
+#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1
+#define DE_WINDOW_SOURCE_BASE_CS F(26:26)
+#define DE_WINDOW_SOURCE_BASE_CS_0 0
+#define DE_WINDOW_SOURCE_BASE_CS_1 1
+#define DE_WINDOW_SOURCE_BASE_ADDRESS F(25:0)
+
+#define DE_WINDOW_DESTINATION_BASE 0x000044
+#define DE_WINDOW_DESTINATION_BASE_EXT F(27:27)
+#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0
+#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1
+#define DE_WINDOW_DESTINATION_BASE_CS F(26:26)
+#define DE_WINDOW_DESTINATION_BASE_CS_0 0
+#define DE_WINDOW_DESTINATION_BASE_CS_1 1
+#define DE_WINDOW_DESTINATION_BASE_ADDRESS F(25:0)
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH 2/3] Hisilicon graphic driver: add hardware cursor support to hisilicon hi1710 graphi chip
From: Rongrong Zou @ 2015-11-03 13:54 UTC (permalink / raw)
To: linux-fbdev
From: Rongrong Zou <zourongrong@huawei.com>
This patch implements hardware cursor.
Signed-off-by: Rongrong Zou <zourongrong@huawei.com>
---
drivers/video/fbdev/hisilicon/Makefile | 2 +-
drivers/video/fbdev/hisilicon/hisi_cursor.c | 121 ++++++++++++++++++++++++++++
drivers/video/fbdev/hisilicon/hisi_cursor.h | 11 +++
drivers/video/fbdev/hisilicon/hisi_drv.c | 88 ++++++++++++++++++++
4 files changed, 221 insertions(+), 1 deletion(-)
create mode 100644 drivers/video/fbdev/hisilicon/hisi_cursor.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_cursor.h
diff --git a/drivers/video/fbdev/hisilicon/Makefile b/drivers/video/fbdev/hisilicon/Makefile
index 540b6d2..5f478ed 100644
--- a/drivers/video/fbdev/hisilicon/Makefile
+++ b/drivers/video/fbdev/hisilicon/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_FB_HISILICON) += hisiliconfb.o
-hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_chip.o
+hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_cursor.o hisi_chip.o
hisiliconfb-y += hisi_mode.o hisi_power.o
hisiliconfb-objs := $(hisiliconfb-y)
diff --git a/drivers/video/fbdev/hisilicon/hisi_cursor.c b/drivers/video/fbdev/hisilicon/hisi_cursor.c
new file mode 100644
index 0000000..84b0156
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_cursor.c
@@ -0,0 +1,121 @@
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include "hisi_drv.h"
+#include "hisi_cursor.h"
+#include "hisi_help.h"
+#include "hisi_reg.h"
+
+
+#define WRITE_REG(addr, data) writel((data), cursor->mmio + (addr))
+
+
+void hw_cursor_enable(struct hisi_cursor *cursor)
+{
+ u32 reg;
+
+ reg = FIELD_VALUE(0, HWC_ADDRESS, ADDRESS, cursor->offset) |
+ FIELD_SET(0, HWC_ADDRESS, EXT, LOCAL) |
+ FIELD_SET(0, HWC_ADDRESS, ENABLE, ENABLE);
+ WRITE_REG(HWC_ADDRESS, reg);
+}
+
+void hw_cursor_disable(struct hisi_cursor *cursor)
+{
+ WRITE_REG(HWC_ADDRESS, 0);
+}
+
+void hw_cursor_set_size(struct hisi_cursor *cursor, int w, int h)
+{
+ cursor->w = w;
+ cursor->h = h;
+}
+
+void hw_cursor_set_pos(struct hisi_cursor *cursor, int x, int y)
+{
+ u32 reg;
+
+ reg = FIELD_VALUE(0, HWC_LOCATION, Y, y) |
+ FIELD_VALUE(0, HWC_LOCATION, X, x);
+ WRITE_REG(HWC_LOCATION, reg);
+}
+
+void hw_cursor_set_color(struct hisi_cursor *cursor, u32 fg, u32 bg)
+{
+ WRITE_REG(HWC_COLOR_12, (fg << 16)|(bg & 0xffff));
+ WRITE_REG(HWC_COLOR_3, 0xffe0);
+}
+
+void hw_cursor_set_data(struct hisi_cursor *cursor,
+ u16 rop, const u8 *pcol, const u8 *pmsk)
+{
+ struct hisifb_crtc *crtc;
+
+ int i, j, count, pitch, offset;
+ u8 color, mask, opr;
+ u16 data;
+ u16 *pbuffer, *pstart;
+
+ crtc = container_of(cursor, struct hisifb_crtc, cursor);
+ /* in byte*/
+ pitch = cursor->w >> 3;
+
+ /* in byte */
+ count = pitch * cursor->h;
+
+ /* in ushort */
+ offset = cursor->maxW * 2 / 8 / 2;
+
+ data = 0;
+ pstart = (u16 *)cursor->vstart;
+ pbuffer = pstart;
+
+
+ for (i = 0; i < count; i++) {
+ color = *pcol++;
+ mask = *pmsk++;
+ data = 0;
+
+ /* either method below works well,
+ * but method 2 shows no lag
+ * and method 1 seems a bit wrong
+ */
+
+ for (j = 0; j < 8; j++) {
+ if (mask & (0x80 >> j)) {
+ if (rop = ROP_XOR)
+ opr = mask ^ color;
+ else
+ opr = mask & color;
+
+ /* 2 stands for forecolor and 1 for backcolor */
+ data |= ((opr & (0x80 >> j)) ? 2 : 1) <<
+ (j * 2);
+ }
+ }
+
+ *pbuffer = data;
+
+ /* assume pitch is 1,2,4,8,...*/
+ if ((i+1) % pitch = 0) {
+ /* need a return */
+ pstart += offset;
+ pbuffer = pstart;
+ } else {
+ pbuffer++;
+ }
+ }
+}
diff --git a/drivers/video/fbdev/hisilicon/hisi_cursor.h b/drivers/video/fbdev/hisilicon/hisi_cursor.h
new file mode 100644
index 0000000..551b743
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_cursor.h
@@ -0,0 +1,11 @@
+#ifndef HISI_CURSOR_H__
+#define HISI_CURSOR_H__
+
+void hw_cursor_enable(struct hisi_cursor *cursor);
+void hw_cursor_disable(struct hisi_cursor *cursor);
+void hw_cursor_set_size(struct hisi_cursor *cursor, int w, int h);
+void hw_cursor_set_pos(struct hisi_cursor *cursor, int x, int y);
+void hw_cursor_set_color(struct hisi_cursor *cursor, u32 fg, u32 bg);
+void hw_cursor_set_data(struct hisi_cursor *cursor, u16 rop,
+ const u8 *data, const u8 *mask);
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_drv.c b/drivers/video/fbdev/hisilicon/hisi_drv.c
index 521a279..54231d3 100644
--- a/drivers/video/fbdev/hisilicon/hisi_drv.c
+++ b/drivers/video/fbdev/hisilicon/hisi_drv.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "hisi_drv.h"
+#include "hisi_cursor.h"
#include "hisi_hw.h"
@@ -37,6 +38,7 @@ static int hisifb_ops_set_par(struct fb_info *);
static int hisifb_ops_setcolreg(unsigned, unsigned, unsigned,
unsigned, unsigned, struct fb_info *);
static int hisifb_ops_blank(int, struct fb_info *);
+static int hisifb_ops_cursor(struct fb_info *, struct fb_cursor *);
typedef void (*PROC_SPEC_SETUP)(struct hisi_share *, char *);
typedef int (*PROC_SPEC_MAP)(struct hisi_share *, struct pci_dev *);
@@ -128,6 +130,63 @@ static struct pci_driver hisifb_driver = {
#endif
};
+static int hisifb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
+{
+ struct hisifb_par *par;
+ struct hisifb_crtc *crtc;
+ struct hisi_cursor *cursor;
+
+ par = info->par;
+ crtc = &par->crtc;
+ cursor = &crtc->cursor;
+
+ if (fbcursor->image.width > cursor->maxW ||
+ fbcursor->image.height > cursor->maxH ||
+ fbcursor->image.depth > 1){
+ return -ENXIO;
+ }
+
+ cursor->disable(cursor);
+ if (fbcursor->set & FB_CUR_SETSIZE)
+ cursor->set_size(cursor, fbcursor->image.width,
+ fbcursor->image.height);
+
+
+ if (fbcursor->set & FB_CUR_SETPOS)
+ cursor->set_pos(cursor, fbcursor->image.dx - info->var.xoffset,
+ fbcursor->image.dy - info->var.yoffset);
+
+ if (fbcursor->set & FB_CUR_SETCMAP) {
+ /* get the 16bit color of kernel means */
+ u16 fg, bg;
+
+ fg + ((info->cmap.red[fbcursor->image.fg_color] & 0xf800)) |
+ ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5)|
+ ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11);
+
+ bg + ((info->cmap.red[fbcursor->image.bg_color] & 0xf800))|
+ ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5)|
+ ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11);
+
+ cursor->set_color(cursor, fg, bg);
+ }
+
+
+ if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+ cursor->set_data(cursor,
+ fbcursor->rop,
+ fbcursor->image.data,
+ fbcursor->mask);
+ }
+
+ if (fbcursor->enable)
+ cursor->enable(cursor);
+
+ return 0;
+}
+
static struct fb_ops hisifb_ops = {
.owner = THIS_MODULE,
.fb_check_var = hisifb_ops_check_var,
@@ -138,6 +197,8 @@ static struct fb_ops hisifb_ops = {
.fb_fillrect = cfb_fillrect,
.fb_imageblit = cfb_imageblit,
.fb_copyarea = cfb_copyarea,
+ /* cursor */
+ .fb_cursor = hisifb_ops_cursor,
};
#ifdef CONFIG_PM
@@ -621,6 +682,33 @@ static int hisifb_set_fbinfo(struct fb_info *info, int index)
output->channel = &crtc->channel;
hisifb_set_drv(par);
+ /*
+ * Set current cursor variable and proc pointer,
+ * must be set after crtc member initialized.
+ */
+ crtc->cursor.offset = crtc->oscreen +
+ crtc->vidmem_size - 1024;
+ crtc->cursor.mmio = share->pvreg + 0x800f0 +
+ (int)crtc->channel * 0x140;
+
+ inf_msg("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
+ crtc->cursor.maxH = crtc->cursor.maxW = 64;
+ crtc->cursor.size = crtc->cursor.maxH *
+ crtc->cursor.maxW * 2 / 8;
+ crtc->cursor.disable = hw_cursor_disable;
+ crtc->cursor.enable = hw_cursor_enable;
+ crtc->cursor.set_color = hw_cursor_set_color;
+ crtc->cursor.set_pos = hw_cursor_set_pos;
+ crtc->cursor.set_size = hw_cursor_set_size;
+ crtc->cursor.set_data = hw_cursor_set_data;
+ crtc->cursor.vstart = crtc->vscreen + crtc->cursor.offset;
+
+ crtc->cursor.share = share;
+ if (!g_hwcursor) {
+ hisifb_ops.fb_cursor = NULL;
+ crtc->cursor.disable(&crtc->cursor);
+ }
+
/* set info->fbops, must be set before fb_find_mode */
info->fbops = &hisifb_ops;
--
1.9.1
^ permalink raw reply related
* [PATCH 3/3] Hisilicon graphic driver: add 2d acceleration to hisilicon hi1710 graphic chip
From: Rongrong Zou @ 2015-11-03 13:54 UTC (permalink / raw)
To: linux-fbdev
From: Rongrong Zou <zourongrong@huawei.com>
This patch implements 2d acceleration.
Signed-off-by: Rongrong Zou <zourongrong@huawei.com>
---
drivers/video/fbdev/hisilicon/Makefile | 2 +-
drivers/video/fbdev/hisilicon/hisi_accel.c | 382 +++++++++++++++++++++++++++++
drivers/video/fbdev/hisilicon/hisi_accel.h | 62 +++++
drivers/video/fbdev/hisilicon/hisi_drv.c | 122 ++++++++-
drivers/video/fbdev/hisilicon/hisi_hw.c | 23 +-
5 files changed, 588 insertions(+), 3 deletions(-)
create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.c
create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.h
diff --git a/drivers/video/fbdev/hisilicon/Makefile b/drivers/video/fbdev/hisilicon/Makefile
index 5f478ed..1675edb 100644
--- a/drivers/video/fbdev/hisilicon/Makefile
+++ b/drivers/video/fbdev/hisilicon/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_FB_HISILICON) += hisiliconfb.o
-hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_cursor.o hisi_chip.o
+hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_accel.o hisi_cursor.o hisi_chip.o
hisiliconfb-y += hisi_mode.o hisi_power.o
hisiliconfb-objs := $(hisiliconfb-y)
diff --git a/drivers/video/fbdev/hisilicon/hisi_accel.c b/drivers/video/fbdev/hisilicon/hisi_accel.c
new file mode 100644
index 0000000..3666995
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_accel.c
@@ -0,0 +1,382 @@
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include "hisi_drv.h"
+#include "hisi_accel.h"
+#include "hisi_help.h"
+#include "hisi_reg.h"
+
+static inline void write_dpr(struct hisi_accel *accel, int offset, u32 value)
+{
+ writel(value, accel->dpr_base + offset);
+}
+
+static inline u32 read_dpr(struct hisi_accel *accel, int offset)
+{
+ return readl(accel->dpr_base + offset);
+}
+
+static inline void write_dpport(struct hisi_accel *accel, u32 data)
+{
+ writel(data, accel->dp_port_base);
+}
+
+int hw_de_init(struct hisi_accel *accel)
+{
+ /* setup 2d engine registers */
+ u32 reg;
+ u32 clr;
+
+ write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
+ /* dpr1c */
+ reg = FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0) |
+ FIELD_SET(0, DE_STRETCH_FORMAT, ADDRESSING, XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT, 3);
+
+ clr = FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_XY) &
+ FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_Y) &
+ FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_X) &
+ FIELD_CLEAR(DE_STRETCH_FORMAT, ADDRESSING) &
+ FIELD_CLEAR(DE_STRETCH_FORMAT, SOURCE_HEIGHT);
+
+ /* DE_STRETCH bpp format need be initilized in setMode routine */
+ write_dpr(accel, DE_STRETCH_FORMAT,
+ (read_dpr(accel, DE_STRETCH_FORMAT) & clr) | reg);
+
+ /* disable clipping and transparent */
+ write_dpr(accel, DE_CLIP_TL, 0);/*dpr2c*/
+ write_dpr(accel, DE_CLIP_BR, 0);/*dpr30*/
+
+ write_dpr(accel, DE_COLOR_COMPARE_MASK, 0);/*dpr24*/
+ write_dpr(accel, DE_COLOR_COMPARE, 0);
+
+ reg = FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE) |
+ FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE) |
+ FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE);
+
+ clr = FIELD_CLEAR(DE_CONTROL, TRANSPARENCY) &
+ FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH) &
+ FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT);
+
+ /* dpr0c */
+ write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL) & clr) | reg);
+
+ return 0;
+}
+
+/* set2dformat only be called from setmode functions
+ * but if you need dual framebuffer driver,need call set2dformat
+ * every time you use 2d function
+ */
+void hw_set_2dformat(struct hisi_accel *accel, int fmt)
+{
+ u32 reg;
+ /* fmt=0,1,2 for 8,16,32 */
+ reg = read_dpr(accel, DE_STRETCH_FORMAT);
+ reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt);
+ write_dpr(accel, DE_STRETCH_FORMAT, reg);
+}
+
+int hw_fillrect(
+ struct hisi_accel *accel, u32 base,
+ u32 pitch, u32 Bpp,
+ u32 x, u32 y, u32 width,
+ u32 height, u32 color, u32 rop)
+{
+ u32 deCtrl;
+
+ if (accel->de_wait() != 0) {
+ /* int time wait and always busy,seems hardware
+ * got something error
+ */
+ dbg_msg("%s:De engine always bussy\n", __func__);
+ return -1;
+ }
+
+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base);/*dpr40*/
+ write_dpr(accel, DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, pitch / Bpp) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, pitch/Bpp));/*dpr10*/
+
+ write_dpr(accel, DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch / Bpp) |
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch / Bpp));
+
+ write_dpr(accel, DE_FOREGROUND, color);/*DPR14*/
+
+ write_dpr(accel, DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, x) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, y));/*dpr4*/
+
+ write_dpr(accel, DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));/*dpr8*/
+
+ deCtrl = FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, ON) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, rop);/*dpr0xc*/
+
+ write_dpr(accel, DE_CONTROL, deCtrl);
+
+ return 0;
+}
+
+int hw_copyarea(
+ struct hisi_accel *accel,
+ unsigned int sbase, /* Address of source: offset in frame buffer */
+ unsigned int spitch, /* Pitch value of source surface in BYTE */
+ unsigned int sx,
+ unsigned int sy, /* Starting coordinate of source surface */
+ /* Address of destination: offset in frame buffer */
+ unsigned int dbase,
+ unsigned int dpitch, /* Pitch value of destination surface in BYTE */
+ unsigned int bpp, /* Color depth of destination surface */
+ unsigned int dx,
+ unsigned int dy, /* Starting coordinate of destination surface */
+ unsigned int width,
+ unsigned int height,
+ unsigned int rop2)
+{
+ unsigned int direction;
+ unsigned int de_ctrl;
+ int opsign;
+
+ direction = LEFT_TO_RIGHT;
+ /* Direction of ROP2 operation:
+ * 1 = Left to Right, (-1) = Right to Left
+ */
+ opsign = 1;
+ de_ctrl = 0;
+
+ /* If source and destination are the same surface,
+ * need to check for overlay cases
+ */
+ if (sbase = dbase && spitch = dpitch) {
+ /* Determine direction of operation */
+ if (sy < dy) {
+ direction = BOTTOM_TO_TOP;
+ } else if (sy > dy) {
+ direction = TOP_TO_BOTTOM;
+ } else {
+ /* sy = dy */
+ if (sx <= dx) {
+ direction = RIGHT_TO_LEFT;
+ } else {
+ /* sx > dx */
+ direction = LEFT_TO_RIGHT;
+ }
+ }
+ }
+
+ if ((direction = BOTTOM_TO_TOP) || (direction = RIGHT_TO_LEFT)) {
+ sx += width - 1;
+ sy += height - 1;
+ dx += width - 1;
+ dy += height - 1;
+ opsign = (-1);
+ }
+
+ /* Note:
+ * DE_FOREGROUND are DE_BACKGROUND are don't care.
+ * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS
+ * are set by set deSetTransparency().
+ */
+
+ /* 2D Source Base.
+ * It is an address offset (128 bit aligned) from the beginning
+ * of frame buffer.
+ */
+ write_dpr(accel, DE_WINDOW_SOURCE_BASE, sbase); /* dpr40 */
+
+ /* 2D Destination Base.
+ * It is an address offset (128 bit aligned) from the beginning
+ * of frame buffer.
+ */
+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dbase); /* dpr44 */
+
+ write_dpr(accel, DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, (dpitch / bpp)) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, (spitch / bpp))); /* dpr10*/
+
+ /* Screen Window width in Pixels.
+ * 2D engine uses this value to calculate the linear address
+ * in frame buffer for a given point.
+ */
+ /* dpr3c */
+ write_dpr(accel, DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH,
+ DESTINATION, (dpitch / bpp)) |
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (spitch / bpp)));
+
+ if (accel->de_wait() != 0)
+ return -1;
+
+ write_dpr(accel, DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, sx) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */
+ write_dpr(accel, DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dx) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */
+ write_dpr(accel, DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+ ((direction = RIGHT_TO_LEFT) ?
+ FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
+ : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+ write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
+
+ return 0;
+}
+
+static unsigned int de_get_transparency(struct hisi_accel *accel)
+{
+ unsigned int de_ctrl;
+
+ de_ctrl = read_dpr(accel, DE_CONTROL);
+
+ de_ctrl &= FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+ return de_ctrl;
+}
+
+int hw_imageblit(
+ struct hisi_accel *accel,
+ /* pointer to start of source buffer in system memory */
+ const char *psrcbuf,
+ /* Pitch value (in bytes) of the source buffer,
+ * +ive means top down and -ive mean button up
+ */
+ u32 srcdelta,
+ /* Mono data can start at any bit in a byte,
+ * this value should be 0 to 7
+ */
+ u32 startbit,
+ u32 dbase, /* Address of destination: offset in frame buffer */
+ u32 dpitch, /* Pitch value of destination surface in BYTE */
+ u32 bytperpxl, /* Color depth of destination surface */
+ u32 dx,
+ u32 dy, /* Starting coordinate of destination surface */
+ u32 width,
+ u32 height, /* width and height of rectange in pixel value */
+ /* Foreground color (corresponding to a 1 in the monochrome data */
+ u32 fcolor,
+ /* Background color (corresponding to a 0 in the monochrome data */
+ u32 bcolor,
+ u32 rop2) /* ROP value */
+{
+ unsigned int bytes_per_scan;
+ unsigned int qbytes_per_scan;
+ unsigned int bytes_remain;
+ unsigned int de_ctrl = 0;
+ unsigned char ajRemain[4];
+ int i, j;
+
+ /* Just make sure the start bit is within legal range */
+ startbit &= 7;
+ bytes_per_scan = (width + startbit + 7) / 8;
+ qbytes_per_scan = bytes_per_scan & ~3;
+ bytes_remain = bytes_per_scan & 3;
+
+ if (accel->de_wait() != 0)
+ return -1;
+
+ /* 2D Source Base. Use 0 for HOST Blt.*/
+ write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
+
+ /* 2D Destination Base.
+ * It is an address offset (128 bit aligned)
+ * from the beginning of frame buffer.
+ */
+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dbase);
+ /* dpr10 */
+ write_dpr(accel, DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, dpitch / bytperpxl)|
+ FIELD_VALUE(0, DE_PITCH, SOURCE, dpitch / bytperpxl));
+
+ /* Screen Window width in Pixels.
+ * 2D engine uses this value to calculate
+ * the linear address in frame buffer
+ * for a given point.
+ */
+ write_dpr(accel, DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ (dpitch / bytperpxl)) |
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,
+ (dpitch / bytperpxl))
+ );
+
+ /* Note: For 2D Source in Host Write, only X_K1_MONO
+ * field is needed, and Y_K2 field is not used.For mono bitmap,
+ * use startBit for X_K1.
+ */
+ write_dpr(accel, DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startbit)); /* dpr00 */
+
+ write_dpr(accel, DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dx) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */
+
+ write_dpr(accel, DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
+
+ write_dpr(accel, DE_FOREGROUND, fcolor);
+ write_dpr(accel, DE_BACKGROUND, bcolor);
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+ FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+ write_dpr(accel, DE_CONTROL,
+ de_ctrl | de_get_transparency(accel));
+
+ /* Write MONO data (line by line) to 2D Engine data port */
+ for (i = 0; i < height; i++) {
+ /* For each line, send the data in chunks of 4 bytes */
+ for (j = 0; j < (qbytes_per_scan/4); j++)
+ write_dpport(accel,
+ *(unsigned int *)(psrcbuf + (j * 4)));
+
+ if (bytes_remain) {
+ memcpy(ajRemain, psrcbuf+qbytes_per_scan,
+ bytes_remain);
+ write_dpport(accel, *(unsigned int *)ajRemain);
+ }
+
+ psrcbuf += srcdelta;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/hisilicon/hisi_accel.h b/drivers/video/fbdev/hisilicon/hisi_accel.h
new file mode 100644
index 0000000..3393b2e
--- /dev/null
+++ b/drivers/video/fbdev/hisilicon/hisi_accel.h
@@ -0,0 +1,62 @@
+#ifndef HISI_ACCEL_H__
+#define HISI_ACCEL_H__
+
+#define HW_ROP2_COPY 0xc
+#define HW_ROP2_XOR 0x6
+
+
+/* blt direction */
+#define TOP_TO_BOTTOM 0
+#define LEFT_TO_RIGHT 0
+#define BOTTOM_TO_TOP 1
+#define RIGHT_TO_LEFT 1
+
+void hw_set_2dformat(struct hisi_accel *accel, int fmt);
+int hw_de_init(struct hisi_accel *accel);
+int hw_fillrect(struct hisi_accel *accel, u32 base, u32 pitch, u32 bpp,
+ u32 x, u32 y, u32 width, u32 height, u32 color, u32 rop);
+
+int hw_copyarea(
+ struct hisi_accel *accel,
+ unsigned int sbase, /* Address of source: offset in frame buffer */
+ unsigned int spitch, /* Pitch value of source surface in BYTE */
+ unsigned int sx,
+ unsigned int sy, /* Starting coordinate of source surface */
+ /* Address of destination: offset in frame buffer */
+ unsigned int dbase,
+ unsigned int dpitch, /* Pitch value of destination surface in BYTE */
+ unsigned int bpp, /* Color depth of destination surface */
+ unsigned int dx,
+ unsigned int dy, /* Starting coordinate of destination surface */
+ unsigned int width,
+ unsigned int height,
+ unsigned int rop2
+);
+
+int hw_imageblit(
+ struct hisi_accel *accel,
+ /* pointer to start of source buffer in system memory */
+ const char *psrcbuf,
+ /* Pitch value (in bytes) of the source buffer,
+ * +ive means top down and -ive mean button up
+ */
+ u32 srcdelta,
+ /* Mono data can start at any bit in a byte, this value
+ * should be 0 to 7
+ */
+ u32 startbit,
+ u32 dbase, /* Address of destination: offset in frame buffer */
+ u32 dpitch, /* Pitch value of destination surface in BYTE */
+ u32 byteperpixel, /* Color depth of destination surface */
+ u32 dx,
+ u32 dy, /* Starting coordinate of destination surface */
+ u32 width,
+ u32 height, /* width and height of rectange in pixel value */
+ /* Foreground color (corresponding to a 1 in the monochrome data */
+ u32 fcolor,
+ /* Background color (corresponding to a 0 in the monochrome data */
+ u32 bcolor,
+ u32 rop2
+);
+
+#endif
diff --git a/drivers/video/fbdev/hisilicon/hisi_drv.c b/drivers/video/fbdev/hisilicon/hisi_drv.c
index 54231d3..e16f942 100644
--- a/drivers/video/fbdev/hisilicon/hisi_drv.c
+++ b/drivers/video/fbdev/hisilicon/hisi_drv.c
@@ -20,6 +20,7 @@
#include "hisi_drv.h"
#include "hisi_cursor.h"
#include "hisi_hw.h"
+#include "hisi_accel.h"
/* chip specific setup routine */
@@ -187,6 +188,103 @@ static int hisifb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
return 0;
}
+static void hisifb_ops_fillrect(struct fb_info *info,
+ const struct fb_fillrect *region)
+{
+ struct hisifb_par *par;
+ struct hisi_share *share;
+ unsigned int base, pitch, Bpp, rop;
+ u32 color;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
+ par = info->par;
+ share = par->share;
+
+ /*
+ * each time 2d function begin to work,below three variable always need
+ * be set, seems we can put them together in some place
+ */
+ base = par->crtc.oscreen;
+ pitch = info->fix.line_length;
+ Bpp = info->var.bits_per_pixel >> 3;
+
+ color = (Bpp = 1) ? region->color :
+ ((u32 *)info->pseudo_palette)[region->color];
+ rop = (region->rop != ROP_COPY) ?
+ HW_ROP2_XOR : HW_ROP2_COPY;
+
+ share->accel.de_fillrect(&share->accel,
+ base, pitch, Bpp, region->dx,
+ region->dy, region->width,
+ region->height, color, rop);
+}
+
+static void hisifb_ops_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region)
+{
+ struct hisifb_par *par;
+ struct hisi_share *share;
+ unsigned int base, pitch, Bpp;
+
+ par = info->par;
+ share = par->share;
+
+ /*
+ * each time 2d function begin to work,below three variable always need
+ * be set, seems we can put them together in some place
+ */
+ base = par->crtc.oscreen;
+ pitch = info->fix.line_length;
+ Bpp = info->var.bits_per_pixel >> 3;
+
+ share->accel.de_copyarea(&share->accel, base, pitch,
+ region->sx, region->sy, base,
+ pitch, Bpp, region->dx, region->dy,
+ region->width, region->height,
+ HW_ROP2_COPY);
+}
+
+static void hisifb_ops_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ unsigned int base, pitch, Bpp;
+ unsigned int fgcol, bgcol;
+ struct hisifb_par *par;
+ struct hisi_share *share;
+
+ par = info->par;
+ share = par->share;
+ /*
+ * each time 2d function begin to work,below three variable always need
+ * be set, seems we can put them together in some place
+ */
+ base = par->crtc.oscreen;
+ pitch = info->fix.line_length;
+ Bpp = info->var.bits_per_pixel >> 3;
+
+ if (image->depth = 1) {
+ if (info->fix.visual = FB_VISUAL_TRUECOLOR ||
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR) {
+ fgcol = ((u32 *)info->pseudo_palette)[image->fg_color];
+ bgcol = ((u32 *)info->pseudo_palette)[image->bg_color];
+ } else {
+ fgcol = image->fg_color;
+ bgcol = image->bg_color;
+ }
+ goto _do_work;
+ }
+ return;
+_do_work:
+ share->accel.de_imageblit(&share->accel,
+ image->data, image->width >> 3, 0,
+ base, pitch, Bpp,
+ image->dx, image->dy,
+ image->width, image->height,
+ fgcol, bgcol, HW_ROP2_COPY);
+}
+
static struct fb_ops hisifb_ops = {
.owner = THIS_MODULE,
.fb_check_var = hisifb_ops_check_var,
@@ -710,7 +808,12 @@ static int hisifb_set_fbinfo(struct fb_info *info, int index)
}
/* set info->fbops, must be set before fb_find_mode */
-
+ if (!share->accel_off) {
+ /* use 2d acceleration */
+ hisifb_ops.fb_fillrect = hisifb_ops_fillrect;
+ hisifb_ops.fb_copyarea = hisifb_ops_copyarea;
+ hisifb_ops.fb_imageblit = hisifb_ops_imageblit;
+ }
info->fbops = &hisifb_ops;
if (!g_fbmode[index]) {
@@ -880,6 +983,23 @@ static int hisifb_pci_probe(struct pci_dev *pdev,
share->accel_off = g_noaccel;
share->dual = g_dualview;
+
+ if (!share->accel_off) {
+ /*
+ * hook deInit and 2d routines, notes that below hw_xxx
+ * routine can work on most of hisi chips,if some chip need
+ * specific function,please hook it in smXXX_set_drv
+ * routine
+ */
+ share->accel.de_init = hw_de_init;
+ share->accel.de_fillrect = hw_fillrect;
+ share->accel.de_copyarea = hw_copyarea;
+ share->accel.de_imageblit = hw_imageblit;
+ inf_msg("enable 2d acceleration\n");
+ } else {
+ inf_msg("disable 2d acceleration\n");
+ }
+
/* call chip specific setup routine */
hisi_fb_setup(share, g_settings);
diff --git a/drivers/video/fbdev/hisilicon/hisi_hw.c b/drivers/video/fbdev/hisilicon/hisi_hw.c
index e993f25..22fa166 100644
--- a/drivers/video/fbdev/hisilicon/hisi_hw.c
+++ b/drivers/video/fbdev/hisilicon/hisi_hw.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include "hisi_drv.h"
+#include "hisi_accel.h"
#include "hisi_help.h"
#include "hisi_hw.h"
#include "hisi_mode.h"
@@ -138,14 +139,34 @@ int hw_hisi_crtc_setmode(struct hisifb_crtc *crtc,
struct fb_var_screeninfo *var,
struct fb_fix_screeninfo *fix)
{
- int ret;
+ int ret, fmt;
u32 reg;
struct mode_para modparm;
enum clock_type clock;
+ struct hisi_share *share;
struct hisifb_par *par;
ret = 0;
par = container_of(crtc, struct hisifb_par, crtc);
+ share = par->share;
+
+ if (!share->accel_off) {
+ /* set 2d engine pixel format according to mode bpp */
+ switch (var->bits_per_pixel) {
+ case 8:
+ fmt = 0;
+ break;
+ case 16:
+ fmt = 1;
+ break;
+ case 32:
+ default:
+ fmt = 2;
+ break;
+ }
+ hw_set_2dformat(&share->accel, fmt);
+ }
+
/* set timing */
modparm.pixel_clock = ps_to_hz(var->pixclock);
modparm.vsync_polarity --
1.9.1
^ permalink raw reply related
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