* [PATCHv5 03/11] of: Add Solomon Systech vendor prefix.
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch adds the solomon prefix for Solomon Systech Limited.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index d3f4809..933c8f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -169,6 +169,7 @@ sitronix Sitronix Technology Corporation
smsc Standard Microsystems Corporation
snps Synopsys, Inc.
solidrun SolidRun
+solomon Solomon Systech Limited
sony Sony Corporation
spansion Spansion Inc.
sprd Spreadtrum Communications Inc.
--
2.3.0
^ permalink raw reply related
* [PATCHv5 04/11] fbdev: ssd1307fb: Unify init code and obtain hw specific bits from DT
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
The 130X controllers are very similar from the configuration point of view.
The configuration registers for the SSD1305/6/7 are bit identical (except the
the VHCOM register and the the default values for clock setup register). This
patch unifies the init code of the controller and adds hardware specific
properties to DT that are needed to correctly initialize the device.
The SSD130X can be wired to the OLED panel in various ways. Even for the
same controller this wiring can differ from one display module to another
and can not be probed by software. The added DT properties reflect these
hardware decisions of the display module manufacturer.
The 'com-sequential', 'com-lrremap' and 'com-invdir' values define different
possibilities for the COM signals pin configuration and readout direction
of the video memory. The 'segment-no-remap' allows the inversion of the
memory-to-pin mapping ultimately inverting the order of the controllers
output pins. The 'prechargepX' values need to be adapted according to the
capacitance of the OLEDs pixel cells.
So far these hardware specific bits are hard coded in the init code, making
the driver usable only for one certain wiring of the controller. This patch
makes the driver usable with all possible hardware setups, given a valid hw
description in DT. If these values are not set in DT the default values,
as they are set in the ssd1307 init code right now, are used. This implies
that without the corresponding DT property "segment-no-remap" the segment
remap of the ssd130X controller gets activated. Even though this is not the
default behaviour according to the datasheet it maintains backward
compatibility with older DTBs.
Note that the SSD1306 does not seem to be using the configuration written to
the registers at all. Therefore this patch does not try to maintain these
values without changes in DT. For reference an example is added to the DT
bindings documentation that reproduces the configuration that is set in the
current init code.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
.../devicetree/bindings/video/ssd1307fb.txt | 21 +++
drivers/video/fbdev/ssd1307fb.c | 192 ++++++++++++---------
2 files changed, 134 insertions(+), 79 deletions(-)
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
index 7a12542..637690f 100644
--- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
+++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
@@ -15,6 +15,16 @@ Required properties:
Optional properties:
- reset-active-low: Is the reset gpio is active on physical low?
+ - solomon,segment-no-remap: Display needs normal (non-inverted) data column
+ to segment mapping
+ - solomon,com-sequential: Display uses sequential COM pin configuration
+ - solomon,com-lrremap: Display uses left-right COM pin remap
+ - solomon,com-invdir: Display uses inverted COM pin scan direction
+ - solomon,com-offset: Number of the COM pin wired to the first display line
+ - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
+ - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
+ This needs to be the higher, the higher the capacitance
+ of the OLED's pixels is
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
@@ -26,3 +36,14 @@ ssd1307: oled@3c {
reset-gpios = <&gpio2 7>;
reset-active-low;
};
+
+ssd1306: oled@3c {
+ compatible = "solomon,ssd1306fb-i2c";
+ reg = <0x3c>;
+ pwms = <&pwm 4 3000>;
+ reset-gpios = <&gpio2 7>;
+ reset-active-low;
+ solomon,com-lrremap;
+ solomon,com-invdir;
+ solomon,com-offset = <32>;
+};
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 8d34c56..d16aad4 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -40,20 +40,34 @@
struct ssd1307fb_par;
-struct ssd1307fb_ops {
- int (*init)(struct ssd1307fb_par *);
- int (*remove)(struct ssd1307fb_par *);
+struct ssd1307fb_deviceinfo {
+ u32 default_vcomh;
+ u32 default_dclk_div;
+ u32 default_dclk_frq;
+ int need_pwm;
+ int need_chargepump;
};
struct ssd1307fb_par {
+ u32 com_invdir;
+ u32 com_lrremap;
+ u32 com_offset;
+ u32 com_seq;
+ u32 contrast;
+ u32 dclk_div;
+ u32 dclk_frq;
+ struct ssd1307fb_deviceinfo *device_info;
struct i2c_client *client;
u32 height;
struct fb_info *info;
- struct ssd1307fb_ops *ops;
u32 page_offset;
+ u32 prechargep1;
+ u32 prechargep2;
struct pwm_device *pwm;
u32 pwm_period;
int reset;
+ u32 seg_remap;
+ u32 vcomh;
u32 width;
};
@@ -254,69 +268,46 @@ static struct fb_deferred_io ssd1307fb_defio = {
.deferred_io = ssd1307fb_deferred_io,
};
-static int ssd1307fb_ssd1307_init(struct ssd1307fb_par *par)
+static int ssd1307fb_init(struct ssd1307fb_par *par)
{
int ret;
+ u32 precharge, dclk, com_invdir, compins;
- par->pwm = pwm_get(&par->client->dev, NULL);
- if (IS_ERR(par->pwm)) {
- dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
- return PTR_ERR(par->pwm);
- }
-
- par->pwm_period = pwm_get_period(par->pwm);
- /* Enable the PWM */
- pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
- pwm_enable(par->pwm);
-
- dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
- par->pwm->pwm, par->pwm_period);
-
- /* Map column 127 of the OLED to segment 0 */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
- if (ret < 0)
- return ret;
-
- /* Turn on the display */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int ssd1307fb_ssd1307_remove(struct ssd1307fb_par *par)
-{
- pwm_disable(par->pwm);
- pwm_put(par->pwm);
- return 0;
-}
+ if (par->device_info->need_pwm) {
+ par->pwm = pwm_get(&par->client->dev, NULL);
+ if (IS_ERR(par->pwm)) {
+ dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
+ return PTR_ERR(par->pwm);
+ }
-static struct ssd1307fb_ops ssd1307fb_ssd1307_ops = {
- .init = ssd1307fb_ssd1307_init,
- .remove = ssd1307fb_ssd1307_remove,
-};
+ par->pwm_period = pwm_get_period(par->pwm);
+ /* Enable the PWM */
+ pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
+ pwm_enable(par->pwm);
-static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
-{
- int ret;
+ dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
+ par->pwm->pwm, par->pwm_period);
+ };
/* Set initial contrast */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x7f);
- if (ret < 0)
- return ret;
-
- /* Set COM direction */
- ret = ssd1307fb_write_cmd(par->client, 0xc8);
+ ret = ssd1307fb_write_cmd(par->client, par->contrast);
if (ret < 0)
return ret;
/* Set segment re-map */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
+ if (par->seg_remap) {
+ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
+ if (ret < 0)
+ return ret;
+ };
+
+ /* Set COM direction */
+ com_invdir = 0xc0 | (par->com_invdir & 0xf) << 3;
+ ret = ssd1307fb_write_cmd(par->client, com_invdir);
if (ret < 0)
return ret;
@@ -334,7 +325,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x20);
+ ret = ssd1307fb_write_cmd(par->client, par->com_offset);
if (ret < 0)
return ret;
@@ -343,7 +334,8 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0xf0);
+ dclk = (par->dclk_div & 0xf) | (par->dclk_frq & 0xf) << 4;
+ ret = ssd1307fb_write_cmd(par->client, dclk);
if (ret < 0)
return ret;
@@ -352,7 +344,8 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x22);
+ precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
+ ret = ssd1307fb_write_cmd(par->client, precharge);
if (ret < 0)
return ret;
@@ -361,7 +354,9 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x22);
+ compins = 0x02 | (!par->com_seq & 0x1) << 4
+ | (par->com_lrremap & 0x1) << 5;
+ ret = ssd1307fb_write_cmd(par->client, compins);
if (ret < 0)
return ret;
@@ -370,18 +365,20 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x49);
+ ret = ssd1307fb_write_cmd(par->client, par->vcomh);
if (ret < 0)
return ret;
- /* Turn on the DC-DC Charge Pump */
- ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
- if (ret < 0)
- return ret;
+ if (par->device_info->need_chargepump) {
+ /* Turn on the DC-DC Charge Pump */
+ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
+ if (ret < 0)
+ return ret;
- ret = ssd1307fb_write_cmd(par->client, 0x14);
- if (ret < 0)
- return ret;
+ ret = ssd1307fb_write_cmd(par->client, 0x14);
+ if (ret < 0)
+ return ret;
+ };
/* Switch to horizontal addressing mode */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
@@ -393,6 +390,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
+ /* Set column range */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
if (ret < 0)
return ret;
@@ -405,6 +403,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
if (ret < 0)
return ret;
+ /* Set page range */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
if (ret < 0)
return ret;
@@ -426,18 +425,30 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
return 0;
}
-static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = {
- .init = ssd1307fb_ssd1306_init,
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
+ .default_vcomh = 0x20,
+ .default_dclk_div = 0,
+ .default_dclk_frq = 8,
+ .need_pwm = 0,
+ .need_chargepump = 1,
+};
+
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
+ .default_vcomh = 0x20,
+ .default_dclk_div = 1,
+ .default_dclk_frq = 12,
+ .need_pwm = 1,
+ .need_chargepump = 0,
};
static const struct of_device_id ssd1307fb_of_match[] = {
{
.compatible = "solomon,ssd1306fb-i2c",
- .data = (void *)&ssd1307fb_ssd1306_ops,
+ .data = (void *)&ssd1307fb_ssd1306_deviceinfo,
},
{
.compatible = "solomon,ssd1307fb-i2c",
- .data = (void *)&ssd1307fb_ssd1307_ops,
+ .data = (void *)&ssd1307fb_ssd1307_deviceinfo,
},
{},
};
@@ -468,8 +479,8 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->info = info;
par->client = client;
- par->ops = (struct ssd1307fb_ops *)of_match_device(ssd1307fb_of_match,
- &client->dev)->data;
+ par->device_info = (struct ssd1307fb_deviceinfo *)of_match_device(
+ ssd1307fb_of_match, &client->dev)->data;
par->reset = of_get_named_gpio(client->dev.of_node,
"reset-gpios", 0);
@@ -487,6 +498,27 @@ static int ssd1307fb_probe(struct i2c_client *client,
if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
par->page_offset = 1;
+ if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
+ par->com_offset = 0;
+
+ if (of_property_read_u32(node, "solomon,prechargep1", &par->prechargep1))
+ par->prechargep1 = 2;
+
+ if (of_property_read_u32(node, "solomon,prechargep2", &par->prechargep2))
+ par->prechargep2 = 0;
+
+ par->seg_remap = !of_property_read_bool(node, "solomon,segment-no-remap");
+ par->com_seq = of_property_read_bool(node, "solomon,com-sequential");
+ par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
+ par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
+
+ par->contrast = 127;
+ par->vcomh = par->device_info->default_vcomh;
+
+ /* Setup display timing */
+ par->dclk_div = par->device_info->default_dclk_div;
+ par->dclk_frq = par->device_info->default_dclk_frq;
+
vmem_size = par->width * par->height / 8;
vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
@@ -539,11 +571,9 @@ static int ssd1307fb_probe(struct i2c_client *client,
gpio_set_value(par->reset, 1);
udelay(4);
- if (par->ops->init) {
- ret = par->ops->init(par);
- if (ret)
- goto reset_oled_error;
- }
+ ret = ssd1307fb_init(par);
+ if (ret)
+ goto reset_oled_error;
ret = register_framebuffer(info);
if (ret) {
@@ -556,8 +586,10 @@ static int ssd1307fb_probe(struct i2c_client *client,
return 0;
panel_init_error:
- if (par->ops->remove)
- par->ops->remove(par);
+ if (par->device_info->need_pwm) {
+ pwm_disable(par->pwm);
+ pwm_put(par->pwm);
+ };
reset_oled_error:
fb_deferred_io_cleanup(info);
fb_alloc_error:
@@ -571,8 +603,10 @@ static int ssd1307fb_remove(struct i2c_client *client)
struct ssd1307fb_par *par = info->par;
unregister_framebuffer(info);
- if (par->ops->remove)
- par->ops->remove(par);
+ if (par->device_info->need_pwm) {
+ pwm_disable(par->pwm);
+ pwm_put(par->pwm);
+ };
fb_deferred_io_cleanup(info);
__free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len));
framebuffer_release(info);
--
2.3.0
^ permalink raw reply related
* [PATCHv5 05/11] ARM: mxs: fix in tree users of ssd1306
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch updates the in tree-users of the SSD1306 controller for using
the newly introduced DT properties.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
arch/arm/boot/dts/imx28-cfa10036.dts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/boot/dts/imx28-cfa10036.dts b/arch/arm/boot/dts/imx28-cfa10036.dts
index b04b6b8..570aa33 100644
--- a/arch/arm/boot/dts/imx28-cfa10036.dts
+++ b/arch/arm/boot/dts/imx28-cfa10036.dts
@@ -99,6 +99,9 @@
solomon,height = <32>;
solomon,width = <128>;
solomon,page-offset = <0>;
+ solomon,com-lrremap;
+ solomon,com-invdir;
+ solomon,com-offset = <32>;
};
};
--
2.3.0
^ permalink raw reply related
* [PATCHv5 06/11] fbdev: ssd1307fb: Add support for SSD1305
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch adds support for the SSD1305 OLED controller.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
Documentation/devicetree/bindings/video/ssd1307fb.txt | 2 +-
drivers/video/fbdev/ssd1307fb.c | 13 +++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
index 637690f..acdf1ae 100644
--- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
+++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
@@ -2,7 +2,7 @@
Required properties:
- compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
- now is i2c, and the supported chips are ssd1306 and ssd1307.
+ now is i2c, and the supported chips are ssd1305, ssd1306 and ssd1307.
- reg: Should contain address of the controller on the I2C bus. Most likely
0x3c or 0x3d
- pwm: Should contain the pwm to use according to the OF device tree PWM
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index d16aad4..284c527 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -425,6 +425,14 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return 0;
}
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
+ .default_vcomh = 0x34,
+ .default_dclk_div = 0,
+ .default_dclk_frq = 7,
+ .need_pwm = 0,
+ .need_chargepump = 0,
+};
+
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
.default_vcomh = 0x20,
.default_dclk_div = 0,
@@ -443,6 +451,10 @@ static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
static const struct of_device_id ssd1307fb_of_match[] = {
{
+ .compatible = "solomon,ssd1305fb-i2c",
+ .data = (void *)&ssd1307fb_ssd1305_deviceinfo,
+ },
+ {
.compatible = "solomon,ssd1306fb-i2c",
.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
},
@@ -615,6 +627,7 @@ static int ssd1307fb_remove(struct i2c_client *client)
}
static const struct i2c_device_id ssd1307fb_i2c_id[] = {
+ { "ssd1305fb", 0 },
{ "ssd1306fb", 0 },
{ "ssd1307fb", 0 },
{ }
--
2.3.0
^ permalink raw reply related
* [PATCHv5 07/11] fbdev: ssd1307fb: Add a module parameter to set the refresh rate
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch adds the module parameter "refreshrate" to set delay for the
deferred io. The refresh rate is given in units of Hertz. The default
refresh rate is 1 Hz. The refresh rate set through the newly introduced
parameter applies to all instances of the driver and for now it is not
possible to change it individually.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
drivers/video/fbdev/ssd1307fb.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 284c527..b38973e 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -38,6 +38,11 @@
#define SSD1307FB_SET_COM_PINS_CONFIG 0xda
#define SSD1307FB_SET_VCOMH 0xdb
+#define REFRESHRATE 1
+
+static u_int refreshrate = REFRESHRATE;
+module_param(refreshrate, uint, 0);
+
struct ssd1307fb_par;
struct ssd1307fb_deviceinfo {
@@ -263,11 +268,6 @@ static void ssd1307fb_deferred_io(struct fb_info *info,
ssd1307fb_update_display(info->par);
}
-static struct fb_deferred_io ssd1307fb_defio = {
- .delay = HZ,
- .deferred_io = ssd1307fb_deferred_io,
-};
-
static int ssd1307fb_init(struct ssd1307fb_par *par)
{
int ret;
@@ -471,6 +471,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
{
struct fb_info *info;
struct device_node *node = client->dev.of_node;
+ struct fb_deferred_io *ssd1307fb_defio;
u32 vmem_size;
struct ssd1307fb_par *par;
u8 *vmem;
@@ -541,10 +542,20 @@ static int ssd1307fb_probe(struct i2c_client *client,
goto fb_alloc_error;
}
+ ssd1307fb_defio = devm_kzalloc(&client->dev, sizeof(struct fb_deferred_io), GFP_KERNEL);
+ if (!ssd1307fb_defio) {
+ dev_err(&client->dev, "Couldn't allocate deferred io.\n");
+ ret = -ENOMEM;
+ goto fb_alloc_error;
+ }
+
+ ssd1307fb_defio->delay = HZ / refreshrate;
+ ssd1307fb_defio->deferred_io = ssd1307fb_deferred_io;
+
info->fbops = &ssd1307fb_ops;
info->fix = ssd1307fb_fix;
info->fix.line_length = par->width / 8;
- info->fbdefio = &ssd1307fb_defio;
+ info->fbdefio = ssd1307fb_defio;
info->var = ssd1307fb_var;
info->var.xres = par->width;
--
2.3.0
^ permalink raw reply related
* [PATCHv5 08/11] fbdev: ssd1307fb: Turn off display on driver unload.
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch turns off the display when the driver is unloaded.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/video/fbdev/ssd1307fb.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index b38973e..6149827 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -625,6 +625,8 @@ static int ssd1307fb_remove(struct i2c_client *client)
struct fb_info *info = i2c_get_clientdata(client);
struct ssd1307fb_par *par = info->par;
+ ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
+
unregister_framebuffer(info);
if (par->device_info->need_pwm) {
pwm_disable(par->pwm);
--
2.3.0
^ permalink raw reply related
* [PATCHv5 09/11] fbdev: ssd1307fb: Add module parameter to set the initial contrast
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch adds the module parameter "contrast" to determine the
contrast value that is used to initialize the display. This
setting applies to all instances of the driver.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
drivers/video/fbdev/ssd1307fb.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 6149827..d5aec5c 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -43,6 +43,9 @@
static u_int refreshrate = REFRESHRATE;
module_param(refreshrate, uint, 0);
+static u_int contrast = 127;
+module_param(contrast, uint, S_IRUGO);
+
struct ssd1307fb_par;
struct ssd1307fb_deviceinfo {
@@ -525,7 +528,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
- par->contrast = 127;
+ par->contrast = contrast;
par->vcomh = par->device_info->default_vcomh;
/* Setup display timing */
--
2.3.0
^ permalink raw reply related
* [PATCHv5 10/11] fbdev: ssd1307fb: add backlight controls for setting the contrast
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
The backlight class is used to create userspace handles for
setting the OLED contrast.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/video/fbdev/Kconfig | 1 +
drivers/video/fbdev/ssd1307fb.c | 58 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index b3dd417..da70bae 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2478,6 +2478,7 @@ config FB_SSD1307
select FB_SYS_IMAGEBLIT
select FB_DEFERRED_IO
select PWM
+ select FB_BACKLIGHT
help
This driver implements support for the Solomon SSD1307
OLED controller over I2C.
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index d5aec5c..061cc95 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -7,6 +7,7 @@
*/
#include <linux/module.h>
+#include <linux/backlight.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/fb.h>
@@ -38,6 +39,8 @@
#define SSD1307FB_SET_COM_PINS_CONFIG 0xda
#define SSD1307FB_SET_VCOMH 0xdb
+#define MAX_CONTRAST 255
+
#define REFRESHRATE 1
static u_int refreshrate = REFRESHRATE;
@@ -428,6 +431,43 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return 0;
}
+static int ssd1307fb_update_bl(struct backlight_device *bdev)
+{
+ struct ssd1307fb_par *par = bl_get_data(bdev);
+ int ret;
+ int brightness = bdev->props.brightness;
+
+ par->contrast = brightness;
+
+ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
+ if (ret < 0)
+ return ret;
+ ret = ssd1307fb_write_cmd(par->client, par->contrast);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int ssd1307fb_get_brightness(struct backlight_device *bdev)
+{
+ struct ssd1307fb_par *par = bl_get_data(bdev);
+
+ return par->contrast;
+}
+
+static int ssd1307fb_check_fb(struct backlight_device *bdev,
+ struct fb_info *info)
+{
+ return (info->bl_dev = bdev);
+}
+
+static const struct backlight_ops ssd1307fb_bl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = ssd1307fb_update_bl,
+ .get_brightness = ssd1307fb_get_brightness,
+ .check_fb = ssd1307fb_check_fb,
+};
+
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
.default_vcomh = 0x34,
.default_dclk_div = 0,
@@ -472,6 +512,8 @@ MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
static int ssd1307fb_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct backlight_device *bl;
+ char bl_name[12];
struct fb_info *info;
struct device_node *node = client->dev.of_node;
struct fb_deferred_io *ssd1307fb_defio;
@@ -607,10 +649,24 @@ static int ssd1307fb_probe(struct i2c_client *client,
goto panel_init_error;
}
+ snprintf(bl_name, sizeof(bl_name), "ssd1307fb%d", info->node);
+ bl = backlight_device_register(bl_name, &client->dev, par,
+ &ssd1307fb_bl_ops, NULL);
+ bl->props.brightness = contrast;
+ bl->props.max_brightness = MAX_CONTRAST;
+ info->bl_dev = bl;
+
+ if (IS_ERR(bl)) {
+ dev_err(&client->dev, "unable to register backlight device: %ld\n",
+ PTR_ERR(bl));
+ goto bl_init_error;
+ }
dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size);
return 0;
+bl_init_error:
+ unregister_framebuffer(info);
panel_init_error:
if (par->device_info->need_pwm) {
pwm_disable(par->pwm);
@@ -630,6 +686,8 @@ static int ssd1307fb_remove(struct i2c_client *client)
ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
+ backlight_device_unregister(info->bl_dev);
+
unregister_framebuffer(info);
if (par->device_info->need_pwm) {
pwm_disable(par->pwm);
--
2.3.0
^ permalink raw reply related
* [PATCHv5 11/11] fbdev: ssd1307fb: Add blank mode
From: Thomas Niederprüm @ 2015-03-24 21:23 UTC (permalink / raw)
To: plagnioj, tomi.valkeinen, maxime.ripard, kernel, shawn.guo,
robh+dt
Cc: linux-fbdev, linux-kernel, Thomas Niederprüm
In-Reply-To: <1427232238-21099-1-git-send-email-niederp@physik.uni-kl.de>
This patch adds ssd1307fb_blank() to make the framebuffer capable
of blanking.
Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
---
drivers/video/fbdev/ssd1307fb.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 061cc95..9101b27 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -238,6 +238,18 @@ static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf,
return count;
}
+static int ssd1307fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct ssd1307fb_par *par = info->par;
+ int ret;
+
+ if (blank_mode != FB_BLANK_UNBLANK)
+ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
+ else
+ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
+ return ret;
+}
+
static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct ssd1307fb_par *par = info->par;
@@ -263,6 +275,7 @@ static struct fb_ops ssd1307fb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
.fb_write = ssd1307fb_write,
+ .fb_blank = ssd1307fb_blank,
.fb_fillrect = ssd1307fb_fillrect,
.fb_copyarea = ssd1307fb_copyarea,
.fb_imageblit = ssd1307fb_imageblit,
--
2.3.0
^ permalink raw reply related
* Re: [PATCHv5 07/11] fbdev: ssd1307fb: Add a module parameter to set the refresh rate
From: Maxime Ripard @ 2015-03-24 21:54 UTC (permalink / raw)
To: Thomas Niederprüm
Cc: plagnioj, tomi.valkeinen, kernel, shawn.guo, robh+dt, linux-fbdev,
linux-kernel
In-Reply-To: <1427232238-21099-8-git-send-email-niederp@physik.uni-kl.de>
[-- Attachment #1: Type: text/plain, Size: 665 bytes --]
On Tue, Mar 24, 2015 at 10:23:54PM +0100, Thomas Niederprüm wrote:
> This patch adds the module parameter "refreshrate" to set delay for the
> deferred io. The refresh rate is given in units of Hertz. The default
> refresh rate is 1 Hz. The refresh rate set through the newly introduced
> parameter applies to all instances of the driver and for now it is not
> possible to change it individually.
>
> Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCHv5 04/11] fbdev: ssd1307fb: Unify init code and obtain hw specific bits from DT
From: Maxime Ripard @ 2015-03-24 22:14 UTC (permalink / raw)
To: Thomas Niederprüm
Cc: plagnioj, tomi.valkeinen, kernel, shawn.guo, robh+dt, linux-fbdev,
linux-kernel
In-Reply-To: <1427232238-21099-5-git-send-email-niederp@physik.uni-kl.de>
[-- Attachment #1: Type: text/plain, Size: 14964 bytes --]
On Tue, Mar 24, 2015 at 10:23:51PM +0100, Thomas Niederprüm wrote:
> The 130X controllers are very similar from the configuration point of view.
> The configuration registers for the SSD1305/6/7 are bit identical (except the
> the VHCOM register and the the default values for clock setup register). This
> patch unifies the init code of the controller and adds hardware specific
> properties to DT that are needed to correctly initialize the device.
>
> The SSD130X can be wired to the OLED panel in various ways. Even for the
> same controller this wiring can differ from one display module to another
> and can not be probed by software. The added DT properties reflect these
> hardware decisions of the display module manufacturer.
> The 'com-sequential', 'com-lrremap' and 'com-invdir' values define different
> possibilities for the COM signals pin configuration and readout direction
> of the video memory. The 'segment-no-remap' allows the inversion of the
> memory-to-pin mapping ultimately inverting the order of the controllers
> output pins. The 'prechargepX' values need to be adapted according to the
> capacitance of the OLEDs pixel cells.
>
> So far these hardware specific bits are hard coded in the init code, making
> the driver usable only for one certain wiring of the controller. This patch
> makes the driver usable with all possible hardware setups, given a valid hw
> description in DT. If these values are not set in DT the default values,
> as they are set in the ssd1307 init code right now, are used. This implies
> that without the corresponding DT property "segment-no-remap" the segment
> remap of the ssd130X controller gets activated. Even though this is not the
> default behaviour according to the datasheet it maintains backward
> compatibility with older DTBs.
>
> Note that the SSD1306 does not seem to be using the configuration written to
> the registers at all. Therefore this patch does not try to maintain these
> values without changes in DT. For reference an example is added to the DT
> bindings documentation that reproduces the configuration that is set in the
> current init code.
>
> Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
> ---
> .../devicetree/bindings/video/ssd1307fb.txt | 21 +++
> drivers/video/fbdev/ssd1307fb.c | 192 ++++++++++++---------
> 2 files changed, 134 insertions(+), 79 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
> index 7a12542..637690f 100644
> --- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
> +++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
> @@ -15,6 +15,16 @@ Required properties:
>
> Optional properties:
> - reset-active-low: Is the reset gpio is active on physical low?
> + - solomon,segment-no-remap: Display needs normal (non-inverted) data column
> + to segment mapping
> + - solomon,com-sequential: Display uses sequential COM pin configuration
> + - solomon,com-lrremap: Display uses left-right COM pin remap
> + - solomon,com-invdir: Display uses inverted COM pin scan direction
> + - solomon,com-offset: Number of the COM pin wired to the first display line
> + - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
> + - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
> + This needs to be the higher, the higher the capacitance
> + of the OLED's pixels is
>
> [0]: Documentation/devicetree/bindings/pwm/pwm.txt
>
> @@ -26,3 +36,14 @@ ssd1307: oled@3c {
> reset-gpios = <&gpio2 7>;
> reset-active-low;
> };
> +
> +ssd1306: oled@3c {
> + compatible = "solomon,ssd1306fb-i2c";
> + reg = <0x3c>;
> + pwms = <&pwm 4 3000>;
> + reset-gpios = <&gpio2 7>;
> + reset-active-low;
> + solomon,com-lrremap;
> + solomon,com-invdir;
> + solomon,com-offset = <32>;
> +};
> diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
> index 8d34c56..d16aad4 100644
> --- a/drivers/video/fbdev/ssd1307fb.c
> +++ b/drivers/video/fbdev/ssd1307fb.c
> @@ -40,20 +40,34 @@
>
> struct ssd1307fb_par;
>
> -struct ssd1307fb_ops {
> - int (*init)(struct ssd1307fb_par *);
> - int (*remove)(struct ssd1307fb_par *);
> +struct ssd1307fb_deviceinfo {
> + u32 default_vcomh;
> + u32 default_dclk_div;
> + u32 default_dclk_frq;
> + int need_pwm;
> + int need_chargepump;
> };
>
> struct ssd1307fb_par {
> + u32 com_invdir;
> + u32 com_lrremap;
> + u32 com_offset;
> + u32 com_seq;
> + u32 contrast;
> + u32 dclk_div;
> + u32 dclk_frq;
> + struct ssd1307fb_deviceinfo *device_info;
> struct i2c_client *client;
> u32 height;
> struct fb_info *info;
> - struct ssd1307fb_ops *ops;
> u32 page_offset;
> + u32 prechargep1;
> + u32 prechargep2;
> struct pwm_device *pwm;
> u32 pwm_period;
> int reset;
> + u32 seg_remap;
> + u32 vcomh;
> u32 width;
> };
>
> @@ -254,69 +268,46 @@ static struct fb_deferred_io ssd1307fb_defio = {
> .deferred_io = ssd1307fb_deferred_io,
> };
>
> -static int ssd1307fb_ssd1307_init(struct ssd1307fb_par *par)
> +static int ssd1307fb_init(struct ssd1307fb_par *par)
> {
> int ret;
> + u32 precharge, dclk, com_invdir, compins;
>
> - par->pwm = pwm_get(&par->client->dev, NULL);
> - if (IS_ERR(par->pwm)) {
> - dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
> - return PTR_ERR(par->pwm);
> - }
> -
> - par->pwm_period = pwm_get_period(par->pwm);
> - /* Enable the PWM */
> - pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
> - pwm_enable(par->pwm);
> -
> - dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
> - par->pwm->pwm, par->pwm_period);
> -
> - /* Map column 127 of the OLED to segment 0 */
> - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
> - if (ret < 0)
> - return ret;
> -
> - /* Turn on the display */
> - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
> - if (ret < 0)
> - return ret;
> -
> - return 0;
> -}
> -
> -static int ssd1307fb_ssd1307_remove(struct ssd1307fb_par *par)
> -{
> - pwm_disable(par->pwm);
> - pwm_put(par->pwm);
> - return 0;
> -}
> + if (par->device_info->need_pwm) {
> + par->pwm = pwm_get(&par->client->dev, NULL);
> + if (IS_ERR(par->pwm)) {
> + dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
> + return PTR_ERR(par->pwm);
> + }
>
> -static struct ssd1307fb_ops ssd1307fb_ssd1307_ops = {
> - .init = ssd1307fb_ssd1307_init,
> - .remove = ssd1307fb_ssd1307_remove,
> -};
> + par->pwm_period = pwm_get_period(par->pwm);
> + /* Enable the PWM */
> + pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
> + pwm_enable(par->pwm);
>
> -static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> -{
> - int ret;
> + dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
> + par->pwm->pwm, par->pwm_period);
> + };
>
> /* Set initial contrast */
> ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x7f);
> - if (ret < 0)
> - return ret;
> -
> - /* Set COM direction */
> - ret = ssd1307fb_write_cmd(par->client, 0xc8);
> + ret = ssd1307fb_write_cmd(par->client, par->contrast);
> if (ret < 0)
> return ret;
>
> /* Set segment re-map */
> - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
> + if (par->seg_remap) {
> + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
> + if (ret < 0)
> + return ret;
> + };
> +
> + /* Set COM direction */
> + com_invdir = 0xc0 | (par->com_invdir & 0xf) << 3;
> + ret = ssd1307fb_write_cmd(par->client, com_invdir);
> if (ret < 0)
> return ret;
>
> @@ -334,7 +325,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x20);
> + ret = ssd1307fb_write_cmd(par->client, par->com_offset);
> if (ret < 0)
> return ret;
>
> @@ -343,7 +334,8 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0xf0);
> + dclk = (par->dclk_div & 0xf) | (par->dclk_frq & 0xf) << 4;
> + ret = ssd1307fb_write_cmd(par->client, dclk);
> if (ret < 0)
> return ret;
>
> @@ -352,7 +344,8 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x22);
> + precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
> + ret = ssd1307fb_write_cmd(par->client, precharge);
> if (ret < 0)
> return ret;
>
> @@ -361,7 +354,9 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x22);
> + compins = 0x02 | (!par->com_seq & 0x1) << 4
> + | (par->com_lrremap & 0x1) << 5;
> + ret = ssd1307fb_write_cmd(par->client, compins);
> if (ret < 0)
> return ret;
>
> @@ -370,18 +365,20 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x49);
> + ret = ssd1307fb_write_cmd(par->client, par->vcomh);
> if (ret < 0)
> return ret;
>
> - /* Turn on the DC-DC Charge Pump */
> - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
> - if (ret < 0)
> - return ret;
> + if (par->device_info->need_chargepump) {
> + /* Turn on the DC-DC Charge Pump */
> + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
> + if (ret < 0)
> + return ret;
>
> - ret = ssd1307fb_write_cmd(par->client, 0x14);
> - if (ret < 0)
> - return ret;
> + ret = ssd1307fb_write_cmd(par->client, 0x14);
> + if (ret < 0)
> + return ret;
> + };
>
> /* Switch to horizontal addressing mode */
> ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
> @@ -393,6 +390,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> + /* Set column range */
> ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
> if (ret < 0)
> return ret;
> @@ -405,6 +403,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
> + /* Set page range */
> ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
> if (ret < 0)
> return ret;
> @@ -426,18 +425,30 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> return 0;
> }
>
> -static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = {
> - .init = ssd1307fb_ssd1306_init,
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
> + .default_vcomh = 0x20,
> + .default_dclk_div = 0,
A division by 0 ?
> + .default_dclk_frq = 8,
> + .need_pwm = 0,
You don't need to declare this field, its value will already be
initialized to 0.
> + .need_chargepump = 1,
> +};
> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
> + .default_vcomh = 0x20,
> + .default_dclk_div = 1,
> + .default_dclk_frq = 12,
> + .need_pwm = 1,
> + .need_chargepump = 0,
> };
Same thing here.
>
> static const struct of_device_id ssd1307fb_of_match[] = {
> {
> .compatible = "solomon,ssd1306fb-i2c",
> - .data = (void *)&ssd1307fb_ssd1306_ops,
> + .data = (void *)&ssd1307fb_ssd1306_deviceinfo,
> },
> {
> .compatible = "solomon,ssd1307fb-i2c",
> - .data = (void *)&ssd1307fb_ssd1307_ops,
> + .data = (void *)&ssd1307fb_ssd1307_deviceinfo,
> },
> {},
> };
> @@ -468,8 +479,8 @@ static int ssd1307fb_probe(struct i2c_client *client,
> par->info = info;
> par->client = client;
>
> - par->ops = (struct ssd1307fb_ops *)of_match_device(ssd1307fb_of_match,
> - &client->dev)->data;
> + par->device_info = (struct ssd1307fb_deviceinfo *)of_match_device(
> + ssd1307fb_of_match, &client->dev)->data;
>
> par->reset = of_get_named_gpio(client->dev.of_node,
> "reset-gpios", 0);
> @@ -487,6 +498,27 @@ static int ssd1307fb_probe(struct i2c_client *client,
> if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
> par->page_offset = 1;
>
> + if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
> + par->com_offset = 0;
> +
> + if (of_property_read_u32(node, "solomon,prechargep1", &par->prechargep1))
> + par->prechargep1 = 2;
> +
> + if (of_property_read_u32(node, "solomon,prechargep2", &par->prechargep2))
> + par->prechargep2 = 0;
> +
> + par->seg_remap = !of_property_read_bool(node, "solomon,segment-no-remap");
> + par->com_seq = of_property_read_bool(node, "solomon,com-sequential");
> + par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
> + par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
> +
> + par->contrast = 127;
> + par->vcomh = par->device_info->default_vcomh;
> +
> + /* Setup display timing */
> + par->dclk_div = par->device_info->default_dclk_div;
> + par->dclk_frq = par->device_info->default_dclk_frq;
> +
> vmem_size = par->width * par->height / 8;
>
> vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
> @@ -539,11 +571,9 @@ static int ssd1307fb_probe(struct i2c_client *client,
> gpio_set_value(par->reset, 1);
> udelay(4);
>
> - if (par->ops->init) {
> - ret = par->ops->init(par);
> - if (ret)
> - goto reset_oled_error;
> - }
> + ret = ssd1307fb_init(par);
> + if (ret)
> + goto reset_oled_error;
>
> ret = register_framebuffer(info);
> if (ret) {
> @@ -556,8 +586,10 @@ static int ssd1307fb_probe(struct i2c_client *client,
> return 0;
>
> panel_init_error:
> - if (par->ops->remove)
> - par->ops->remove(par);
> + if (par->device_info->need_pwm) {
> + pwm_disable(par->pwm);
> + pwm_put(par->pwm);
> + };
> reset_oled_error:
> fb_deferred_io_cleanup(info);
> fb_alloc_error:
> @@ -571,8 +603,10 @@ static int ssd1307fb_remove(struct i2c_client *client)
> struct ssd1307fb_par *par = info->par;
>
> unregister_framebuffer(info);
> - if (par->ops->remove)
> - par->ops->remove(par);
> + if (par->device_info->need_pwm) {
> + pwm_disable(par->pwm);
> + pwm_put(par->pwm);
> + };
> fb_deferred_io_cleanup(info);
> __free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len));
> framebuffer_release(info);
> --
> 2.3.0
>
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCHv5 09/11] fbdev: ssd1307fb: Add module parameter to set the initial contrast
From: Maxime Ripard @ 2015-03-24 22:16 UTC (permalink / raw)
To: Thomas Niederprüm
Cc: plagnioj, tomi.valkeinen, kernel, shawn.guo, robh+dt, linux-fbdev,
linux-kernel
In-Reply-To: <1427232238-21099-10-git-send-email-niederp@physik.uni-kl.de>
[-- Attachment #1: Type: text/plain, Size: 527 bytes --]
On Tue, Mar 24, 2015 at 10:23:56PM +0100, Thomas Niederprüm wrote:
> This patch adds the module parameter "contrast" to determine the
> contrast value that is used to initialize the display. This
> setting applies to all instances of the driver.
>
> Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
Do we still need this patch given that the next one is doing the exact
same thing?
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC 1/6] drm: Add top level Kconfig option for DRM fbdev emulation
From: Archit Taneja @ 2015-03-25 8:29 UTC (permalink / raw)
To: robdclark, airlied, treding, p.zabel, benjamin.gaignard,
dri-devel, daniel
Cc: linux-arm-msm, linux-fbdev, tomi.valkeinen, linux-kernel
In-Reply-To: <20150313090651.GZ3800@phenom.ffwll.local>
Hi,
On 03/13/2015 02:36 PM, Daniel Vetter wrote:
> On Fri, Mar 13, 2015 at 11:55:07AM +0530, Archit Taneja wrote:
>>
>>
>> On 03/11/2015 08:47 PM, Daniel Vetter wrote:
>>> On Wed, Mar 11, 2015 at 01:51:02PM +0530, Archit Taneja wrote:
>>>>
>>>>
>>>> On 03/10/2015 05:47 PM, Daniel Vetter wrote:
>>>>> On Tue, Mar 10, 2015 at 03:52:41PM +0530, Archit Taneja wrote:
>>>>>> On 03/10/2015 03:35 PM, Daniel Vetter wrote:
>>>>>>> On Tue, Mar 10, 2015 at 03:22:49PM +0530, Archit Taneja wrote:
>>>>>>>> On 03/10/2015 03:17 PM, Daniel Vetter wrote:
>>>>>>>>> On Tue, Mar 10, 2015 at 03:11:28PM +0530, Archit Taneja wrote:
>>>>>>>>>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>>>>>>>>>> index 151a050..38f83a0 100644
>>>>>>>>>> --- a/drivers/gpu/drm/Kconfig
>>>>>>>>>> +++ b/drivers/gpu/drm/Kconfig
>>>>>>>>>> @@ -40,6 +40,24 @@ config DRM_KMS_FB_HELPER
>>>>>>>>>> help
>>>>>>>>>> FBDEV helpers for KMS drivers.
>>>>>>>>>>
>>>>>>>>>> +config DRM_FBDEV_EMULATION
>>>>>>>>>> + bool "Enable legacy fbdev support for your modesetting driver"
>>>>>>>>>> + depends on DRM
>>>>>>>>>> + select DRM_KMS_HELPER
>>>>>>>>>> + select DRM_KMS_FB_HELPER
>>>>>>>>>> + select FB_SYS_FILLRECT
>>>>>>>>>> + select FB_SYS_COPYAREA
>>>>>>>>>> + select FB_SYS_IMAGEBLIT
>>>>>>>>>> + select FB_SYS_FOPS
>>>>>>>>>> + select FB_CFB_FILLRECT
>>>>>>>>>> + select FB_CFB_COPYAREA
>>>>>>>>>> + select FB_CFB_IMAGEBLIT
>>>>>>>>>> + default y
>>>>>>>>>> + help
>>>>>>>>>> + Choose this option if you have a need for the legacy fbdev
>>>>>>>>>> + support. Note that this support also provide the linux console
>>>>>>>>>> + support on top of your modesetting driver.
>>>>>>>>>
>>>>>>>>> Maybe clarify that for linux console support you also need
>>>>>>>>> CONFIG_FRAMEBUFFER_CONSOLE? fbdev alone isn't enough.
>>>>>>>>
>>>>>>>> DRM_KMS_FB_HELPER selects that for us, right?
>>>>>>>
>>>>>>> Hm right I've missed that. Reminds me that you need one more patch at the
>>>>>>> end to remove all the various select DRM_KMS_FB_HELPER from all drm
>>>>>>> drivers. Otherwise this knob here won't work by default if you e.g. select
>>>>>>> radeon. In general we can't mix explicit options with menu entries with a
>>>>>>> select.
>>>>>>
>>>>>> I was trying that out. Removing DRM_KMS_FB_HELPER and having
>>>>>> DRM_FBDEV_EMULATION disabled breaks drivers which use FB stuff internally in
>>>>>> their respective xyz_fbdev.c files.
>>>>>
>>>>> But with the stubbed out functions that should work, right? Why doesn't
>>>>> it?
>>>>
>>>> There are still calls to functions from fb core like fb_set_suspend and
>>>> register_framebuffer which aren't covered by the drm fb helper functions.
>>>
>>> Hm, sounds like we need another patch to stub out fb_set_suspend when
>>> fbdev isn't enabled. Is there anything else?
>>
>> There are a handful of fb core functions which are called by drm drivers:
>>
>> fb_alloc_cmap/fb_dealloc_cmap
>>
>> fb_sys_read/fb_sys_write
>>
>> register_framebuffer/unregister_framebuffer/unlink_framebuffer/
>> remove_conflicting_framebuffers
>>
>> fb_set_suspend
>>
>> fb_deferred_io_init/fb_deferred_io_cleanup
>>
>> framebuffer_alloc/framebuffer_release
>
> Hm yeah that's somewhat annoying indeed. What about the following:
> 1. We move all the #include <linux/fb.h> from drivers into drm_fb_helper.h
>
> 2. Then we add stubs for these functions in drm_fb_helper.h, like this
>
> #if defined(CONFIG_FB)
> #include <linux/fb.h>
> #else
>
> /* static inline stubs for all the fb stuff used by kms drivers */
> #endif
>
> Imo this makes sense since kms drivers really have a bit a special
> situation with fbdev. They're not full-blown fbdev drivers and can be
> useful fully without fbdev.
>
I was trying this out. Removing 'linux/fb.h' and replacing stub fb funcs
won't really work because struct declarations(like fb_info) also get
removed.
I considered placing '#if IS_ENABLED(CONFIG_FB)' within linux/fb.h
itself, but that seemed a bit too intrusive.
This is what I'm currently doing:
- Some funcs, like framebufer_alloc/release, alloc_cmap/dealloc_cmap
would actually benefit if we have drm fb helpers for them. They are used
in exactly the same manner by all the drivers.
- For the rest of the functions that are sparsely used, I was
considering making very simple drm_fb_* wrapper functions. Something like:
void drm_fb_helper_deferred_io_init(struct drm_fb_helper *helper)
{
if (helper->fbdev)
fb_deferred_io_init(helper->fbdev);
}
We could have all fb calls called within drm_fb_helper.c, creating
drm_fb_helper_* stub functions would then be an easier task. What do you
think?
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [RFC 1/6] drm: Add top level Kconfig option for DRM fbdev emulation
From: Daniel Vetter @ 2015-03-25 9:21 UTC (permalink / raw)
To: Archit Taneja
Cc: robdclark, airlied, treding, p.zabel, benjamin.gaignard,
dri-devel, daniel, linux-kernel, linux-arm-msm, Jani Nikula,
linux-fbdev, tomi.valkeinen
In-Reply-To: <55126F32.90404@codeaurora.org>
On Wed, Mar 25, 2015 at 01:47:54PM +0530, Archit Taneja wrote:
> Hi,
>
> On 03/13/2015 02:36 PM, Daniel Vetter wrote:
> >On Fri, Mar 13, 2015 at 11:55:07AM +0530, Archit Taneja wrote:
> >>
> >>
> >>On 03/11/2015 08:47 PM, Daniel Vetter wrote:
> >>>On Wed, Mar 11, 2015 at 01:51:02PM +0530, Archit Taneja wrote:
> >>>>
> >>>>
> >>>>On 03/10/2015 05:47 PM, Daniel Vetter wrote:
> >>>>>On Tue, Mar 10, 2015 at 03:52:41PM +0530, Archit Taneja wrote:
> >>>>>>On 03/10/2015 03:35 PM, Daniel Vetter wrote:
> >>>>>>>On Tue, Mar 10, 2015 at 03:22:49PM +0530, Archit Taneja wrote:
> >>>>>>>>On 03/10/2015 03:17 PM, Daniel Vetter wrote:
> >>>>>>>>>On Tue, Mar 10, 2015 at 03:11:28PM +0530, Archit Taneja wrote:
> >>>>>>>>>>diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >>>>>>>>>>index 151a050..38f83a0 100644
> >>>>>>>>>>--- a/drivers/gpu/drm/Kconfig
> >>>>>>>>>>+++ b/drivers/gpu/drm/Kconfig
> >>>>>>>>>>@@ -40,6 +40,24 @@ config DRM_KMS_FB_HELPER
> >>>>>>>>>> help
> >>>>>>>>>> FBDEV helpers for KMS drivers.
> >>>>>>>>>>
> >>>>>>>>>>+config DRM_FBDEV_EMULATION
> >>>>>>>>>>+ bool "Enable legacy fbdev support for your modesetting driver"
> >>>>>>>>>>+ depends on DRM
> >>>>>>>>>>+ select DRM_KMS_HELPER
> >>>>>>>>>>+ select DRM_KMS_FB_HELPER
> >>>>>>>>>>+ select FB_SYS_FILLRECT
> >>>>>>>>>>+ select FB_SYS_COPYAREA
> >>>>>>>>>>+ select FB_SYS_IMAGEBLIT
> >>>>>>>>>>+ select FB_SYS_FOPS
> >>>>>>>>>>+ select FB_CFB_FILLRECT
> >>>>>>>>>>+ select FB_CFB_COPYAREA
> >>>>>>>>>>+ select FB_CFB_IMAGEBLIT
> >>>>>>>>>>+ default y
> >>>>>>>>>>+ help
> >>>>>>>>>>+ Choose this option if you have a need for the legacy fbdev
> >>>>>>>>>>+ support. Note that this support also provide the linux console
> >>>>>>>>>>+ support on top of your modesetting driver.
> >>>>>>>>>
> >>>>>>>>>Maybe clarify that for linux console support you also need
> >>>>>>>>>CONFIG_FRAMEBUFFER_CONSOLE? fbdev alone isn't enough.
> >>>>>>>>
> >>>>>>>>DRM_KMS_FB_HELPER selects that for us, right?
> >>>>>>>
> >>>>>>>Hm right I've missed that. Reminds me that you need one more patch at the
> >>>>>>>end to remove all the various select DRM_KMS_FB_HELPER from all drm
> >>>>>>>drivers. Otherwise this knob here won't work by default if you e.g. select
> >>>>>>>radeon. In general we can't mix explicit options with menu entries with a
> >>>>>>>select.
> >>>>>>
> >>>>>>I was trying that out. Removing DRM_KMS_FB_HELPER and having
> >>>>>>DRM_FBDEV_EMULATION disabled breaks drivers which use FB stuff internally in
> >>>>>>their respective xyz_fbdev.c files.
> >>>>>
> >>>>>But with the stubbed out functions that should work, right? Why doesn't
> >>>>>it?
> >>>>
> >>>>There are still calls to functions from fb core like fb_set_suspend and
> >>>>register_framebuffer which aren't covered by the drm fb helper functions.
> >>>
> >>>Hm, sounds like we need another patch to stub out fb_set_suspend when
> >>>fbdev isn't enabled. Is there anything else?
> >>
> >>There are a handful of fb core functions which are called by drm drivers:
> >>
> >>fb_alloc_cmap/fb_dealloc_cmap
> >>
> >>fb_sys_read/fb_sys_write
> >>
> >>register_framebuffer/unregister_framebuffer/unlink_framebuffer/
> >>remove_conflicting_framebuffers
> >>
> >>fb_set_suspend
> >>
> >>fb_deferred_io_init/fb_deferred_io_cleanup
> >>
> >>framebuffer_alloc/framebuffer_release
> >
> >Hm yeah that's somewhat annoying indeed. What about the following:
> >1. We move all the #include <linux/fb.h> from drivers into drm_fb_helper.h
> >
> >2. Then we add stubs for these functions in drm_fb_helper.h, like this
> >
> >#if defined(CONFIG_FB)
> >#include <linux/fb.h>
> >#else
> >
> >/* static inline stubs for all the fb stuff used by kms drivers */
> >#endif
> >
> >Imo this makes sense since kms drivers really have a bit a special
> >situation with fbdev. They're not full-blown fbdev drivers and can be
> >useful fully without fbdev.
> >
>
> I was trying this out. Removing 'linux/fb.h' and replacing stub fb funcs
> won't really work because struct declarations(like fb_info) also get
> removed.
>
> I considered placing '#if IS_ENABLED(CONFIG_FB)' within linux/fb.h itself,
> but that seemed a bit too intrusive.
>
> This is what I'm currently doing:
>
> - Some funcs, like framebufer_alloc/release, alloc_cmap/dealloc_cmap would
> actually benefit if we have drm fb helpers for them. They are used in
> exactly the same manner by all the drivers.
>
> - For the rest of the functions that are sparsely used, I was considering
> making very simple drm_fb_* wrapper functions. Something like:
>
> void drm_fb_helper_deferred_io_init(struct drm_fb_helper *helper)
> {
> if (helper->fbdev)
> fb_deferred_io_init(helper->fbdev);
> }
>
> We could have all fb calls called within drm_fb_helper.c, creating
> drm_fb_helper_* stub functions would then be an easier task. What do you
> think?
That's actually an option I considered, but I hoped we could do it with
less work. If this indeed works and you can create the patch that would be
awesome.
Thanks, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply
* Re: [PATCH 5/8] fbdev: ssd1307fb: Add module parameter bitsperpixel.
From: Olliver Schinagl @ 2015-03-25 10:56 UTC (permalink / raw)
To: linux-kernel; +Cc: linux-fbdev, plagnioj
In-Reply-To: <54FECB5D.1020908@ti.com>
Hey all,
On 10-03-15 11:45, Tomi Valkeinen wrote:
> On 14/02/15 17:54, Maxime Ripard wrote:
>> On Sat, Feb 07, 2015 at 05:05:03PM +0100, Thomas Niederprüm wrote:
>>> Am Sat, 7 Feb 2015 12:20:43 +0100
>>> schrieb Maxime Ripard <maxime.ripard@free-electrons.com>:
>>>
>>>> On Fri, Feb 06, 2015 at 11:28:11PM +0100, niederp@physik.uni-kl.de
>>>> wrote:
>>>>> From: Thomas Niederprüm <niederp@physik.uni-kl.de>
>>>>>
>>>>> This patch adds a module parameter 'bitsperpixel' to adjust the
>>>>> colordepth of the framebuffer. All values >1 will result in memory
>>>>> map of the requested color depth. However only the MSB of each
>>>>> pixel will be sent to the device. The framebuffer identifies itself
>>>>> as a grayscale display with the specified depth.
>>>>
>>>> I'm not sure this is the right thing to do.
>>>>
>>>> The bits per pixel for this display is rightfully defined, used and
>>>> reported to the userspace, why would you want to change that?
>>>
>>> You are right of course. The display is 1bpp and it reports to be 1
>>> bpp. The problem is that there is almost no userspace library that can
>>> handle 1 bit framebuffers correctly. So it is nice if the framebuffer
>>> (optionally) can expose itself as 8 bits per pixel grayscale to the
>>> userspace program. As an example this allows to run DirectFB on the
>>> framebuffer, which is not possible out of the box for 1bpp.
>>>
>>> Also note that if do not set the module parameter at load time
>>> the framebuffer will be 1bpp. So you have to actively set that module
>>> parameter to make the framebuffer pretend to be more than 1bpp.
>>>
>>> In any case I don't cling to that patch, I just thought it was a nice
>>> feature.
>>
>> I'd say that the right fix would be to patch DirectFB, instead of
>> faking that in the kernel.
>>
>> But again, that's probably Tomi's call, not mine.
>
> Right, I'm not thrilled =). I don't think it's a good idea to lie to the
> userspace (except when fixing regressions).
I've done the same thing actually in a local patchset and while you are
right, we shouldn't lie to userspace, my choice was a performance one.
Right now, in the driver we already have to convert from a regular
packed pixel framebuffer, to the format that supports the page layout of
the actual chip. Especially on slow hardware, doing the math within this
conversion just adds a few multiplications.
Also, there is indeed a lot of userspace out there which doesn't expect
single bit displays.
Having said that, what about actually faking grayscale? If we toggle a
pixel fast enough (we can achieve 40ish fps right now with a 400 kHz I2C
bus) it appears to a user as gray. This can't easily be done in user
space, would that be acceptable?
Olliver
>
> Tomi
>
>
^ permalink raw reply
* Re: [PATCH 1/2] vt: add cursor blink interval escape sequence
From: Greg Kroah-Hartman @ 2015-03-25 11:19 UTC (permalink / raw)
To: Scot Doyle
Cc: Jiri Slaby, Tomi Valkeinen, Jean-Christophe Plagniol-Villard,
Michael Kerrisk, Pavel Machek, Geert Uytterhoeven, linux-kernel,
linux-fbdev, linux-api, linux-man
In-Reply-To: <alpine.LNX.2.11.1502271911380.4248@localhost>
On Fri, Feb 27, 2015 at 07:13:48PM +0000, Scot Doyle wrote:
> Add an escape sequence to specify the current console's cursor blink
> interval. The interval is specified as a number of milliseconds until
> the next cursor display state toggle, from 50 to 65535. /proc/loadavg
> did not show a difference with a one msec interval, but the lower
> bound is set to 50 msecs since slower hardware wasn't tested.
>
> Store the interval in the vc_data structure for later access by fbcon,
> initializing the value to fbcon's current hardcoded value of 200 msecs.
>
> Signed-off-by: Scot Doyle <lkml14@scotdoyle.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---
> drivers/tty/vt/vt.c | 9 +++++++++
> include/linux/console_struct.h | 1 +
> 2 files changed, 10 insertions(+)
>
> diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
> index 6e00572..ab1f173 100644
> --- a/drivers/tty/vt/vt.c
> +++ b/drivers/tty/vt/vt.c
> @@ -135,6 +135,7 @@ const struct consw *conswitchp;
> */
> #define DEFAULT_BELL_PITCH 750
> #define DEFAULT_BELL_DURATION (HZ/8)
> +#define DEFAULT_CURSOR_BLINK_MS 200
>
> struct vc vc_cons [MAX_NR_CONSOLES];
>
> @@ -1590,6 +1591,13 @@ static void setterm_command(struct vc_data *vc)
> case 15: /* activate the previous console */
> set_console(last_console);
> break;
> + case 16: /* set cursor blink duration in msec */
Where is this now documented? Is this a "standard" ASCII command
somewhere? Adding new userspace apis have to be documented properly.
Without that, I can't take this series, sorry.
greg k-h
^ permalink raw reply
* Re: [PATCHv5 04/11] fbdev: ssd1307fb: Unify init code and obtain hw specific bits from DT
From: Olliver Schinagl @ 2015-03-25 15:49 UTC (permalink / raw)
To: Thomas Niederprüm, plagnioj, tomi.valkeinen, maxime.ripard,
kernel, shawn.guo, robh+dt
Cc: linux-fbdev, linux-kernel
In-Reply-To: <1427232238-21099-5-git-send-email-niederp@physik.uni-kl.de>
Hey Thomas,
awesome the time you put into this driver. It does what I was working on
the last few weeks, but with a much bigger bang ;)
I personally have a ssd1309 and will be submitting the patches for that
after testing your patch-set.
On 24-03-15 22:23, Thomas Niederprüm wrote:
> The 130X controllers are very similar from the configuration point of view.
> The configuration registers for the SSD1305/6/7 are bit identical (except the
> the VHCOM register and the the default values for clock setup register). This
> patch unifies the init code of the controller and adds hardware specific
> properties to DT that are needed to correctly initialize the device.
>
> The SSD130X can be wired to the OLED panel in various ways. Even for the
> same controller this wiring can differ from one display module to another
> and can not be probed by software. The added DT properties reflect these
> hardware decisions of the display module manufacturer.
> The 'com-sequential', 'com-lrremap' and 'com-invdir' values define different
> possibilities for the COM signals pin configuration and readout direction
> of the video memory. The 'segment-no-remap' allows the inversion of the
> memory-to-pin mapping ultimately inverting the order of the controllers
> output pins. The 'prechargepX' values need to be adapted according to the
> capacitance of the OLEDs pixel cells.
>
> So far these hardware specific bits are hard coded in the init code, making
> the driver usable only for one certain wiring of the controller. This patch
> makes the driver usable with all possible hardware setups, given a valid hw
> description in DT. If these values are not set in DT the default values,
> as they are set in the ssd1307 init code right now, are used. This implies
> that without the corresponding DT property "segment-no-remap" the segment
> remap of the ssd130X controller gets activated. Even though this is not the
> default behaviour according to the datasheet it maintains backward
> compatibility with older DTBs.
>
> Note that the SSD1306 does not seem to be using the configuration written to
> the registers at all. Therefore this patch does not try to maintain these
> values without changes in DT. For reference an example is added to the DT
> bindings documentation that reproduces the configuration that is set in the
> current init code.
>
> Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
> ---
> .../devicetree/bindings/video/ssd1307fb.txt | 21 +++
> drivers/video/fbdev/ssd1307fb.c | 192 ++++++++++++---------
> 2 files changed, 134 insertions(+), 79 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
> index 7a12542..637690f 100644
> --- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
> +++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
> @@ -15,6 +15,16 @@ Required properties:
>
> Optional properties:
> - reset-active-low: Is the reset gpio is active on physical low?
> + - solomon,segment-no-remap: Display needs normal (non-inverted) data column
> + to segment mapping
> + - solomon,com-sequential: Display uses sequential COM pin configuration
> + - solomon,com-lrremap: Display uses left-right COM pin remap
> + - solomon,com-invdir: Display uses inverted COM pin scan direction
> + - solomon,com-offset: Number of the COM pin wired to the first display line
> + - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
> + - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
> + This needs to be the higher, the higher the capacitance
> + of the OLED's pixels is
Aren't the height, width and page-offset also optional? They should be
set to sane defaults when not supplied. Though the default (which is the
max really) width/height depends on the actual attached display to the
chip (I mention this in the vcomh section too below, the controller's
width/height would be the absolute maximum values, the display can
always be smaller).
Same goes to say for the precharge, and probably other parameters. I
don't think we have a proper framework to handle the attached displays
to a controller chip at the moment anyhow?
>
> [0]: Documentation/devicetree/bindings/pwm/pwm.txt
>
<snip>
> +
> + /* Set COM direction */
> + com_invdir = 0xc0 | (par->com_invdir & 0xf) << 3;
Shouldn't this be par->com_invdir & 0x1 ?
The datasheet only mentions 1 bit change for the ssd1306, ssd1307 and
ssd1309. I dont' know what the ssd1305 does here though.
> + ret = ssd1307fb_write_cmd(par->client, com_invdir);
> if (ret < 0)
> return ret;
<snip>
>
> - ret = ssd1307fb_write_cmd(par->client, 0x14);
> - if (ret < 0)
> - return ret;
> + ret = ssd1307fb_write_cmd(par->client, 0x14);
> + if (ret < 0)
> + return ret;
> + };
I had to look hard for this setting, as my old datasheet had omitted the
charge pump def.
but wouldn't you want something like (0x10 |
par->device_info->need_chargepump & 0x1 << 2) & 0x14 to follow your
previous styles?
Only bit 2 determines the state of the charge-pump. And I guess it
should be safe to use on the other chips as well. My 1309 doesn't seem
to have a problem with it, I'm working a lot on this display so it will
be tested thoroughly in the next few weeks.
>
> /* Switch to horizontal addressing mode */
> ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
> @@ -393,6 +390,7 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> if (ret < 0)
> return ret;
>
<snip>
>
> -static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = {
> - .init = ssd1307fb_ssd1306_init,
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
> + .default_vcomh = 0x20,
> + .default_dclk_div = 0,
> + .default_dclk_frq = 8,
> + .need_pwm = 0,
> + .need_chargepump = 1,
> +};
This device info struct, is this really always fixed data? We use a
ssd1309 with a MI12864MO i think and the combination of these two parts
defines atleast the vcomh I would imagine? There are only a very limited
number of consumers of this driver so for now it won't make much of a
difference, just mentioning it as it is a configurable so it may matter
depending on the physical display.
> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
> + .default_vcomh = 0x20,
> + .default_dclk_div = 1,
> + .default_dclk_frq = 12,
> + .need_pwm = 1,
> + .need_chargepump = 0,
> };
>
> static const struct of_device_id ssd1307fb_of_match[] = {
> {
> .compatible = "solomon,ssd1306fb-i2c",
> - .data = (void *)&ssd1307fb_ssd1306_ops,
> + .data = (void *)&ssd1307fb_ssd1306_deviceinfo,
> },
> {
> .compatible = "solomon,ssd1307fb-i2c",
> - .data = (void *)&ssd1307fb_ssd1307_ops,
> + .data = (void *)&ssd1307fb_ssd1307_deviceinfo,
> },
> {},
> };
> @@ -468,8 +479,8 @@ static int ssd1307fb_probe(struct i2c_client *client,
> par->info = info;
> par->client = client;
>
> - par->ops = (struct ssd1307fb_ops *)of_match_device(ssd1307fb_of_match,
> - &client->dev)->data;
> + par->device_info = (struct ssd1307fb_deviceinfo *)of_match_device(
> + ssd1307fb_of_match, &client->dev)->data;
>
> par->reset = of_get_named_gpio(client->dev.of_node,
> "reset-gpios", 0);
> @@ -487,6 +498,27 @@ static int ssd1307fb_probe(struct i2c_client *client,
> if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
> par->page_offset = 1;
While your re-doing the whole driver, why use a default page_offset of
1? 0 makes far more sense (its the default on my board also) and
logically, we'd start counting at 0 as programmers ;) Also, the
datasheet uses 0 as a default preset.
>
> + if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
> + par->com_offset = 0;
> +
> + if (of_property_read_u32(node, "solomon,prechargep1", &par->prechargep1))
> + par->prechargep1 = 2;
> +
> + if (of_property_read_u32(node, "solomon,prechargep2", &par->prechargep2))
> + par->prechargep2 = 0;
Why set the default to 0 here? The datasheet sets it to 0x2 by default
for example.
> +
> + par->seg_remap = !of_property_read_bool(node, "solomon,segment-no-remap");
> + par->com_seq = of_property_read_bool(node, "solomon,com-sequential");
all the other parameters are somewhat abbreviated, or the property name
matches the variable name. I'd just abbreviate it to com-seq clear and
short.
Overal, the driver works and can have a Tested-by: Olliver Schinagl
<o.schinagl@ultimaker.com> from me (for the 1309 which I'll submit very
soon.
Olliver
P.S. Do you have a link for your display? I'm curious as to how it looks.
^ permalink raw reply
* Re: [PATCHv5 11/11] fbdev: ssd1307fb: Add blank mode
From: Olliver Schinagl @ 2015-03-25 15:50 UTC (permalink / raw)
To: Thomas Niederprüm, plagnioj, tomi.valkeinen, maxime.ripard,
kernel, shawn.guo, robh+dt
Cc: linux-fbdev, linux-kernel
In-Reply-To: <1427232238-21099-12-git-send-email-niederp@physik.uni-kl.de>
Hey Thomas,
On 24-03-15 22:23, Thomas Niederprüm wrote:
> This patch adds ssd1307fb_blank() to make the framebuffer capable
> of blanking.
>
> Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
> ---
> drivers/video/fbdev/ssd1307fb.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
> index 061cc95..9101b27 100644
> --- a/drivers/video/fbdev/ssd1307fb.c
> +++ b/drivers/video/fbdev/ssd1307fb.c
> @@ -238,6 +238,18 @@ static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf,
> return count;
> }
>
> +static int ssd1307fb_blank(int blank_mode, struct fb_info *info)
> +{
> + struct ssd1307fb_par *par = info->par;
> + int ret;
> +
> + if (blank_mode != FB_BLANK_UNBLANK)
> + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
> + else
> + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
I'd probably add an extra return, or drop the ret var at all and just
return the function.
or even shorter :)
return sd1307fb_write_cmd(par->client, (blank_mode != FB_BLANK_UNBLANK)
? SSD1307FB_DISPLAY_OFF : SSD1307FB_DISPLAY_ON;
Olliver
> + return ret;
> +}
> +
> static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
> {
> struct ssd1307fb_par *par = info->par;
> @@ -263,6 +275,7 @@ static struct fb_ops ssd1307fb_ops = {
> .owner = THIS_MODULE,
> .fb_read = fb_sys_read,
> .fb_write = ssd1307fb_write,
> + .fb_blank = ssd1307fb_blank,
> .fb_fillrect = ssd1307fb_fillrect,
> .fb_copyarea = ssd1307fb_copyarea,
> .fb_imageblit = ssd1307fb_imageblit,
>
^ permalink raw reply
* Re: [PATCH 5/8] fbdev: ssd1307fb: Add module parameter bitsperpixel.
From: Maxime Ripard @ 2015-03-25 16:02 UTC (permalink / raw)
To: Olliver Schinagl
Cc: Tomi Valkeinen, Thomas Niederprüm, linux-fbdev, plagnioj,
linux-kernel
In-Reply-To: <55129466.4060000@schinagl.nl>
[-- Attachment #1: Type: text/plain, Size: 3885 bytes --]
On Wed, Mar 25, 2015 at 11:56:38AM +0100, Olliver Schinagl wrote:
> Hey all,
>
> On 10-03-15 11:45, Tomi Valkeinen wrote:
> >On 14/02/15 17:54, Maxime Ripard wrote:
> >>On Sat, Feb 07, 2015 at 05:05:03PM +0100, Thomas Niederprüm wrote:
> >>>Am Sat, 7 Feb 2015 12:20:43 +0100
> >>>schrieb Maxime Ripard <maxime.ripard@free-electrons.com>:
> >>>
> >>>>On Fri, Feb 06, 2015 at 11:28:11PM +0100, niederp@physik.uni-kl.de
> >>>>wrote:
> >>>>>From: Thomas Niederprüm <niederp@physik.uni-kl.de>
> >>>>>
> >>>>>This patch adds a module parameter 'bitsperpixel' to adjust the
> >>>>>colordepth of the framebuffer. All values >1 will result in memory
> >>>>>map of the requested color depth. However only the MSB of each
> >>>>>pixel will be sent to the device. The framebuffer identifies itself
> >>>>>as a grayscale display with the specified depth.
> >>>>
> >>>>I'm not sure this is the right thing to do.
> >>>>
> >>>>The bits per pixel for this display is rightfully defined, used and
> >>>>reported to the userspace, why would you want to change that?
> >>>
> >>>You are right of course. The display is 1bpp and it reports to be 1
> >>>bpp. The problem is that there is almost no userspace library that can
> >>>handle 1 bit framebuffers correctly. So it is nice if the framebuffer
> >>>(optionally) can expose itself as 8 bits per pixel grayscale to the
> >>>userspace program. As an example this allows to run DirectFB on the
> >>>framebuffer, which is not possible out of the box for 1bpp.
> >>>
> >>>Also note that if do not set the module parameter at load time
> >>>the framebuffer will be 1bpp. So you have to actively set that module
> >>>parameter to make the framebuffer pretend to be more than 1bpp.
> >>>
> >>>In any case I don't cling to that patch, I just thought it was a nice
> >>>feature.
> >>
> >>I'd say that the right fix would be to patch DirectFB, instead of
> >>faking that in the kernel.
> >>
> >>But again, that's probably Tomi's call, not mine.
> >
> >Right, I'm not thrilled =). I don't think it's a good idea to lie to the
> >userspace (except when fixing regressions).
>
> I've done the same thing actually in a local patchset and while you are
> right, we shouldn't lie to userspace, my choice was a performance one.
Userspace drivers can be more performant than the kernel ones. That
doesn't mean that it's a good choice, let alone the right choice.
> Right now, in the driver we already have to convert from a regular packed
> pixel framebuffer, to the format that supports the page layout of the actual
> chip. Especially on slow hardware, doing the math within this conversion
> just adds a few multiplications.
And how does implementing monochrome operations in directfb would make
things worse from a performance point of view?
Are you really using performance as an argument for a device that is
driven through i2c?
> Also, there is indeed a lot of userspace out there which doesn't expect
> single bit displays.
And so just because *they* don't expect it and are not supporting
every case they should, *we* should do something about it?
A lot of userspace applications don't check syscall errors. Does that
mean that we should never return an error?
> Having said that, what about actually faking grayscale? If we toggle a pixel
> fast enough (we can achieve 40ish fps right now with a 400 kHz I2C bus) it
> appears to a user as gray. This can't easily be done in user space, would
> that be acceptable?
You can't make the assumption that the bus is fast enough. It's your
case, it might not be the case for everyone.
Seriously, the device is monochrome, deal with it. If you wanted a
grayscale screen, you should have chosen better.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v1 03/47] devres: add devm_ioremap_wc()
From: Luis R. Rodriguez @ 2015-03-25 19:50 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Luis R. Rodriguez, Ingo Molnar, Thomas Gleixner, H. Peter Anvin,
Juergen Gross, Jan Beulich, Borislav Petkov, Suresh Siddha,
venkatesh.pallipadi, Dave Airlie, linux-kernel@vger.kernel.org,
Linux Fbdev development list, X86 ML,
xen-devel@lists.xenproject.org, Ingo Molnar, Daniel Vetter,
Antonino Daplas, Jean-Christophe Plagniol-Villard, Tomi Valkeinen
In-Reply-To: <CALCETrX5K4pZE0DqcEwJiKYZofCr6yjJGK8MhjhPXMHNLJ4TTQ@mail.gmail.com>
On Fri, Mar 20, 2015 at 04:49:51PM -0700, Andy Lutomirski wrote:
> On Fri, Mar 20, 2015 at 4:17 PM, Luis R. Rodriguez
> <mcgrof@do-not-panic.com> wrote:
> > From: "Luis R. Rodriguez" <mcgrof@suse.com>
> >
> > We have devm_ioremap_nocache() but no devm_ioremap_wc()
> > so add that. This will be used later.
> >
> > Cc: Suresh Siddha <suresh.b.siddha@intel.com>
> > Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
> > Cc: Ingo Molnar <mingo@elte.hu>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Juergen Gross <jgross@suse.com>
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Cc: Andy Lutomirski <luto@amacapital.net>
> > Cc: Dave Airlie <airlied@redhat.com>
> > Cc: Antonino Daplas <adaplas@gmail.com>
> > Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> > Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > Cc: linux-fbdev@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> > Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
>
> Looks good to me.
Thanks, I'll peg a Reviewed-by.
Luis
^ permalink raw reply
* Re: [PATCH v1 02/47] x86: mtrr: generalize run time disabling of MTRR
From: Konrad Rzeszutek Wilk @ 2015-03-25 19:59 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: luto, mingo, tglx, hpa, jgross, JBeulich, bp, suresh.b.siddha,
venkatesh.pallipadi, airlied, linux-kernel, linux-fbdev, x86,
xen-devel, Luis R. Rodriguez, Ingo Molnar, Daniel Vetter,
Antonino Daplas, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
Dave Hansen, Stefan Bader, ville.syrjala, david.vrabel,
toshi.kani, bhelgaas, Roger Pau Monné, xen-devel
In-Reply-To: <1426893517-2511-3-git-send-email-mcgrof@do-not-panic.com>
On Fri, Mar 20, 2015 at 04:17:52PM -0700, Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <mcgrof@suse.com>
>
> It is possible to enable CONFIG_MTRR and up with it
> disabled at run time and yet CONFIG_X86_PAT continues
> to kick through fully functionally. This can happen
s/fully/full/ ?
> for instance on Xen where MTRR is not supported but
> PAT is, this can happen now on Linux as of commit
> 47591df50 by Juergen introduced as of v3.19.
s/3.19/4.0/
>
> Technically we should assume the proper CPU
> bits would be set to disable MTRR but we can't
> always rely on this. At least on the Xen Hypervisor
> for instance only X86_FEATURE_MTRR was disabled
> as of Xen 4.4 through Xen commit 586ab6a [0],
> but not X86_FEATURE_K6_MTRR, X86_FEATURE_CENTAUR_MCR,
> or X86_FEATURE_CYRIX_ARR for instance.
Oh, could you send an patch for that to Xen please?
>
> x86 mtrr code relies on quite a bit of checks for
> mtrr_if being set to check to see if MTRR did get
> set up, instead of using that lets provide a generic
> setter which when set we know MTRR is enabled. This
s/we know MTRR is enabled/will let us know that MTRR is enabled/
> also adds a few checks where they were not before
> which could potentially safeguard ourselves against
> incorrect usage of MTRR where this was not desirable.
>
> Where possible match error codes as if MTRR was
> disabled on arch/x86/include/asm/mtrr.h.
>
> Lastly, since disabling MTRR can happen at run time
> and we could end up with PAT enabled best record now
> on our logs when MTRR is disabled.
>
> [0] ~/devel/xen (git::stable-4.5)$ git describe --contains 586ab6a
> 4.4.0-rc1~18
>
> Cc: Andy Lutomirski <luto@amacapital.net>
> Cc: Suresh Siddha <suresh.b.siddha@intel.com>
> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Juergen Gross <jgross@suse.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Dave Airlie <airlied@redhat.com>
> Cc: Antonino Daplas <adaplas@gmail.com>
> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: venkatesh.pallipadi@intel.com
> Cc: Stefan Bader <stefan.bader@canonical.com>
> Cc: konrad.wilk@oracle.com
> Cc: ville.syrjala@linux.intel.com
> Cc: david.vrabel@citrix.com
> Cc: jbeulich@suse.com
> Cc: toshi.kani@hp.com
> Cc: bhelgaas@google.com
> Cc: Roger Pau Monné <roger.pau@citrix.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: xen-devel@lists.xensource.com
> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
> ---
> arch/x86/include/asm/mtrr.h | 2 ++
> arch/x86/kernel/cpu/mtrr/cleanup.c | 2 +-
> arch/x86/kernel/cpu/mtrr/generic.c | 5 +++--
> arch/x86/kernel/cpu/mtrr/if.c | 3 +++
> arch/x86/kernel/cpu/mtrr/main.c | 31 ++++++++++++++++++++++---------
> 5 files changed, 31 insertions(+), 12 deletions(-)
>
> diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
> index f768f62..cade917 100644
> --- a/arch/x86/include/asm/mtrr.h
> +++ b/arch/x86/include/asm/mtrr.h
> @@ -31,6 +31,7 @@
> * arch_phys_wc_add and arch_phys_wc_del.
> */
> # ifdef CONFIG_MTRR
> +extern int mtrr_enabled;
> extern u8 mtrr_type_lookup(u64 addr, u64 end);
> extern void mtrr_save_fixed_ranges(void *);
> extern void mtrr_save_state(void);
> @@ -50,6 +51,7 @@ extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
> extern int amd_special_default_mtrr(void);
> extern int phys_wc_to_mtrr_index(int handle);
> # else
> +static const int mtrr_enabled;
> static inline u8 mtrr_type_lookup(u64 addr, u64 end)
> {
> /*
> diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
> index 5f90b85..784dc55 100644
> --- a/arch/x86/kernel/cpu/mtrr/cleanup.c
> +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
> @@ -880,7 +880,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
> * Make sure we only trim uncachable memory on machines that
> * support the Intel MTRR architecture:
> */
> - if (!is_cpu(INTEL) || disable_mtrr_trim)
> + if (!is_cpu(INTEL) || disable_mtrr_trim || !mtrr_enabled)
> return 0;
>
> rdmsr(MSR_MTRRdefType, def, dummy);
> diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
> index 09c82de..df321b2 100644
> --- a/arch/x86/kernel/cpu/mtrr/generic.c
> +++ b/arch/x86/kernel/cpu/mtrr/generic.c
> @@ -116,7 +116,8 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
> u8 prev_match, curr_match;
>
> *repeat = 0;
> - if (!mtrr_state_set)
> + /* generic_mtrr_ops is only set for generic_mtrr_ops */
> + if (!mtrr_state_set || !mtrr_enabled)
> return 0xFF;
>
> if (!mtrr_state.enabled)
> @@ -290,7 +291,7 @@ static void get_fixed_ranges(mtrr_type *frs)
>
> void mtrr_save_fixed_ranges(void *info)
> {
> - if (cpu_has_mtrr)
> + if (mtrr_enabled && cpu_has_mtrr)
> get_fixed_ranges(mtrr_state.fixed_ranges);
> }
>
> diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
> index d76f13d..e9e001a 100644
> --- a/arch/x86/kernel/cpu/mtrr/if.c
> +++ b/arch/x86/kernel/cpu/mtrr/if.c
> @@ -436,6 +436,9 @@ static int __init mtrr_if_init(void)
> {
> struct cpuinfo_x86 *c = &boot_cpu_data;
>
> + if (!mtrr_enabled)
> + return 0;
> +
> if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
> (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
> (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
> diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
> index ea5f363..7db9c47 100644
> --- a/arch/x86/kernel/cpu/mtrr/main.c
> +++ b/arch/x86/kernel/cpu/mtrr/main.c
> @@ -59,6 +59,7 @@
> #define MTRR_TO_PHYS_WC_OFFSET 1000
>
> u32 num_var_ranges;
> +int mtrr_enabled;
>
> unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
> static DEFINE_MUTEX(mtrr_mutex);
> @@ -84,6 +85,9 @@ static int have_wrcomb(void)
> {
> struct pci_dev *dev;
>
> + if (!mtrr_enabled)
> + return 0;
> +
> dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL);
> if (dev != NULL) {
> /*
> @@ -286,7 +290,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
> int i, replace, error;
> mtrr_type ltype;
>
> - if (!mtrr_if)
> + if (!mtrr_enabled)
> return -ENXIO;
>
> error = mtrr_if->validate_add_page(base, size, type);
> @@ -388,6 +392,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
>
> static int mtrr_check(unsigned long base, unsigned long size)
> {
> + if (!mtrr_enabled)
> + return -ENODEV;
> if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
> pr_warning("mtrr: size and base must be multiples of 4 kiB\n");
> pr_debug("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
> @@ -463,8 +469,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
> unsigned long lbase, lsize;
> int error = -EINVAL;
>
> - if (!mtrr_if)
> - return -ENXIO;
> + if (!mtrr_enabled)
> + return -ENODEV;
>
> max = num_var_ranges;
> /* No CPU hotplug when we change MTRR entries */
> @@ -523,6 +529,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
> */
> int mtrr_del(int reg, unsigned long base, unsigned long size)
> {
> + if (!mtrr_enabled)
> + return -ENODEV;
> if (mtrr_check(base, size))
> return -EINVAL;
> return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
> @@ -545,7 +553,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
> {
> int ret;
>
> - if (pat_enabled)
> + if (pat_enabled || !mtrr_enabled)
> return 0; /* Success! (We don't need to do anything.) */
>
> ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
> @@ -734,6 +742,7 @@ void __init mtrr_bp_init(void)
> }
>
> if (mtrr_if) {
> + mtrr_enabled = true;
> set_num_var_ranges();
> init_table();
> if (use_intel()) {
> @@ -744,12 +753,13 @@ void __init mtrr_bp_init(void)
> mtrr_if->set_all();
> }
> }
> - }
> + } else
> + pr_info("mtrr: system does not support MTRR\n");
'pr_warn' ?
> }
>
> void mtrr_ap_init(void)
> {
> - if (!use_intel() || mtrr_aps_delayed_init)
> + if (!use_intel() || mtrr_aps_delayed_init || !mtrr_enabled)
> return;
> /*
> * Ideally we should hold mtrr_mutex here to avoid mtrr entries
> @@ -774,6 +784,9 @@ void mtrr_save_state(void)
> {
> int first_cpu;
>
> + if (!mtrr_enabled)
> + return;
> +
> get_online_cpus();
> first_cpu = cpumask_first(cpu_online_mask);
> smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
> @@ -782,7 +795,7 @@ void mtrr_save_state(void)
>
> void set_mtrr_aps_delayed_init(void)
> {
> - if (!use_intel())
> + if (!use_intel() || !mtrr_enabled)
> return;
>
> mtrr_aps_delayed_init = true;
> @@ -810,7 +823,7 @@ void mtrr_aps_init(void)
>
> void mtrr_bp_restore(void)
> {
> - if (!use_intel())
> + if (!use_intel() || !mtrr_enabled)
> return;
>
> mtrr_if->set_all();
> @@ -818,7 +831,7 @@ void mtrr_bp_restore(void)
>
> static int __init mtrr_init_finialize(void)
> {
> - if (!mtrr_if)
> + if (!mtrr_enabled)
> return 0;
>
> if (use_intel()) {
> --
> 2.3.2.209.gd67f9d5.dirty
>
^ permalink raw reply
* Re: [PATCHv5 04/11] fbdev: ssd1307fb: Unify init code and obtain hw specific bits from DT
From: Thomas Niederprüm @ 2015-03-25 20:03 UTC (permalink / raw)
To: Maxime Ripard
Cc: plagnioj, tomi.valkeinen, kernel, shawn.guo, robh+dt, linux-fbdev,
linux-kernel
In-Reply-To: <20150324221428.GD23664@lukather>
Am Tue, 24 Mar 2015 15:14:28 -0700
schrieb Maxime Ripard <maxime.ripard@free-electrons.com>:
> On Tue, Mar 24, 2015 at 10:23:51PM +0100, Thomas Niederprüm wrote:
> > The 130X controllers are very similar from the configuration point
> > of view. The configuration registers for the SSD1305/6/7 are bit
> > identical (except the the VHCOM register and the the default values
> > for clock setup register). This patch unifies the init code of the
> > controller and adds hardware specific properties to DT that are
> > needed to correctly initialize the device.
> >
> > The SSD130X can be wired to the OLED panel in various ways. Even
> > for the same controller this wiring can differ from one display
> > module to another and can not be probed by software. The added DT
> > properties reflect these hardware decisions of the display module
> > manufacturer. The 'com-sequential', 'com-lrremap' and 'com-invdir'
> > values define different possibilities for the COM signals pin
> > configuration and readout direction of the video memory. The
> > 'segment-no-remap' allows the inversion of the memory-to-pin
> > mapping ultimately inverting the order of the controllers output
> > pins. The 'prechargepX' values need to be adapted according to the
> > capacitance of the OLEDs pixel cells.
> >
> > So far these hardware specific bits are hard coded in the init
> > code, making the driver usable only for one certain wiring of the
> > controller. This patch makes the driver usable with all possible
> > hardware setups, given a valid hw description in DT. If these
> > values are not set in DT the default values, as they are set in the
> > ssd1307 init code right now, are used. This implies that without
> > the corresponding DT property "segment-no-remap" the segment remap
> > of the ssd130X controller gets activated. Even though this is not
> > the default behaviour according to the datasheet it maintains
> > backward compatibility with older DTBs.
> >
> > Note that the SSD1306 does not seem to be using the configuration
> > written to the registers at all. Therefore this patch does not try
> > to maintain these values without changes in DT. For reference an
> > example is added to the DT bindings documentation that reproduces
> > the configuration that is set in the current init code.
> >
> > Signed-off-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
> > ---
> > .../devicetree/bindings/video/ssd1307fb.txt | 21 +++
> > drivers/video/fbdev/ssd1307fb.c | 192
> > ++++++++++++--------- 2 files changed, 134 insertions(+), 79
> > deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt
> > b/Documentation/devicetree/bindings/video/ssd1307fb.txt index
> > 7a12542..637690f 100644 ---
> > a/Documentation/devicetree/bindings/video/ssd1307fb.txt +++
> > b/Documentation/devicetree/bindings/video/ssd1307fb.txt @@ -15,6
> > +15,16 @@ Required properties:
> > Optional properties:
> > - reset-active-low: Is the reset gpio is active on physical low?
> > + - solomon,segment-no-remap: Display needs normal (non-inverted)
> > data column
> > + to segment mapping
> > + - solomon,com-sequential: Display uses sequential COM pin
> > configuration
> > + - solomon,com-lrremap: Display uses left-right COM pin remap
> > + - solomon,com-invdir: Display uses inverted COM pin scan
> > direction
> > + - solomon,com-offset: Number of the COM pin wired to the first
> > display line
> > + - solomon,prechargep1: Length of deselect period (phase 1) in
> > clock cycles.
> > + - solomon,prechargep2: Length of precharge period (phase 2) in
> > clock cycles.
> > + This needs to be the higher, the higher
> > the capacitance
> > + of the OLED's pixels is
> >
> > [0]: Documentation/devicetree/bindings/pwm/pwm.txt
> >
> > @@ -26,3 +36,14 @@ ssd1307: oled@3c {
> > reset-gpios = <&gpio2 7>;
> > reset-active-low;
> > };
> > +
> > +ssd1306: oled@3c {
> > + compatible = "solomon,ssd1306fb-i2c";
> > + reg = <0x3c>;
> > + pwms = <&pwm 4 3000>;
> > + reset-gpios = <&gpio2 7>;
> > + reset-active-low;
> > + solomon,com-lrremap;
> > + solomon,com-invdir;
> > + solomon,com-offset = <32>;
> > +};
> > diff --git a/drivers/video/fbdev/ssd1307fb.c
> > b/drivers/video/fbdev/ssd1307fb.c index 8d34c56..d16aad4 100644
> > --- a/drivers/video/fbdev/ssd1307fb.c
> > +++ b/drivers/video/fbdev/ssd1307fb.c
> > @@ -40,20 +40,34 @@
> >
> > struct ssd1307fb_par;
> >
> > -struct ssd1307fb_ops {
> > - int (*init)(struct ssd1307fb_par *);
> > - int (*remove)(struct ssd1307fb_par *);
> > +struct ssd1307fb_deviceinfo {
> > + u32 default_vcomh;
> > + u32 default_dclk_div;
> > + u32 default_dclk_frq;
> > + int need_pwm;
> > + int need_chargepump;
> > };
> >
> > struct ssd1307fb_par {
> > + u32 com_invdir;
> > + u32 com_lrremap;
> > + u32 com_offset;
> > + u32 com_seq;
> > + u32 contrast;
> > + u32 dclk_div;
> > + u32 dclk_frq;
> > + struct ssd1307fb_deviceinfo *device_info;
> > struct i2c_client *client;
> > u32 height;
> > struct fb_info *info;
> > - struct ssd1307fb_ops *ops;
> > u32 page_offset;
> > + u32 prechargep1;
> > + u32 prechargep2;
> > struct pwm_device *pwm;
> > u32 pwm_period;
> > int reset;
> > + u32 seg_remap;
> > + u32 vcomh;
> > u32 width;
> > };
> >
> > @@ -254,69 +268,46 @@ static struct fb_deferred_io ssd1307fb_defio
> > = { .deferred_io = ssd1307fb_deferred_io,
> > };
> >
> > -static int ssd1307fb_ssd1307_init(struct ssd1307fb_par *par)
> > +static int ssd1307fb_init(struct ssd1307fb_par *par)
> > {
> > int ret;
> > + u32 precharge, dclk, com_invdir, compins;
> >
> > - par->pwm = pwm_get(&par->client->dev, NULL);
> > - if (IS_ERR(par->pwm)) {
> > - dev_err(&par->client->dev, "Could not get PWM from
> > device tree!\n");
> > - return PTR_ERR(par->pwm);
> > - }
> > -
> > - par->pwm_period = pwm_get_period(par->pwm);
> > - /* Enable the PWM */
> > - pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
> > - pwm_enable(par->pwm);
> > -
> > - dev_dbg(&par->client->dev, "Using PWM%d with a %dns
> > period.\n",
> > - par->pwm->pwm, par->pwm_period);
> > -
> > - /* Map column 127 of the OLED to segment 0 */
> > - ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SEG_REMAP_ON);
> > - if (ret < 0)
> > - return ret;
> > -
> > - /* Turn on the display */
> > - ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_DISPLAY_ON);
> > - if (ret < 0)
> > - return ret;
> > -
> > - return 0;
> > -}
> > -
> > -static int ssd1307fb_ssd1307_remove(struct ssd1307fb_par *par)
> > -{
> > - pwm_disable(par->pwm);
> > - pwm_put(par->pwm);
> > - return 0;
> > -}
> > + if (par->device_info->need_pwm) {
> > + par->pwm = pwm_get(&par->client->dev, NULL);
> > + if (IS_ERR(par->pwm)) {
> > + dev_err(&par->client->dev, "Could not get
> > PWM from device tree!\n");
> > + return PTR_ERR(par->pwm);
> > + }
> >
> > -static struct ssd1307fb_ops ssd1307fb_ssd1307_ops = {
> > - .init = ssd1307fb_ssd1307_init,
> > - .remove = ssd1307fb_ssd1307_remove,
> > -};
> > + par->pwm_period = pwm_get_period(par->pwm);
> > + /* Enable the PWM */
> > + pwm_config(par->pwm, par->pwm_period / 2,
> > par->pwm_period);
> > + pwm_enable(par->pwm);
> >
> > -static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
> > -{
> > - int ret;
> > + dev_dbg(&par->client->dev, "Using PWM%d with a
> > %dns period.\n",
> > + par->pwm->pwm, par->pwm_period);
> > + };
> >
> > /* Set initial contrast */
> > ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
> > if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x7f);
> > - if (ret < 0)
> > - return ret;
> > -
> > - /* Set COM direction */
> > - ret = ssd1307fb_write_cmd(par->client, 0xc8);
> > + ret = ssd1307fb_write_cmd(par->client, par->contrast);
> > if (ret < 0)
> > return ret;
> >
> > /* Set segment re-map */
> > - ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SEG_REMAP_ON);
> > + if (par->seg_remap) {
> > + ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SEG_REMAP_ON);
> > + if (ret < 0)
> > + return ret;
> > + };
> > +
> > + /* Set COM direction */
> > + com_invdir = 0xc0 | (par->com_invdir & 0xf) << 3;
> > + ret = ssd1307fb_write_cmd(par->client, com_invdir);
> > if (ret < 0)
> > return ret;
> >
> > @@ -334,7 +325,7 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x20);
> > + ret = ssd1307fb_write_cmd(par->client, par->com_offset);
> > if (ret < 0)
> > return ret;
> >
> > @@ -343,7 +334,8 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0xf0);
> > + dclk = (par->dclk_div & 0xf) | (par->dclk_frq & 0xf) << 4;
> > + ret = ssd1307fb_write_cmd(par->client, dclk);
> > if (ret < 0)
> > return ret;
> >
> > @@ -352,7 +344,8 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x22);
> > + precharge = (par->prechargep1 & 0xf) | (par->prechargep2 &
> > 0xf) << 4;
> > + ret = ssd1307fb_write_cmd(par->client, precharge);
> > if (ret < 0)
> > return ret;
> >
> > @@ -361,7 +354,9 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x22);
> > + compins = 0x02 | (!par->com_seq & 0x1) << 4
> > + | (par->com_lrremap & 0x1) << 5;
> > + ret = ssd1307fb_write_cmd(par->client, compins);
> > if (ret < 0)
> > return ret;
> >
> > @@ -370,18 +365,20 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x49);
> > + ret = ssd1307fb_write_cmd(par->client, par->vcomh);
> > if (ret < 0)
> > return ret;
> >
> > - /* Turn on the DC-DC Charge Pump */
> > - ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_CHARGE_PUMP);
> > - if (ret < 0)
> > - return ret;
> > + if (par->device_info->need_chargepump) {
> > + /* Turn on the DC-DC Charge Pump */
> > + ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_CHARGE_PUMP);
> > + if (ret < 0)
> > + return ret;
> >
> > - ret = ssd1307fb_write_cmd(par->client, 0x14);
> > - if (ret < 0)
> > - return ret;
> > + ret = ssd1307fb_write_cmd(par->client, 0x14);
> > + if (ret < 0)
> > + return ret;
> > + };
> >
> > /* Switch to horizontal addressing mode */
> > ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SET_ADDRESS_MODE); @@ -393,6 +390,7 @@ static int
> > ssd1307fb_ssd1306_init(struct ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > + /* Set column range */
> > ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SET_COL_RANGE); if (ret < 0)
> > return ret;
> > @@ -405,6 +403,7 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) if (ret < 0)
> > return ret;
> >
> > + /* Set page range */
> > ret = ssd1307fb_write_cmd(par->client,
> > SSD1307FB_SET_PAGE_RANGE); if (ret < 0)
> > return ret;
> > @@ -426,18 +425,30 @@ static int ssd1307fb_ssd1306_init(struct
> > ssd1307fb_par *par) return 0;
> > }
> >
> > -static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = {
> > - .init = ssd1307fb_ssd1306_init,
> > +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
> > + .default_vcomh = 0x20,
> > + .default_dclk_div = 0,
>
> A division by 0 ?
default_dclk_div stores the bit value for the divider register. The
bit encodes the divider as follows: bit = (divider - 1). But I guess
your are right that it makes more sense to store the actual divider
here and just calculate the bit value when writing to the device.
>
> > + .default_dclk_frq = 8,
> > + .need_pwm = 0,
>
> You don't need to declare this field, its value will already be
> initialized to 0.
I wasn't sure whether this is necessarily the case. But your hint and
a bit more reading on initialization of static structs convinced me. I
will remove the unnecessary fields.
Thomas
^ permalink raw reply
* Re: [Xen-devel] [PATCH v1 04/47] pci: add pci_ioremap_wc_bar()
From: Konrad Rzeszutek Wilk @ 2015-03-25 20:03 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: luto, mingo, tglx, hpa, jgross, JBeulich, bp, suresh.b.siddha,
venkatesh.pallipadi, airlied, linux-fbdev, Antonino Daplas,
Daniel Vetter, Luis R. Rodriguez, x86, linux-kernel,
Tomi Valkeinen, xen-devel, Ingo Molnar,
Jean-Christophe Plagniol-Villard
In-Reply-To: <1426893517-2511-5-git-send-email-mcgrof@do-not-panic.com>
On Fri, Mar 20, 2015 at 04:17:54PM -0700, Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <mcgrof@suse.com>
>
> This lets drivers take advanate of PAT when available. This
s/advanate/advantage/
> should help with the transition of converting video drivers over
> to ioremap_wc() to help with the goal of eventually using
> _PAGE_CACHE_UC over _PAGE_CACHE_UC_MINUS on x86 on
> ioremap_nocache() (de33c442e)
Please mention the title of the patch too:
"x86 PAT: fix performance drop for glx, use UC minus for ioremap(), ioremap_nocache() and pci_mmap_page_range()"
>
> Cc: Suresh Siddha <suresh.b.siddha@intel.com>
> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Juergen Gross <jgross@suse.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Andy Lutomirski <luto@amacapital.net>
> Cc: Dave Airlie <airlied@redhat.com>
> Cc: Antonino Daplas <adaplas@gmail.com>
> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
> ---
> drivers/pci/pci.c | 14 ++++++++++++++
> include/linux/pci.h | 1 +
> 2 files changed, 15 insertions(+)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 81f06e8..6afd507 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -137,6 +137,20 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
> pci_resource_len(pdev, bar));
> }
> EXPORT_SYMBOL_GPL(pci_ioremap_bar);
> +
> +void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
> +{
> + /*
> + * Make sure the BAR is actually a memory resource, not an IO resource
> + */
> + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
> + WARN_ON(1);
Would it be better to use dev_warn ? That way you can see which BDF it is?
Thought WARN will give a nice stack-trace that should easily point to the
driver so perhaps not.. Either way - up to you.
> + return NULL;
> + }
> + return ioremap_wc(pci_resource_start(pdev, bar),
> + pci_resource_len(pdev, bar));
> +}
> +EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
> #endif
>
> #define PCI_FIND_CAP_TTL 48
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 211e9da..c235b09 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1667,6 +1667,7 @@ static inline void pci_mmcfg_late_init(void) { }
> int pci_ext_cfg_avail(void);
>
> void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
> +void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar);
>
> #ifdef CONFIG_PCI_IOV
> int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
> --
> 2.3.2.209.gd67f9d5.dirty
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
^ permalink raw reply
* Re: [PATCH v1 04/47] pci: add pci_ioremap_wc_bar()
From: Luis R. Rodriguez @ 2015-03-25 20:06 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Luis R. Rodriguez, Ingo Molnar, Thomas Gleixner, H. Peter Anvin,
Juergen Gross, Jan Beulich, Borislav Petkov, Suresh Siddha,
venkatesh.pallipadi, Dave Airlie, linux-kernel@vger.kernel.org,
Linux Fbdev development list, X86 ML,
xen-devel@lists.xenproject.org, Ingo Molnar, Daniel Vetter,
Antonino Daplas, Jean-Christophe Plagniol-Villard, Tomi Valkeinen
In-Reply-To: <CALCETrXkZipqdY_faY+JOyuqcQKerk_CKH90ChDLTgCJPMKLug@mail.gmail.com>
On Fri, Mar 20, 2015 at 04:50:32PM -0700, Andy Lutomirski wrote:
> On Fri, Mar 20, 2015 at 4:17 PM, Luis R. Rodriguez
> <mcgrof@do-not-panic.com> wrote:
> > From: "Luis R. Rodriguez" <mcgrof@suse.com>
> >
> > This lets drivers take advanate of PAT when available. This
> > should help with the transition of converting video drivers over
> > to ioremap_wc() to help with the goal of eventually using
> > _PAGE_CACHE_UC over _PAGE_CACHE_UC_MINUS on x86 on
> > ioremap_nocache() (de33c442e)
> >
> > Cc: Suresh Siddha <suresh.b.siddha@intel.com>
> > Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
> > Cc: Ingo Molnar <mingo@elte.hu>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Juergen Gross <jgross@suse.com>
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Cc: Andy Lutomirski <luto@amacapital.net>
> > Cc: Dave Airlie <airlied@redhat.com>
> > Cc: Antonino Daplas <adaplas@gmail.com>
> > Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> > Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > Cc: linux-fbdev@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> > Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
> > ---
> > drivers/pci/pci.c | 14 ++++++++++++++
> > include/linux/pci.h | 1 +
> > 2 files changed, 15 insertions(+)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index 81f06e8..6afd507 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -137,6 +137,20 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
> > pci_resource_len(pdev, bar));
> > }
> > EXPORT_SYMBOL_GPL(pci_ioremap_bar);
> > +
> > +void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
> > +{
> > + /*
> > + * Make sure the BAR is actually a memory resource, not an IO resource
> > + */
> > + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
> > + WARN_ON(1);
> > + return NULL;
> > + }
>
> if (WARN_ON(...))?
Sure, they are equivalent however this follows the same exact style as
pci_ioremap_bar() so if we change this one might as well change the style of
pci_ioremap_bar() as well. Let me know if there is any preference. I personally
don't mind the extra line as it shortens the check.
Luis
^ permalink raw reply
* Re: [PATCH v1 05/47] pci: add pci_iomap_wc() variants
From: Konrad Rzeszutek Wilk @ 2015-03-25 20:07 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: luto, mingo, tglx, hpa, jgross, JBeulich, bp, suresh.b.siddha,
venkatesh.pallipadi, airlied, linux-kernel, linux-fbdev, x86,
xen-devel, Luis R. Rodriguez, Ingo Molnar, Daniel Vetter,
Bjorn Helgaas, Antonino Daplas, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, Dave Hansen, Arnd Bergmann, Michael S. Tsirkin,
Stefan Bader, ville.syrjala, david.vrabel, toshi.kani,
Roger Pau Monné, xen-devel
In-Reply-To: <1426893517-2511-6-git-send-email-mcgrof@do-not-panic.com>
On Fri, Mar 20, 2015 at 04:17:55PM -0700, Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <mcgrof@suse.com>
>
> This allows drivers to take advantage of write-combining
> when possible. Ideally we'd have pci_read_bases() just
> peg an IORESOURCE_WC flag for us but where exactly
> video devices memory lie varies *largely* and at times things
> are mixed with MMIO registers, sometimes we can address
> the changes in drivers, other times the change requires
> intrusive changes.
>
> Although there is also arch_phys_wc_add() that makes use of
> architecture specific write-combinging alternatives (MTRR on
combinging?
> x86 when a system does not have PAT) we void polluting
> pci_iomap() space with it and force drivers and subsystems
> that want to use it to be explicit.
>
> There are a few motivations for this:
>
> a) Take advantage of PAT when available
>
> b) Help bury MTRR code away, MTRR is architecture specific and on
> x86 its replaced by PAT
>
> c) Help with the goal of eventually using _PAGE_CACHE_UC over
> _PAGE_CACHE_UC_MINUS on x86 on ioremap_nocache() (de33c442e)
>
> Cc: Andy Lutomirski <luto@amacapital.net>
> Cc: Suresh Siddha <suresh.b.siddha@intel.com>
> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Juergen Gross <jgross@suse.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Dave Airlie <airlied@redhat.com>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: Antonino Daplas <adaplas@gmail.com>
> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: venkatesh.pallipadi@intel.com
> Cc: Stefan Bader <stefan.bader@canonical.com>
> Cc: konrad.wilk@oracle.com
> Cc: ville.syrjala@linux.intel.com
> Cc: david.vrabel@citrix.com
> Cc: jbeulich@suse.com
> Cc: toshi.kani@hp.com
> Cc: Roger Pau Monné <roger.pau@citrix.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: xen-devel@lists.xensource.com
> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
> ---
> include/asm-generic/pci_iomap.h | 14 ++++++++++
> lib/pci_iomap.c | 61 +++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 75 insertions(+)
>
> diff --git a/include/asm-generic/pci_iomap.h b/include/asm-generic/pci_iomap.h
> index 7389c87..b1e17fc 100644
> --- a/include/asm-generic/pci_iomap.h
> +++ b/include/asm-generic/pci_iomap.h
> @@ -15,9 +15,13 @@ struct pci_dev;
> #ifdef CONFIG_PCI
> /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
> extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
> +extern void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max);
> extern void __iomem *pci_iomap_range(struct pci_dev *dev, int bar,
> unsigned long offset,
> unsigned long maxlen);
> +extern void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar,
> + unsigned long offset,
> + unsigned long maxlen);
> /* Create a virtual mapping cookie for a port on a given PCI device.
> * Do not call this directly, it exists to make it easier for architectures
> * to override */
> @@ -34,12 +38,22 @@ static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned lon
> return NULL;
> }
>
> +static inline void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max)
> +{
> + return NULL;
> +}
> static inline void __iomem *pci_iomap_range(struct pci_dev *dev, int bar,
> unsigned long offset,
> unsigned long maxlen)
> {
> return NULL;
> }
> +static inline void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar,
> + unsigned long offset,
> + unsigned long maxlen)
> +{
> + return NULL;
> +}
> #endif
>
> #endif /* __ASM_GENERIC_IO_H */
> diff --git a/lib/pci_iomap.c b/lib/pci_iomap.c
> index bcce5f1..30b65ae 100644
> --- a/lib/pci_iomap.c
> +++ b/lib/pci_iomap.c
> @@ -52,6 +52,46 @@ void __iomem *pci_iomap_range(struct pci_dev *dev,
> EXPORT_SYMBOL(pci_iomap_range);
>
> /**
> + * pci_iomap_wc_range - create a virtual WC mapping cookie for a PCI BAR
> + * @dev: PCI device that owns the BAR
> + * @bar: BAR number
> + * @offset: map memory at the given offset in BAR
> + * @maxlen: max length of the memory to map
> + *
> + * Using this function you will get a __iomem address to your device BAR.
> + * You can access it using ioread*() and iowrite*(). These functions hide
> + * the details if this is a MMIO or PIO address space and will just do what
> + * you expect from them in the correct way. When possible write combining
> + * is used.
> + *
> + * @maxlen specifies the maximum length to map. If you want to get access to
> + * the complete BAR from offset to the end, pass %0 here.
s/%0/0 ? Or is that some special syntax?
> + * */
> +void __iomem *pci_iomap_wc_range(struct pci_dev *dev,
> + int bar,
> + unsigned long offset,
> + unsigned long maxlen)
> +{
> + resource_size_t start = pci_resource_start(dev, bar);
> + resource_size_t len = pci_resource_len(dev, bar);
> + unsigned long flags = pci_resource_flags(dev, bar);
> +
> + if (len <= offset || !start)
> + return NULL;
> + len -= offset;
> + start += offset;
> + if (maxlen && len > maxlen)
> + len = maxlen;
> + if (flags & IORESOURCE_IO)
> + return __pci_ioport_map(dev, start, len);
> + if (flags & IORESOURCE_MEM)
> + return ioremap_wc(start, len);
> + /* What? */
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(pci_iomap_wc_range);
> +
> +/**
> * pci_iomap - create a virtual mapping cookie for a PCI BAR
> * @dev: PCI device that owns the BAR
> * @bar: BAR number
> @@ -70,4 +110,25 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
> return pci_iomap_range(dev, bar, 0, maxlen);
> }
> EXPORT_SYMBOL(pci_iomap);
> +
> +/**
> + * pci_iomap_wc - create a virtual WC mapping cookie for a PCI BAR
> + * @dev: PCI device that owns the BAR
> + * @bar: BAR number
> + * @maxlen: length of the memory to map
> + *
> + * Using this function you will get a __iomem address to your device BAR.
> + * You can access it using ioread*() and iowrite*(). These functions hide
> + * the details if this is a MMIO or PIO address space and will just do what
> + * you expect from them in the correct way. When possible write combining
> + * is used.
> + *
> + * @maxlen specifies the maximum length to map. If you want to get access to
> + * the complete BAR without checking for its length first, pass %0 here.
> + * */
> +void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
> +{
> + return pci_iomap_wc_range(dev, bar, 0, maxlen);
> +}
> +EXPORT_SYMBOL_GPL(pci_iomap_wc);
> #endif /* CONFIG_PCI */
> --
> 2.3.2.209.gd67f9d5.dirty
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox