Version Bump
This commit is contained in:
parent
c2eb96088a
commit
6562b2c3c3
@ -1,3 +1,5 @@
|
|||||||
DIST all-5.15.6.patch 15465054 BLAKE2B e60ee46d00f0d2a82c491431366e96650b08050e64bc5a751961a7f7d465735250bdc2b26832fc1f0a6a21da1d7c5e87d119359a02c9e175201af5750f8e50f4 SHA512 6499b9f8b5575ca3ab21a28ec5a9c9bd0bcecfec54b90cf7dac1f2c9e818f0a5804a7389f37e6220661210f7ecc80da3cfd3b2c218d29c0d10bb9066c68aa802
|
DIST all-5.15.6.patch 15465054 BLAKE2B e60ee46d00f0d2a82c491431366e96650b08050e64bc5a751961a7f7d465735250bdc2b26832fc1f0a6a21da1d7c5e87d119359a02c9e175201af5750f8e50f4 SHA512 6499b9f8b5575ca3ab21a28ec5a9c9bd0bcecfec54b90cf7dac1f2c9e818f0a5804a7389f37e6220661210f7ecc80da3cfd3b2c218d29c0d10bb9066c68aa802
|
||||||
|
DIST all-5.16.0.patch 15386424 BLAKE2B 4ddf492fedab9dde02e9e3fbfdaaa8c31f3c4ed0267447cd38eb2ede38a4ed44255d6b0972cdca9c440c30031196e35e0b2c00cbadd8ee09a67d7375d24db633 SHA512 fc337e97242c206337f4aa88075a1a850e404ac09c566c06fa42de268d83c58ab9ee3052a0510246023b1e073aced8c88d605bd49a11983cc3716058814926a5
|
||||||
DIST linux-5.15.tar.xz 121913744 BLAKE2B 3921274b23f7938abdf3ed9334534b4581e13d7484303d3a5280eddb038999aaa8b836666a487472d9c4a219af0f06b9fecccaf348fb5510ab8762f4ef4b7e83 SHA512 d25ad40b5bcd6a4c6042fd0fd84e196e7a58024734c3e9a484fd0d5d54a0c1d87db8a3c784eff55e43b6f021709dc685eb0efa18d2aec327e4f88a79f405705a
|
DIST linux-5.15.tar.xz 121913744 BLAKE2B 3921274b23f7938abdf3ed9334534b4581e13d7484303d3a5280eddb038999aaa8b836666a487472d9c4a219af0f06b9fecccaf348fb5510ab8762f4ef4b7e83 SHA512 d25ad40b5bcd6a4c6042fd0fd84e196e7a58024734c3e9a484fd0d5d54a0c1d87db8a3c784eff55e43b6f021709dc685eb0efa18d2aec327e4f88a79f405705a
|
||||||
|
DIST linux-5.16.tar.xz 123114100 BLAKE2B 07a90cc640ff89e1359c06cee8c38abd33e51f9b9a89833e31a1d2750526fda4a59e8884db3c1ea63df0a37f0d3de6b5a922b014b7313d8abce20d90ac08adcb SHA512 7a257dd576bc8493595ec7d6f3c9cb6e22c772a8b2dbe735d2485c4f5c56e26a08695546e7e0f1f1cd04a533f25e829361958d4da0b98bf0ba8094dd57a85aaf
|
||||||
DIST patch-5.15.6.xz 430232 BLAKE2B ed3eb640ae8617ae726b9d98f3b17ab1602f733e228970826e4a34cb7e466b61ead5371f51e6bc1fc75bb9e468cfeca66c6bca21731f25b53decc52eb59ecb3e SHA512 926403406c82f4589bb872cb74ff21dc4729184a3dd5293ba0cc201c13a5c3917b231721be551a6f19fb1d93e443b8ebac557df2a9cc265967a693b4031cedb3
|
DIST patch-5.15.6.xz 430232 BLAKE2B ed3eb640ae8617ae726b9d98f3b17ab1602f733e228970826e4a34cb7e466b61ead5371f51e6bc1fc75bb9e468cfeca66c6bca21731f25b53decc52eb59ecb3e SHA512 926403406c82f4589bb872cb74ff21dc4729184a3dd5293ba0cc201c13a5c3917b231721be551a6f19fb1d93e443b8ebac557df2a9cc265967a693b4031cedb3
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 15 Nov 2021 04:09:50 +0100
|
|
||||||
Subject: [PATCH 01/36] base: property: Swap order of search for connection to
|
|
||||||
"devcon, graph"
|
|
||||||
|
|
||||||
This avoids confusing error in kernel log, when using devcon matching
|
|
||||||
in DT. Example:
|
|
||||||
|
|
||||||
"OF: graph: no port node found in /i2c@ff3d0000/typec-portc@22"
|
|
||||||
|
|
||||||
This suggest there's some error because graph based search failed,
|
|
||||||
but there is no error, because devcon based matching succeeds.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/base/property.c | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/base/property.c b/drivers/base/property.c
|
|
||||||
index f1f35b4..68cb945 100644
|
|
||||||
--- a/drivers/base/property.c
|
|
||||||
+++ b/drivers/base/property.c
|
|
||||||
@@ -1261,10 +1261,10 @@ void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
|
|
||||||
if (!fwnode || !match)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
- ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
|
|
||||||
+ ret = fwnode_devcon_match(fwnode, con_id, data, match);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
- return fwnode_devcon_match(fwnode, con_id, data, match);
|
|
||||||
+ return fwnode_graph_devcon_match(fwnode, con_id, data, match);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
|
|
@ -1,746 +0,0 @@
|
|||||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
||||||
index a74227ad082e..b5633b56391e 100644
|
|
||||||
--- a/MAINTAINERS
|
|
||||||
+++ b/MAINTAINERS
|
|
||||||
@@ -2705,6 +2705,14 @@ S: Supported
|
|
||||||
F: drivers/net/bonding/
|
|
||||||
F: include/uapi/linux/if_bonding.h
|
|
||||||
|
|
||||||
+BOOTSPLASH
|
|
||||||
+M: Max Staudt <mstaudt@suse.de>
|
|
||||||
+L: linux-fbdev@vger.kernel.org
|
|
||||||
+S: Maintained
|
|
||||||
+F: drivers/video/fbdev/core/bootsplash*.*
|
|
||||||
+F: drivers/video/fbdev/core/dummycon.c
|
|
||||||
+F: include/linux/bootsplash.h
|
|
||||||
+
|
|
||||||
BPF (Safe dynamic programs and tools)
|
|
||||||
M: Alexei Starovoitov <ast@kernel.org>
|
|
||||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
|
||||||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
|
|
||||||
index 7f1f1fbcef9e..f3ff976266fe 100644
|
|
||||||
--- a/drivers/video/console/Kconfig
|
|
||||||
+++ b/drivers/video/console/Kconfig
|
|
||||||
@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION
|
|
||||||
such that other users of the framebuffer will remain normally
|
|
||||||
oriented.
|
|
||||||
|
|
||||||
+config BOOTSPLASH
|
|
||||||
+ bool "Bootup splash screen"
|
|
||||||
+ depends on FRAMEBUFFER_CONSOLE
|
|
||||||
+ help
|
|
||||||
+ This option enables the Linux bootsplash screen.
|
|
||||||
+
|
|
||||||
+ The bootsplash is a full-screen logo or animation indicating a
|
|
||||||
+ booting system. It replaces the classic scrolling text with a
|
|
||||||
+ graphical alternative, similar to other systems.
|
|
||||||
+
|
|
||||||
+ Since this is technically implemented as a hook on top of fbcon,
|
|
||||||
+ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a
|
|
||||||
+ framebuffer driver is active. Thus, to get a text-free boot,
|
|
||||||
+ the system needs to boot with vesafb, efifb, or similar.
|
|
||||||
+
|
|
||||||
+ Once built into the kernel, the bootsplash needs to be enabled
|
|
||||||
+ with bootsplash.enabled=1 and a splash file needs to be supplied.
|
|
||||||
+
|
|
||||||
+ Further documentation can be found in:
|
|
||||||
+ Documentation/fb/bootsplash.txt
|
|
||||||
+
|
|
||||||
+ If unsure, say N.
|
|
||||||
+ This is typically used by distributors and system integrators.
|
|
||||||
+
|
|
||||||
config STI_CONSOLE
|
|
||||||
bool "STI text console"
|
|
||||||
depends on PARISC
|
|
||||||
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
|
|
||||||
index 73493bbd7a15..66895321928e 100644
|
|
||||||
--- a/drivers/video/fbdev/core/Makefile
|
|
||||||
+++ b/drivers/video/fbdev/core/Makefile
|
|
||||||
@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
|
|
||||||
obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
|
|
||||||
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
|
|
||||||
obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
|
||||||
+
|
|
||||||
+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
|
|
||||||
+ dummyblit.o
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..e449755af268
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -0,0 +1,294 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (Main file: Glue code, workers, timer, PM, kernel and userland API)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#include <linux/atomic.h>
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
+#include <linux/console.h>
|
|
||||||
+#include <linux/device.h> /* dev_warn() */
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+#include <linux/fs.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/jiffies.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/mutex.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/printk.h>
|
|
||||||
+#include <linux/selection.h> /* console_blanked */
|
|
||||||
+#include <linux/stringify.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/vmalloc.h>
|
|
||||||
+#include <linux/vt_kern.h>
|
|
||||||
+#include <linux/workqueue.h>
|
|
||||||
+
|
|
||||||
+#include "bootsplash_internal.h"
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * We only have one splash screen, so let's keep a single
|
|
||||||
+ * instance of the internal state.
|
|
||||||
+ */
|
|
||||||
+static struct splash_priv splash_state;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void splash_callback_redraw_vc(struct work_struct *ignored)
|
|
||||||
+{
|
|
||||||
+ if (console_blanked)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ console_lock();
|
|
||||||
+ if (vc_cons[fg_console].d)
|
|
||||||
+ update_screen(vc_cons[fg_console].d);
|
|
||||||
+ console_unlock();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static bool is_fb_compatible(const struct fb_info *info)
|
|
||||||
+{
|
|
||||||
+ if (!(info->flags & FBINFO_BE_MATH)
|
|
||||||
+ != !fb_be_math((struct fb_info *)info)) {
|
|
||||||
+ dev_warn(info->device,
|
|
||||||
+ "Can't draw on foreign endianness framebuffer.\n");
|
|
||||||
+
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (info->flags & FBINFO_MISC_TILEBLITTING) {
|
|
||||||
+ dev_warn(info->device,
|
|
||||||
+ "Can't draw splash on tiling framebuffer.\n");
|
|
||||||
+
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (info->fix.type != FB_TYPE_PACKED_PIXELS
|
|
||||||
+ || (info->fix.visual != FB_VISUAL_TRUECOLOR
|
|
||||||
+ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) {
|
|
||||||
+ dev_warn(info->device,
|
|
||||||
+ "Can't draw splash on non-packed or non-truecolor framebuffer.\n");
|
|
||||||
+
|
|
||||||
+ dev_warn(info->device,
|
|
||||||
+ " type: %u visual: %u\n",
|
|
||||||
+ info->fix.type, info->fix.visual);
|
|
||||||
+
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (info->var.bits_per_pixel != 16
|
|
||||||
+ && info->var.bits_per_pixel != 24
|
|
||||||
+ && info->var.bits_per_pixel != 32) {
|
|
||||||
+ dev_warn(info->device,
|
|
||||||
+ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n",
|
|
||||||
+ info->var.bits_per_pixel);
|
|
||||||
+
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return true;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Called by fbcon_switch() when an instance is activated or refreshed.
|
|
||||||
+ */
|
|
||||||
+void bootsplash_render_full(struct fb_info *info)
|
|
||||||
+{
|
|
||||||
+ if (!is_fb_compatible(info))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ bootsplash_do_render_background(info);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * External status enquiry and on/off switch
|
|
||||||
+ */
|
|
||||||
+bool bootsplash_would_render_now(void)
|
|
||||||
+{
|
|
||||||
+ return !oops_in_progress
|
|
||||||
+ && !console_blanked
|
|
||||||
+ && bootsplash_is_enabled();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+bool bootsplash_is_enabled(void)
|
|
||||||
+{
|
|
||||||
+ bool was_enabled;
|
|
||||||
+
|
|
||||||
+ /* Make sure we have the newest state */
|
|
||||||
+ smp_rmb();
|
|
||||||
+
|
|
||||||
+ was_enabled = test_bit(0, &splash_state.enabled);
|
|
||||||
+
|
|
||||||
+ return was_enabled;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void bootsplash_disable(void)
|
|
||||||
+{
|
|
||||||
+ int was_enabled;
|
|
||||||
+
|
|
||||||
+ was_enabled = test_and_clear_bit(0, &splash_state.enabled);
|
|
||||||
+
|
|
||||||
+ if (was_enabled) {
|
|
||||||
+ if (oops_in_progress) {
|
|
||||||
+ /* Redraw screen now so we can see a panic */
|
|
||||||
+ if (vc_cons[fg_console].d)
|
|
||||||
+ update_screen(vc_cons[fg_console].d);
|
|
||||||
+ } else {
|
|
||||||
+ /* No urgency, redraw at next opportunity */
|
|
||||||
+ schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void bootsplash_enable(void)
|
|
||||||
+{
|
|
||||||
+ bool was_enabled;
|
|
||||||
+
|
|
||||||
+ if (oops_in_progress)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ was_enabled = test_and_set_bit(0, &splash_state.enabled);
|
|
||||||
+
|
|
||||||
+ if (!was_enabled)
|
|
||||||
+ schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Userland API via platform device in sysfs
|
|
||||||
+ */
|
|
||||||
+static ssize_t splash_show_enabled(struct device *dev,
|
|
||||||
+ struct device_attribute *attr, char *buf)
|
|
||||||
+{
|
|
||||||
+ return sprintf(buf, "%d\n", bootsplash_is_enabled());
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static ssize_t splash_store_enabled(struct device *device,
|
|
||||||
+ struct device_attribute *attr,
|
|
||||||
+ const char *buf, size_t count)
|
|
||||||
+{
|
|
||||||
+ bool enable;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ if (!buf || !count)
|
|
||||||
+ return -EFAULT;
|
|
||||||
+
|
|
||||||
+ err = kstrtobool(buf, &enable);
|
|
||||||
+ if (err)
|
|
||||||
+ return err;
|
|
||||||
+
|
|
||||||
+ if (enable)
|
|
||||||
+ bootsplash_enable();
|
|
||||||
+ else
|
|
||||||
+ bootsplash_disable();
|
|
||||||
+
|
|
||||||
+ return count;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static struct attribute *splash_dev_attrs[] = {
|
|
||||||
+ &dev_attr_enabled.attr,
|
|
||||||
+ NULL
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+ATTRIBUTE_GROUPS(splash_dev);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Power management fixup via platform device
|
|
||||||
+ *
|
|
||||||
+ * When the system is woken from sleep or restored after hibernating, we
|
|
||||||
+ * cannot expect the screen contents to still be present in video RAM.
|
|
||||||
+ * Thus, we have to redraw the splash if we're currently active.
|
|
||||||
+ */
|
|
||||||
+static int splash_resume(struct device *device)
|
|
||||||
+{
|
|
||||||
+ if (bootsplash_would_render_now())
|
|
||||||
+ schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int splash_suspend(struct device *device)
|
|
||||||
+{
|
|
||||||
+ cancel_work_sync(&splash_state.work_redraw_vc);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static const struct dev_pm_ops splash_pm_ops = {
|
|
||||||
+ .thaw = splash_resume,
|
|
||||||
+ .restore = splash_resume,
|
|
||||||
+ .resume = splash_resume,
|
|
||||||
+ .suspend = splash_suspend,
|
|
||||||
+ .freeze = splash_suspend,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct platform_driver splash_driver = {
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "bootsplash",
|
|
||||||
+ .pm = &splash_pm_ops,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Main init
|
|
||||||
+ */
|
|
||||||
+void bootsplash_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ /* Initialized already? */
|
|
||||||
+ if (splash_state.splash_device)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Register platform device to export user API */
|
|
||||||
+ ret = platform_driver_register(&splash_driver);
|
|
||||||
+ if (ret) {
|
|
||||||
+ pr_err("platform_driver_register() failed: %d\n", ret);
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ splash_state.splash_device
|
|
||||||
+ = platform_device_alloc("bootsplash", 0);
|
|
||||||
+
|
|
||||||
+ if (!splash_state.splash_device)
|
|
||||||
+ goto err_driver;
|
|
||||||
+
|
|
||||||
+ splash_state.splash_device->dev.groups = splash_dev_groups;
|
|
||||||
+
|
|
||||||
+ ret = platform_device_add(splash_state.splash_device);
|
|
||||||
+ if (ret) {
|
|
||||||
+ pr_err("platform_device_add() failed: %d\n", ret);
|
|
||||||
+ goto err_device;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
|
||||||
+
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+err_device:
|
|
||||||
+ platform_device_put(splash_state.splash_device);
|
|
||||||
+ splash_state.splash_device = NULL;
|
|
||||||
+err_driver:
|
|
||||||
+ platform_driver_unregister(&splash_driver);
|
|
||||||
+err:
|
|
||||||
+ pr_err("Failed to initialize.\n");
|
|
||||||
+}
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..b11da5cb90bf
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
@@ -0,0 +1,55 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (Internal data structures used at runtime)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef __BOOTSPLASH_INTERNAL_H
|
|
||||||
+#define __BOOTSPLASH_INTERNAL_H
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/mutex.h>
|
|
||||||
+#include <linux/spinlock.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Runtime types
|
|
||||||
+ */
|
|
||||||
+struct splash_priv {
|
|
||||||
+ /*
|
|
||||||
+ * Enabled/disabled state, to be used with atomic bit operations.
|
|
||||||
+ * Bit 0: 0 = Splash hidden
|
|
||||||
+ * 1 = Splash shown
|
|
||||||
+ *
|
|
||||||
+ * Note: fbcon.c uses this twice, by calling
|
|
||||||
+ * bootsplash_would_render_now() in set_blitting_type() and
|
|
||||||
+ * in fbcon_switch().
|
|
||||||
+ * This is racy, but eventually consistent: Turning the
|
|
||||||
+ * splash on/off will cause a redraw, which calls
|
|
||||||
+ * fbcon_switch(), which calls set_blitting_type().
|
|
||||||
+ * So the last on/off toggle will make things consistent.
|
|
||||||
+ */
|
|
||||||
+ unsigned long enabled;
|
|
||||||
+
|
|
||||||
+ /* Our gateway to userland via sysfs */
|
|
||||||
+ struct platform_device *splash_device;
|
|
||||||
+
|
|
||||||
+ struct work_struct work_redraw_vc;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Rendering functions
|
|
||||||
+ */
|
|
||||||
+void bootsplash_do_render_background(struct fb_info *info);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..4d7e0117f653
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
@@ -0,0 +1,93 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (Rendering functions)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/printk.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+
|
|
||||||
+#include "bootsplash_internal.h"
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Rendering: Internal drawing routines
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Pack pixel into target format and do Big/Little Endian handling.
|
|
||||||
+ * This would be a good place to handle endianness conversion if necessary.
|
|
||||||
+ */
|
|
||||||
+static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
|
|
||||||
+ u8 red, u8 green, u8 blue)
|
|
||||||
+{
|
|
||||||
+ u32 dstpix;
|
|
||||||
+
|
|
||||||
+ /* Quantize pixel */
|
|
||||||
+ red = red >> (8 - dst_var->red.length);
|
|
||||||
+ green = green >> (8 - dst_var->green.length);
|
|
||||||
+ blue = blue >> (8 - dst_var->blue.length);
|
|
||||||
+
|
|
||||||
+ /* Pack pixel */
|
|
||||||
+ dstpix = red << (dst_var->red.offset)
|
|
||||||
+ | green << (dst_var->green.offset)
|
|
||||||
+ | blue << (dst_var->blue.offset);
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Move packed pixel to the beginning of the memory cell,
|
|
||||||
+ * so we can memcpy() it out easily
|
|
||||||
+ */
|
|
||||||
+#ifdef __BIG_ENDIAN
|
|
||||||
+ switch (dst_var->bits_per_pixel) {
|
|
||||||
+ case 16:
|
|
||||||
+ dstpix <<= 16;
|
|
||||||
+ break;
|
|
||||||
+ case 24:
|
|
||||||
+ dstpix <<= 8;
|
|
||||||
+ break;
|
|
||||||
+ case 32:
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+#else
|
|
||||||
+ /* This is intrinsically unnecessary on Little Endian */
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+ return dstpix;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_do_render_background(struct fb_info *info)
|
|
||||||
+{
|
|
||||||
+ unsigned int x, y;
|
|
||||||
+ u32 dstpix;
|
|
||||||
+ u32 dst_octpp = info->var.bits_per_pixel / 8;
|
|
||||||
+
|
|
||||||
+ dstpix = pack_pixel(&info->var,
|
|
||||||
+ 0,
|
|
||||||
+ 0,
|
|
||||||
+ 0);
|
|
||||||
+
|
|
||||||
+ for (y = 0; y < info->var.yres_virtual; y++) {
|
|
||||||
+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
|
|
||||||
+
|
|
||||||
+ for (x = 0; x < info->var.xres_virtual; x++) {
|
|
||||||
+ memcpy(dstline, &dstpix, dst_octpp);
|
|
||||||
+
|
|
||||||
+ dstline += dst_octpp;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..8c22ff92ce24
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/video/fbdev/core/dummyblit.c
|
|
||||||
@@ -0,0 +1,89 @@
|
|
||||||
+/*
|
|
||||||
+ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * These functions are used in place of blitblit/tileblit to suppress
|
|
||||||
+ * fbcon's text output while a splash is shown.
|
|
||||||
+ *
|
|
||||||
+ * Only suppressing actual rendering keeps the text buffer in the VC layer
|
|
||||||
+ * intact and makes it easy to switch back from the bootsplash to a full
|
|
||||||
+ * text console with a simple redraw (with the original functions in place).
|
|
||||||
+ *
|
|
||||||
+ * Based on linux/drivers/video/fbdev/core/bitblit.c
|
|
||||||
+ * and linux/drivers/video/fbdev/core/tileblit.c
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+#include <linux/vt_kern.h>
|
|
||||||
+#include <linux/console.h>
|
|
||||||
+#include <asm/types.h>
|
|
||||||
+#include "fbcon.h"
|
|
||||||
+
|
|
||||||
+static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
|
||||||
+ int sx, int dy, int dx, int height, int width)
|
|
||||||
+{
|
|
||||||
+ ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
|
||||||
+ int sx, int height, int width)
|
|
||||||
+{
|
|
||||||
+ ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dummy_putcs(struct vc_data *vc, struct fb_info *info,
|
|
||||||
+ const unsigned short *s, int count, int yy, int xx,
|
|
||||||
+ int fg, int bg)
|
|
||||||
+{
|
|
||||||
+ ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info,
|
|
||||||
+ int color, int bottom_only)
|
|
||||||
+{
|
|
||||||
+ ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
+{
|
|
||||||
+ ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int dummy_update_start(struct fb_info *info)
|
|
||||||
+{
|
|
||||||
+ /*
|
|
||||||
+ * Copied from bitblit.c and tileblit.c
|
|
||||||
+ *
|
|
||||||
+ * As of Linux 4.12, nobody seems to care about our return value.
|
|
||||||
+ */
|
|
||||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = fb_pan_display(info, &ops->var);
|
|
||||||
+ ops->var.xoffset = info->var.xoffset;
|
|
||||||
+ ops->var.yoffset = info->var.yoffset;
|
|
||||||
+ ops->var.vmode = info->var.vmode;
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void fbcon_set_dummyops(struct fbcon_ops *ops)
|
|
||||||
+{
|
|
||||||
+ ops->bmove = dummy_bmove;
|
|
||||||
+ ops->clear = dummy_clear;
|
|
||||||
+ ops->putcs = dummy_putcs;
|
|
||||||
+ ops->clear_margins = dummy_clear_margins;
|
|
||||||
+ ops->cursor = dummy_cursor;
|
|
||||||
+ ops->update_start = dummy_update_start;
|
|
||||||
+ ops->rotate_font = NULL;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(fbcon_set_dummyops);
|
|
||||||
+
|
|
||||||
+MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>");
|
|
||||||
+MODULE_DESCRIPTION("Dummy Blitting Operation");
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
index 04612f938bab..9a39a6fcfe98 100644
|
|
||||||
--- a/drivers/video/fbdev/core/fbcon.c
|
|
||||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
@@ -80,6 +80,7 @@
|
|
||||||
#include <asm/irq.h>
|
|
||||||
|
|
||||||
#include "fbcon.h"
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
|
|
||||||
#ifdef FBCONDEBUG
|
|
||||||
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
|
|
||||||
@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo)
|
|
||||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
|
||||||
con2fb_map[i] = info_idx;
|
|
||||||
|
|
||||||
+ bootsplash_init();
|
|
||||||
+
|
|
||||||
err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
|
|
||||||
fbcon_is_default);
|
|
||||||
|
|
||||||
@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
|
||||||
else {
|
|
||||||
fbcon_set_rotation(info);
|
|
||||||
fbcon_set_bitops(ops);
|
|
||||||
+
|
|
||||||
+ if (bootsplash_would_render_now())
|
|
||||||
+ fbcon_set_dummyops(ops);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
|
||||||
ops->p = &fb_display[vc->vc_num];
|
|
||||||
fbcon_set_rotation(info);
|
|
||||||
fbcon_set_bitops(ops);
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Note:
|
|
||||||
+ * This is *eventually correct*.
|
|
||||||
+ * Setting the fbcon operations and drawing the splash happen at
|
|
||||||
+ * different points in time. If the splash is enabled/disabled
|
|
||||||
+ * in between, then bootsplash_{en,dis}able will schedule a
|
|
||||||
+ * redraw, which will again render the splash (or not) and set
|
|
||||||
+ * the correct fbcon ops.
|
|
||||||
+ * The last run will then be the right one.
|
|
||||||
+ */
|
|
||||||
+ if (bootsplash_would_render_now())
|
|
||||||
+ fbcon_set_dummyops(ops);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
|
|
||||||
@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc)
|
|
||||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
|
||||||
ops = info->fbcon_par;
|
|
||||||
|
|
||||||
+ if (bootsplash_would_render_now())
|
|
||||||
+ bootsplash_render_full(info);
|
|
||||||
+
|
|
||||||
if (softback_top) {
|
|
||||||
if (softback_lines)
|
|
||||||
fbcon_set_origin(vc);
|
|
||||||
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
|
|
||||||
index 18f3ac144237..45f94347fe5e 100644
|
|
||||||
--- a/drivers/video/fbdev/core/fbcon.h
|
|
||||||
+++ b/drivers/video/fbdev/core/fbcon.h
|
|
||||||
@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
|
|
||||||
#define SCROLL_REDRAW 0x004
|
|
||||||
#define SCROLL_PAN_REDRAW 0x005
|
|
||||||
|
|
||||||
+#ifdef CONFIG_BOOTSPLASH
|
|
||||||
+extern void fbcon_set_dummyops(struct fbcon_ops *ops);
|
|
||||||
+#else /* CONFIG_BOOTSPLASH */
|
|
||||||
+#define fbcon_set_dummyops(x)
|
|
||||||
+#endif /* CONFIG_BOOTSPLASH */
|
|
||||||
#ifdef CONFIG_FB_TILEBLITTING
|
|
||||||
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
|
|
||||||
#endif
|
|
||||||
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..c6dd0b43180d
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/include/linux/bootsplash.h
|
|
||||||
@@ -0,0 +1,43 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef __LINUX_BOOTSPLASH_H
|
|
||||||
+#define __LINUX_BOOTSPLASH_H
|
|
||||||
+
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_BOOTSPLASH
|
|
||||||
+
|
|
||||||
+extern void bootsplash_render_full(struct fb_info *info);
|
|
||||||
+
|
|
||||||
+extern bool bootsplash_would_render_now(void);
|
|
||||||
+
|
|
||||||
+extern bool bootsplash_is_enabled(void);
|
|
||||||
+extern void bootsplash_disable(void);
|
|
||||||
+extern void bootsplash_enable(void);
|
|
||||||
+
|
|
||||||
+extern void bootsplash_init(void);
|
|
||||||
+
|
|
||||||
+#else /* CONFIG_BOOTSPLASH */
|
|
||||||
+
|
|
||||||
+#define bootsplash_render_full(x)
|
|
||||||
+
|
|
||||||
+#define bootsplash_would_render_now() (false)
|
|
||||||
+
|
|
||||||
+#define bootsplash_is_enabled() (false)
|
|
||||||
+#define bootsplash_disable()
|
|
||||||
+#define bootsplash_enable()
|
|
||||||
+
|
|
||||||
+#define bootsplash_init()
|
|
||||||
+
|
|
||||||
+#endif /* CONFIG_BOOTSPLASH */
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#endif
|
|
File diff suppressed because it is too large
Load Diff
@ -1,669 +0,0 @@
|
|||||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
||||||
index b5633b56391e..5c237445761e 100644
|
|
||||||
--- a/MAINTAINERS
|
|
||||||
+++ b/MAINTAINERS
|
|
||||||
@@ -2712,6 +2712,7 @@ S: Maintained
|
|
||||||
F: drivers/video/fbdev/core/bootsplash*.*
|
|
||||||
F: drivers/video/fbdev/core/dummycon.c
|
|
||||||
F: include/linux/bootsplash.h
|
|
||||||
+F: include/uapi/linux/bootsplash_file.h
|
|
||||||
|
|
||||||
BPF (Safe dynamic programs and tools)
|
|
||||||
M: Alexei Starovoitov <ast@kernel.org>
|
|
||||||
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
|
|
||||||
index 66895321928e..6a8d1bab8a01 100644
|
|
||||||
--- a/drivers/video/fbdev/core/Makefile
|
|
||||||
+++ b/drivers/video/fbdev/core/Makefile
|
|
||||||
@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
|
|
||||||
obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
|
|
||||||
- dummyblit.o
|
|
||||||
+ bootsplash_load.o dummyblit.o
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
index e449755af268..843c5400fefc 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -32,6 +32,7 @@
|
|
||||||
#include <linux/workqueue.h>
|
|
||||||
|
|
||||||
#include "bootsplash_internal.h"
|
|
||||||
+#include "uapi/linux/bootsplash_file.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
|
|
||||||
*/
|
|
||||||
void bootsplash_render_full(struct fb_info *info)
|
|
||||||
{
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
if (!is_fb_compatible(info))
|
|
||||||
- return;
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ bootsplash_do_render_background(info, splash_state.file);
|
|
||||||
+
|
|
||||||
+ bootsplash_do_render_pictures(info, splash_state.file);
|
|
||||||
|
|
||||||
- bootsplash_do_render_background(info);
|
|
||||||
+out:
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
|
|
||||||
{
|
|
||||||
return !oops_in_progress
|
|
||||||
&& !console_blanked
|
|
||||||
+ && splash_state.file
|
|
||||||
&& bootsplash_is_enabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
|
|
||||||
void bootsplash_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
+ struct splash_file_priv *fp;
|
|
||||||
|
|
||||||
/* Initialized already? */
|
|
||||||
if (splash_state.splash_device)
|
|
||||||
@@ -280,8 +290,26 @@ void bootsplash_init(void)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+ mutex_init(&splash_state.data_lock);
|
|
||||||
+ set_bit(0, &splash_state.enabled);
|
|
||||||
+
|
|
||||||
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
|
||||||
|
|
||||||
+
|
|
||||||
+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
|
|
||||||
+ splash_state.bootfile);
|
|
||||||
+
|
|
||||||
+ if (!fp)
|
|
||||||
+ goto err;
|
|
||||||
+
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+ splash_state.file = fp;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
return;
|
|
||||||
|
|
||||||
err_device:
|
|
||||||
@@ -292,3 +320,7 @@ void bootsplash_init(void)
|
|
||||||
err:
|
|
||||||
pr_err("Failed to initialize.\n");
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+module_param_named(bootfile, splash_state.bootfile, charp, 0444);
|
|
||||||
+MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
index b11da5cb90bf..71e2a27ac0b8 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
@@ -15,15 +15,43 @@
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/fb.h>
|
|
||||||
+#include <linux/firmware.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
|
|
||||||
+#include "uapi/linux/bootsplash_file.h"
|
|
||||||
+
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Runtime types
|
|
||||||
*/
|
|
||||||
+struct splash_blob_priv {
|
|
||||||
+ struct splash_blob_header *blob_header;
|
|
||||||
+ const void *data;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+struct splash_pic_priv {
|
|
||||||
+ const struct splash_pic_header *pic_header;
|
|
||||||
+
|
|
||||||
+ struct splash_blob_priv *blobs;
|
|
||||||
+ u16 blobs_loaded;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+struct splash_file_priv {
|
|
||||||
+ const struct firmware *fw;
|
|
||||||
+ const struct splash_file_header *header;
|
|
||||||
+
|
|
||||||
+ struct splash_pic_priv *pics;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
struct splash_priv {
|
|
||||||
+ /* Bootup and runtime state */
|
|
||||||
+ char *bootfile;
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Enabled/disabled state, to be used with atomic bit operations.
|
|
||||||
* Bit 0: 0 = Splash hidden
|
|
||||||
@@ -43,6 +71,13 @@ struct splash_priv {
|
|
||||||
struct platform_device *splash_device;
|
|
||||||
|
|
||||||
struct work_struct work_redraw_vc;
|
|
||||||
+
|
|
||||||
+ /* Splash data structures including lock for everything below */
|
|
||||||
+ struct mutex data_lock;
|
|
||||||
+
|
|
||||||
+ struct fb_info *splash_fb;
|
|
||||||
+
|
|
||||||
+ struct splash_file_priv *file;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@@ -50,6 +85,14 @@ struct splash_priv {
|
|
||||||
/*
|
|
||||||
* Rendering functions
|
|
||||||
*/
|
|
||||||
-void bootsplash_do_render_background(struct fb_info *info);
|
|
||||||
+void bootsplash_do_render_background(struct fb_info *info,
|
|
||||||
+ const struct splash_file_priv *fp);
|
|
||||||
+void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
+ const struct splash_file_priv *fp);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_free_file(struct splash_file_priv *fp);
|
|
||||||
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
+ const char *path);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..fd807571ab7d
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_load.c
|
|
||||||
@@ -0,0 +1,225 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (Loading and freeing functions)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
+#include <linux/fb.h>
|
|
||||||
+#include <linux/firmware.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/mutex.h>
|
|
||||||
+#include <linux/printk.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/vmalloc.h>
|
|
||||||
+
|
|
||||||
+#include "bootsplash_internal.h"
|
|
||||||
+#include "uapi/linux/bootsplash_file.h"
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Free all vmalloc()'d resources describing a splash file.
|
|
||||||
+ */
|
|
||||||
+void bootsplash_free_file(struct splash_file_priv *fp)
|
|
||||||
+{
|
|
||||||
+ if (!fp)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ if (fp->pics) {
|
|
||||||
+ unsigned int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+
|
|
||||||
+ if (pp->blobs)
|
|
||||||
+ vfree(pp->blobs);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ vfree(fp->pics);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ release_firmware(fp->fw);
|
|
||||||
+ vfree(fp);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Load a splash screen from a "firmware" file.
|
|
||||||
+ *
|
|
||||||
+ * Parsing, and sanity checks.
|
|
||||||
+ */
|
|
||||||
+#ifdef __BIG_ENDIAN
|
|
||||||
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE
|
|
||||||
+#else
|
|
||||||
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
+ const char *path)
|
|
||||||
+{
|
|
||||||
+ const struct firmware *fw;
|
|
||||||
+ struct splash_file_priv *fp;
|
|
||||||
+ unsigned int i;
|
|
||||||
+ const u8 *walker;
|
|
||||||
+
|
|
||||||
+ if (request_firmware(&fw, path, device))
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ if (fw->size < sizeof(struct splash_file_header)
|
|
||||||
+ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {
|
|
||||||
+ pr_err("Not a bootsplash file.\n");
|
|
||||||
+
|
|
||||||
+ release_firmware(fw);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fp = vzalloc(sizeof(struct splash_file_priv));
|
|
||||||
+ if (!fp) {
|
|
||||||
+ release_firmware(fw);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pr_info("Loading splash file (%li bytes)\n", fw->size);
|
|
||||||
+
|
|
||||||
+ fp->fw = fw;
|
|
||||||
+ fp->header = (struct splash_file_header *)fw->data;
|
|
||||||
+
|
|
||||||
+ /* Sanity checks */
|
|
||||||
+ if (fp->header->version != BOOTSPLASH_VERSION) {
|
|
||||||
+ pr_err("Loaded v%d file, but we only support version %d\n",
|
|
||||||
+ fp->header->version,
|
|
||||||
+ BOOTSPLASH_VERSION);
|
|
||||||
+
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (fw->size < sizeof(struct splash_file_header)
|
|
||||||
+ + fp->header->num_pics
|
|
||||||
+ * sizeof(struct splash_pic_header)
|
|
||||||
+ + fp->header->num_blobs
|
|
||||||
+ * sizeof(struct splash_blob_header)) {
|
|
||||||
+ pr_err("File incomplete.\n");
|
|
||||||
+
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Read picture headers */
|
|
||||||
+ if (fp->header->num_pics) {
|
|
||||||
+ fp->pics = vzalloc(fp->header->num_pics
|
|
||||||
+ * sizeof(struct splash_pic_priv));
|
|
||||||
+ if (!fp->pics)
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ walker = fw->data + sizeof(struct splash_file_header);
|
|
||||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+ struct splash_pic_header *ph = (void *)walker;
|
|
||||||
+
|
|
||||||
+ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);
|
|
||||||
+
|
|
||||||
+ if (ph->num_blobs < 1) {
|
|
||||||
+ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pp->pic_header = ph;
|
|
||||||
+ pp->blobs = vzalloc(ph->num_blobs
|
|
||||||
+ * sizeof(struct splash_blob_priv));
|
|
||||||
+ if (!pp->blobs)
|
|
||||||
+ goto err;
|
|
||||||
+
|
|
||||||
+ walker += sizeof(struct splash_pic_header);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Read blob headers */
|
|
||||||
+ for (i = 0; i < fp->header->num_blobs; i++) {
|
|
||||||
+ struct splash_blob_header *bh = (void *)walker;
|
|
||||||
+ struct splash_pic_priv *pp;
|
|
||||||
+
|
|
||||||
+ if (walker + sizeof(struct splash_blob_header)
|
|
||||||
+ > fw->data + fw->size)
|
|
||||||
+ goto err;
|
|
||||||
+
|
|
||||||
+ walker += sizeof(struct splash_blob_header);
|
|
||||||
+
|
|
||||||
+ if (walker + bh->length > fw->data + fw->size)
|
|
||||||
+ goto err;
|
|
||||||
+
|
|
||||||
+ if (bh->picture_id >= fp->header->num_pics)
|
|
||||||
+ goto nextblob;
|
|
||||||
+
|
|
||||||
+ pp = &fp->pics[bh->picture_id];
|
|
||||||
+
|
|
||||||
+ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",
|
|
||||||
+ i, bh->picture_id,
|
|
||||||
+ pp->blobs_loaded, pp->pic_header->num_blobs);
|
|
||||||
+
|
|
||||||
+ if (pp->blobs_loaded >= pp->pic_header->num_blobs)
|
|
||||||
+ goto nextblob;
|
|
||||||
+
|
|
||||||
+ switch (bh->type) {
|
|
||||||
+ case 0:
|
|
||||||
+ /* Raw 24-bit packed pixels */
|
|
||||||
+ if (bh->length != pp->pic_header->width
|
|
||||||
+ * pp->pic_header->height * 3) {
|
|
||||||
+ pr_err("Blob %u, type 1: Length doesn't match picture.\n",
|
|
||||||
+ i);
|
|
||||||
+
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);
|
|
||||||
+ goto nextblob;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pp->blobs[pp->blobs_loaded].blob_header = bh;
|
|
||||||
+ pp->blobs[pp->blobs_loaded].data = walker;
|
|
||||||
+ pp->blobs_loaded++;
|
|
||||||
+
|
|
||||||
+nextblob:
|
|
||||||
+ walker += bh->length;
|
|
||||||
+ if (bh->length % 16)
|
|
||||||
+ walker += 16 - (bh->length % 16);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (walker != fw->data + fw->size)
|
|
||||||
+ pr_warn("Trailing data in splash file.\n");
|
|
||||||
+
|
|
||||||
+ /* Walk over pictures and ensure all blob slots are filled */
|
|
||||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+
|
|
||||||
+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
|
|
||||||
+ pr_err("Picture %u doesn't have all blob slots filled.\n",
|
|
||||||
+ i);
|
|
||||||
+
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
|
|
||||||
+ fw->size,
|
|
||||||
+ fp->header->num_pics,
|
|
||||||
+ fp->header->num_blobs);
|
|
||||||
+
|
|
||||||
+ return fp;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+err:
|
|
||||||
+ bootsplash_free_file(fp);
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
index 4d7e0117f653..2ae36949d0e3 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
@@ -19,6 +19,7 @@
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
#include "bootsplash_internal.h"
|
|
||||||
+#include "uapi/linux/bootsplash_file.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-void bootsplash_do_render_background(struct fb_info *info)
|
|
||||||
+/*
|
|
||||||
+ * Copy from source and blend into the destination picture.
|
|
||||||
+ * Currently assumes that the source picture is 24bpp.
|
|
||||||
+ * Currently assumes that the destination is <= 32bpp.
|
|
||||||
+ */
|
|
||||||
+static int splash_convert_to_fb(u8 *dst,
|
|
||||||
+ const struct fb_var_screeninfo *dst_var,
|
|
||||||
+ unsigned int dst_stride,
|
|
||||||
+ unsigned int dst_xoff,
|
|
||||||
+ unsigned int dst_yoff,
|
|
||||||
+ const u8 *src,
|
|
||||||
+ unsigned int src_width,
|
|
||||||
+ unsigned int src_height)
|
|
||||||
+{
|
|
||||||
+ unsigned int x, y;
|
|
||||||
+ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */
|
|
||||||
+ u32 dst_octpp = dst_var->bits_per_pixel / 8;
|
|
||||||
+
|
|
||||||
+ dst_xoff += dst_var->xoffset;
|
|
||||||
+ dst_yoff += dst_var->yoffset;
|
|
||||||
+
|
|
||||||
+ /* Copy with stride and pixel size adjustment */
|
|
||||||
+ for (y = 0;
|
|
||||||
+ y < src_height && y + dst_yoff < dst_var->yres_virtual;
|
|
||||||
+ y++) {
|
|
||||||
+ const u8 *srcline = src + (y * src_stride);
|
|
||||||
+ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)
|
|
||||||
+ + (dst_xoff * dst_octpp);
|
|
||||||
+
|
|
||||||
+ for (x = 0;
|
|
||||||
+ x < src_width && x + dst_xoff < dst_var->xres_virtual;
|
|
||||||
+ x++) {
|
|
||||||
+ u8 red, green, blue;
|
|
||||||
+ u32 dstpix;
|
|
||||||
+
|
|
||||||
+ /* Read pixel */
|
|
||||||
+ red = *srcline++;
|
|
||||||
+ green = *srcline++;
|
|
||||||
+ blue = *srcline++;
|
|
||||||
+
|
|
||||||
+ /* Write pixel */
|
|
||||||
+ dstpix = pack_pixel(dst_var, red, green, blue);
|
|
||||||
+ memcpy(dstline, &dstpix, dst_octpp);
|
|
||||||
+
|
|
||||||
+ dstline += dst_octpp;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_do_render_background(struct fb_info *info,
|
|
||||||
+ const struct splash_file_priv *fp)
|
|
||||||
{
|
|
||||||
unsigned int x, y;
|
|
||||||
u32 dstpix;
|
|
||||||
u32 dst_octpp = info->var.bits_per_pixel / 8;
|
|
||||||
|
|
||||||
dstpix = pack_pixel(&info->var,
|
|
||||||
- 0,
|
|
||||||
- 0,
|
|
||||||
- 0);
|
|
||||||
+ fp->header->bg_red,
|
|
||||||
+ fp->header->bg_green,
|
|
||||||
+ fp->header->bg_blue);
|
|
||||||
|
|
||||||
for (y = 0; y < info->var.yres_virtual; y++) {
|
|
||||||
u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
|
|
||||||
@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
+ const struct splash_file_priv *fp)
|
|
||||||
+{
|
|
||||||
+ unsigned int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
+ struct splash_blob_priv *bp;
|
|
||||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+ long dst_xoff, dst_yoff;
|
|
||||||
+
|
|
||||||
+ if (pp->blobs_loaded < 1)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ bp = &pp->blobs[0];
|
|
||||||
+
|
|
||||||
+ if (!bp || bp->blob_header->type != 0)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
|
|
||||||
+ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
|
|
||||||
+
|
|
||||||
+ if (dst_xoff < 0
|
|
||||||
+ || dst_yoff < 0
|
|
||||||
+ || dst_xoff + pp->pic_header->width > info->var.xres
|
|
||||||
+ || dst_yoff + pp->pic_header->height > info->var.yres) {
|
|
||||||
+ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"
|
|
||||||
+ "(this will only be printed once every reboot)\n",
|
|
||||||
+ i, info->var.xres, info->var.yres);
|
|
||||||
+
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Draw next splash frame */
|
|
||||||
+ splash_convert_to_fb(info->screen_buffer, &info->var,
|
|
||||||
+ info->fix.line_length, dst_xoff, dst_yoff,
|
|
||||||
+ bp->data,
|
|
||||||
+ pp->pic_header->width, pp->pic_header->height);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..89dc9cca8f0c
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/include/uapi/linux/bootsplash_file.h
|
|
||||||
@@ -0,0 +1,118 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (File format)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef __BOOTSPLASH_FILE_H
|
|
||||||
+#define __BOOTSPLASH_FILE_H
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#define BOOTSPLASH_VERSION 55561
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * On-disk types
|
|
||||||
+ *
|
|
||||||
+ * A splash file consists of:
|
|
||||||
+ * - One single 'struct splash_file_header'
|
|
||||||
+ * - An array of 'struct splash_pic_header'
|
|
||||||
+ * - An array of raw data blocks, each padded to 16 bytes and
|
|
||||||
+ * preceded by a 'struct splash_blob_header'
|
|
||||||
+ *
|
|
||||||
+ * A single-frame splash may look like this:
|
|
||||||
+ *
|
|
||||||
+ * +--------------------+
|
|
||||||
+ * | |
|
|
||||||
+ * | splash_file_header |
|
|
||||||
+ * | -> num_blobs = 1 |
|
|
||||||
+ * | -> num_pics = 1 |
|
|
||||||
+ * | |
|
|
||||||
+ * +--------------------+
|
|
||||||
+ * | |
|
|
||||||
+ * | splash_pic_header |
|
|
||||||
+ * | |
|
|
||||||
+ * +--------------------+
|
|
||||||
+ * | |
|
|
||||||
+ * | splash_blob_header |
|
|
||||||
+ * | -> type = 0 |
|
|
||||||
+ * | -> picture_id = 0 |
|
|
||||||
+ * | |
|
|
||||||
+ * | (raw RGB data) |
|
|
||||||
+ * | (pad to 16 bytes) |
|
|
||||||
+ * | |
|
|
||||||
+ * +--------------------+
|
|
||||||
+ *
|
|
||||||
+ * All multi-byte values are stored on disk in the native format
|
|
||||||
+ * expected by the system the file will be used on.
|
|
||||||
+ */
|
|
||||||
+#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"
|
|
||||||
+#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"
|
|
||||||
+
|
|
||||||
+struct splash_file_header {
|
|
||||||
+ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */
|
|
||||||
+
|
|
||||||
+ /* Splash file format version to avoid clashes */
|
|
||||||
+ uint16_t version;
|
|
||||||
+
|
|
||||||
+ /* The background color */
|
|
||||||
+ uint8_t bg_red;
|
|
||||||
+ uint8_t bg_green;
|
|
||||||
+ uint8_t bg_blue;
|
|
||||||
+ uint8_t bg_reserved;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Number of pic/blobs so we can allocate memory for internal
|
|
||||||
+ * structures ahead of time when reading the file
|
|
||||||
+ */
|
|
||||||
+ uint16_t num_blobs;
|
|
||||||
+ uint8_t num_pics;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[103];
|
|
||||||
+} __attribute__((__packed__));
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+struct splash_pic_header {
|
|
||||||
+ uint16_t width;
|
|
||||||
+ uint16_t height;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Number of data packages associated with this picture.
|
|
||||||
+ * Currently, the only use for more than 1 is for animations.
|
|
||||||
+ */
|
|
||||||
+ uint8_t num_blobs;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[27];
|
|
||||||
+} __attribute__((__packed__));
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+struct splash_blob_header {
|
|
||||||
+ /* Length of the data block in bytes. */
|
|
||||||
+ uint32_t length;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Type of the contents.
|
|
||||||
+ * 0 - Raw RGB data.
|
|
||||||
+ */
|
|
||||||
+ uint16_t type;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Picture this blob is associated with.
|
|
||||||
+ * Blobs will be added to a picture in the order they are
|
|
||||||
+ * found in the file.
|
|
||||||
+ */
|
|
||||||
+ uint8_t picture_id;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[9];
|
|
||||||
+} __attribute__((__packed__));
|
|
||||||
+
|
|
||||||
+#endif
|
|
@ -1,150 +0,0 @@
|
|||||||
--- b/drivers/video/fbdev/core/bitblit.c
|
|
||||||
+++ a/drivers/video/fbdev/core/bitblit.c
|
|
||||||
@@ -234,7 +234,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
- int fg, int bg)
|
|
||||||
{
|
|
||||||
struct fb_cursor cursor;
|
|
||||||
struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
@@ -247,6 +247,15 @@
|
|
||||||
|
|
||||||
cursor.set = 0;
|
|
||||||
|
|
||||||
+ if (softback_lines) {
|
|
||||||
+ if (y + softback_lines >= vc->vc_rows) {
|
|
||||||
+ mode = CM_ERASE;
|
|
||||||
+ ops->cursor_flash = 0;
|
|
||||||
+ return;
|
|
||||||
+ } else
|
|
||||||
+ y += softback_lines;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
attribute = get_attribute(info, c);
|
|
||||||
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
|
|
||||||
--- b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
|
||||||
@@ -394,7 +394,7 @@
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
|
||||||
CM_ERASE : CM_DRAW;
|
|
||||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
|
||||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
|
||||||
get_color(vc, info, c, 0));
|
|
||||||
console_unlock();
|
|
||||||
}
|
|
||||||
@@ -1345,7 +1345,7 @@
|
|
||||||
|
|
||||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
|
||||||
|
|
||||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
|
||||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
|
||||||
get_color(vc, info, c, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
--- b/drivers/video/fbdev/core/fbcon.h
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon.h
|
|
||||||
@@ -62,7 +62,7 @@
|
|
||||||
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
|
|
||||||
int color, int bottom_only);
|
|
||||||
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg);
|
|
||||||
- int fg, int bg);
|
|
||||||
int (*update_start)(struct fb_info *info);
|
|
||||||
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
|
|
||||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
|
||||||
--- b/drivers/video/fbdev/core/fbcon_ccw.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon_ccw.c
|
|
||||||
@@ -219,7 +219,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
- int fg, int bg)
|
|
||||||
{
|
|
||||||
struct fb_cursor cursor;
|
|
||||||
struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
@@ -236,6 +236,15 @@
|
|
||||||
|
|
||||||
cursor.set = 0;
|
|
||||||
|
|
||||||
+ if (softback_lines) {
|
|
||||||
+ if (y + softback_lines >= vc->vc_rows) {
|
|
||||||
+ mode = CM_ERASE;
|
|
||||||
+ ops->cursor_flash = 0;
|
|
||||||
+ return;
|
|
||||||
+ } else
|
|
||||||
+ y += softback_lines;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
attribute = get_attribute(info, c);
|
|
||||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
|
||||||
--- b/drivers/video/fbdev/core/fbcon_cw.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon_cw.c
|
|
||||||
@@ -202,7 +202,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
- int fg, int bg)
|
|
||||||
{
|
|
||||||
struct fb_cursor cursor;
|
|
||||||
struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
@@ -219,6 +219,15 @@
|
|
||||||
|
|
||||||
cursor.set = 0;
|
|
||||||
|
|
||||||
+ if (softback_lines) {
|
|
||||||
+ if (y + softback_lines >= vc->vc_rows) {
|
|
||||||
+ mode = CM_ERASE;
|
|
||||||
+ ops->cursor_flash = 0;
|
|
||||||
+ return;
|
|
||||||
+ } else
|
|
||||||
+ y += softback_lines;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
attribute = get_attribute(info, c);
|
|
||||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
|
||||||
--- b/drivers/video/fbdev/core/fbcon_ud.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon_ud.c
|
|
||||||
@@ -249,7 +249,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
- int fg, int bg)
|
|
||||||
{
|
|
||||||
struct fb_cursor cursor;
|
|
||||||
struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
@@ -267,6 +267,15 @@
|
|
||||||
|
|
||||||
cursor.set = 0;
|
|
||||||
|
|
||||||
+ if (softback_lines) {
|
|
||||||
+ if (y + softback_lines >= vc->vc_rows) {
|
|
||||||
+ mode = CM_ERASE;
|
|
||||||
+ ops->cursor_flash = 0;
|
|
||||||
+ return;
|
|
||||||
+ } else
|
|
||||||
+ y += softback_lines;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
attribute = get_attribute(info, c);
|
|
||||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
|
|
||||||
--- b/drivers/video/fbdev/core/tileblit.c
|
|
||||||
+++ a/drivers/video/fbdev/core/tileblit.c
|
|
||||||
@@ -80,7 +80,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|
||||||
+ int softback_lines, int fg, int bg)
|
|
||||||
- int fg, int bg)
|
|
||||||
{
|
|
||||||
struct fb_tilecursor cursor;
|
|
||||||
int use_sw = (vc->vc_cursor_type & 0x10);
|
|
@ -1,152 +0,0 @@
|
|||||||
From: Manish Narani <manish.narani@xilinx.com>
|
|
||||||
Date: Tue, 18 Sep 2018 20:34:06 +0530
|
|
||||||
Subject: [PATCH 16/36] sdhci: arasan: Add runtime PM support
|
|
||||||
|
|
||||||
Add runtime PM support in Arasan SDHCI driver.
|
|
||||||
|
|
||||||
Signed-off-by: Manish Narani <manish.narani@xilinx.com>
|
|
||||||
---
|
|
||||||
drivers/mmc/host/sdhci-of-arasan.c | 88 +++++++++++++++++++++++++++++++++++++-
|
|
||||||
1 file changed, 86 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
|
|
||||||
index 6a2e5a4..e08d6ef 100644
|
|
||||||
--- a/drivers/mmc/host/sdhci-of-arasan.c
|
|
||||||
+++ b/drivers/mmc/host/sdhci-of-arasan.c
|
|
||||||
@@ -19,6 +19,7 @@
|
|
||||||
#include <linux/mfd/syscon.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/of_device.h>
|
|
||||||
+#include <linux/pm_runtime.h>
|
|
||||||
#include <linux/phy/phy.h>
|
|
||||||
#include <linux/regmap.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
@@ -27,6 +28,7 @@
|
|
||||||
#include "cqhci.h"
|
|
||||||
#include "sdhci-pltfm.h"
|
|
||||||
|
|
||||||
+#define SDHCI_ARASAN_AUTOSUSPEND_DELAY 2000 /* ms */
|
|
||||||
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
|
|
||||||
|
|
||||||
#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8
|
|
||||||
@@ -472,6 +474,70 @@ static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = {
|
|
||||||
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
|
|
||||||
};
|
|
||||||
|
|
||||||
+#ifdef CONFIG_PM
|
|
||||||
+static int sdhci_arasan_runtime_suspend(struct device *dev)
|
|
||||||
+{
|
|
||||||
+ struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
+ struct sdhci_host *host = platform_get_drvdata(pdev);
|
|
||||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
||||||
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (sdhci_arasan->has_cqe) {
|
|
||||||
+ ret = cqhci_suspend(host->mmc);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = sdhci_runtime_suspend_host(host);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
|
|
||||||
+ mmc_retune_needed(host->mmc);
|
|
||||||
+
|
|
||||||
+ clk_disable(pltfm_host->clk);
|
|
||||||
+ clk_disable(sdhci_arasan->clk_ahb);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int sdhci_arasan_runtime_resume(struct device *dev)
|
|
||||||
+{
|
|
||||||
+ struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
+ struct sdhci_host *host = platform_get_drvdata(pdev);
|
|
||||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
||||||
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = clk_enable(sdhci_arasan->clk_ahb);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(dev, "Cannot enable AHB clock.\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = clk_enable(pltfm_host->clk);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(dev, "Cannot enable SD clock.\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = sdhci_runtime_resume_host(host, 0);
|
|
||||||
+ if (ret)
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ if (sdhci_arasan->has_cqe)
|
|
||||||
+ return cqhci_resume(host->mmc);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+out:
|
|
||||||
+ clk_disable(pltfm_host->clk);
|
|
||||||
+ clk_disable(sdhci_arasan->clk_ahb);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+#endif /* ! CONFIG_PM */
|
|
||||||
+
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
/**
|
|
||||||
* sdhci_arasan_suspend - Suspend method for the driver
|
|
||||||
@@ -568,8 +634,10 @@ static int sdhci_arasan_resume(struct device *dev)
|
|
||||||
}
|
|
||||||
#endif /* ! CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
-static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
|
|
||||||
- sdhci_arasan_resume);
|
|
||||||
+static const struct dev_pm_ops sdhci_arasan_dev_pm_ops = {
|
|
||||||
+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_arasan_suspend, sdhci_arasan_resume)
|
|
||||||
+ SET_RUNTIME_PM_OPS(sdhci_arasan_runtime_suspend,
|
|
||||||
+ sdhci_arasan_runtime_resume, NULL) };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
|
|
||||||
@@ -1708,13 +1776,25 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
|
|
||||||
host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ pm_runtime_get_noresume(&pdev->dev);
|
|
||||||
+ pm_runtime_set_active(&pdev->dev);
|
|
||||||
+ pm_runtime_enable(&pdev->dev);
|
|
||||||
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
|
|
||||||
+ SDHCI_ARASAN_AUTOSUSPEND_DELAY);
|
|
||||||
+ pm_runtime_use_autosuspend(&pdev->dev);
|
|
||||||
+
|
|
||||||
ret = sdhci_arasan_add_host(sdhci_arasan);
|
|
||||||
if (ret)
|
|
||||||
goto err_add_host;
|
|
||||||
|
|
||||||
+ pm_runtime_put_autosuspend(&pdev->dev);
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_add_host:
|
|
||||||
+ pm_runtime_disable(&pdev->dev);
|
|
||||||
+ pm_runtime_set_suspended(&pdev->dev);
|
|
||||||
+ pm_runtime_put_noidle(&pdev->dev);
|
|
||||||
if (!IS_ERR(sdhci_arasan->phy))
|
|
||||||
phy_exit(sdhci_arasan->phy);
|
|
||||||
unreg_clk:
|
|
||||||
@@ -1742,6 +1822,10 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
|
|
||||||
phy_exit(sdhci_arasan->phy);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ pm_runtime_get_sync(&pdev->dev);
|
|
||||||
+ pm_runtime_disable(&pdev->dev);
|
|
||||||
+ pm_runtime_put_noidle(&pdev->dev);
|
|
||||||
+
|
|
||||||
sdhci_arasan_unregister_sdclk(&pdev->dev);
|
|
||||||
|
|
||||||
ret = sdhci_pltfm_unregister(pdev);
|
|
@ -1,66 +0,0 @@
|
|||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
index 843c5400fefc..815b007f81ca 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info)
|
|
||||||
|
|
||||||
bootsplash_do_render_pictures(info, splash_state.file);
|
|
||||||
|
|
||||||
+ bootsplash_do_render_flush(info);
|
|
||||||
+
|
|
||||||
out:
|
|
||||||
mutex_unlock(&splash_state.data_lock);
|
|
||||||
}
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
index 71e2a27ac0b8..0acb383aa4e3 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
@@ -89,6 +89,7 @@ void bootsplash_do_render_background(struct fb_info *info,
|
|
||||||
const struct splash_file_priv *fp);
|
|
||||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
const struct splash_file_priv *fp);
|
|
||||||
+void bootsplash_do_render_flush(struct fb_info *info);
|
|
||||||
|
|
||||||
|
|
||||||
void bootsplash_free_file(struct splash_file_priv *fp);
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
index 2ae36949d0e3..8c09c306ff67 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
pp->pic_header->width, pp->pic_header->height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_do_render_flush(struct fb_info *info)
|
|
||||||
+{
|
|
||||||
+ /*
|
|
||||||
+ * FB drivers using deferred_io (such as Xen) need to sync the
|
|
||||||
+ * screen after modifying its contents. When the FB is mmap()ed
|
|
||||||
+ * from userspace, this happens via a dirty pages callback, but
|
|
||||||
+ * when modifying the FB from the kernel, there is no such thing.
|
|
||||||
+ *
|
|
||||||
+ * So let's issue a fake fb_copyarea (copying the FB onto itself)
|
|
||||||
+ * to trick the FB driver into syncing the screen.
|
|
||||||
+ *
|
|
||||||
+ * A few DRM drivers' FB implementations are broken by not using
|
|
||||||
+ * deferred_io when they really should - we match on the known
|
|
||||||
+ * bad ones manually for now.
|
|
||||||
+ */
|
|
||||||
+ if (info->fbdefio
|
|
||||||
+ || !strcmp(info->fix.id, "astdrmfb")
|
|
||||||
+ || !strcmp(info->fix.id, "cirrusdrmfb")
|
|
||||||
+ || !strcmp(info->fix.id, "mgadrmfb")) {
|
|
||||||
+ struct fb_copyarea area;
|
|
||||||
+
|
|
||||||
+ area.dx = 0;
|
|
||||||
+ area.dy = 0;
|
|
||||||
+ area.width = info->var.xres;
|
|
||||||
+ area.height = info->var.yres;
|
|
||||||
+ area.sx = 0;
|
|
||||||
+ area.sy = 0;
|
|
||||||
+
|
|
||||||
+ info->fbops->fb_copyarea(info, &area);
|
|
||||||
+ }
|
|
||||||
+}
|
|
@ -1,37 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 22 Oct 2021 18:09:09 +0200
|
|
||||||
Subject: [PATCH 19/36] clk: rk3399: Export SCLK_CIF_OUT_SRC to device tree
|
|
||||||
|
|
||||||
So that it can be used in assigned-clock-parents.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/clk/rockchip/clk-rk3399.c | 2 +-
|
|
||||||
include/dt-bindings/clock/rk3399-cru.h | 1 +
|
|
||||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
|
|
||||||
index 306910a..897581e 100644
|
|
||||||
--- a/drivers/clk/rockchip/clk-rk3399.c
|
|
||||||
+++ b/drivers/clk/rockchip/clk-rk3399.c
|
|
||||||
@@ -1259,7 +1259,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
||||||
RK3399_CLKGATE_CON(27), 6, GFLAGS),
|
|
||||||
|
|
||||||
/* cif */
|
|
||||||
- COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
||||||
+ COMPOSITE_NODIV(SCLK_CIF_OUT_SRC, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
||||||
RK3399_CLKSEL_CON(56), 6, 2, MFLAGS,
|
|
||||||
RK3399_CLKGATE_CON(10), 7, GFLAGS),
|
|
||||||
|
|
||||||
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
|
|
||||||
index 44e0a31..e83b3fb 100644
|
|
||||||
--- a/include/dt-bindings/clock/rk3399-cru.h
|
|
||||||
+++ b/include/dt-bindings/clock/rk3399-cru.h
|
|
||||||
@@ -125,6 +125,7 @@
|
|
||||||
#define SCLK_DDRC 168
|
|
||||||
#define SCLK_TESTCLKOUT1 169
|
|
||||||
#define SCLK_TESTCLKOUT2 170
|
|
||||||
+#define SCLK_CIF_OUT_SRC 171
|
|
||||||
|
|
||||||
#define DCLK_VOP0 180
|
|
||||||
#define DCLK_VOP1 181
|
|
@ -1,31 +0,0 @@
|
|||||||
--- b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
|
||||||
@@ -163,6 +163,8 @@
|
|
||||||
|
|
||||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
|
||||||
|
|
||||||
+static int fbcon_set_origin(struct vc_data *);
|
|
||||||
+
|
|
||||||
static int fbcon_cursor_noblink;
|
|
||||||
|
|
||||||
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
|
|
||||||
@@ -2633,6 +2635,11 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int fbcon_set_origin(struct vc_data *vc)
|
|
||||||
+{
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void fbcon_suspended(struct fb_info *info)
|
|
||||||
{
|
|
||||||
struct vc_data *vc = NULL;
|
|
||||||
@@ -3103,6 +3110,7 @@
|
|
||||||
.con_font_default = fbcon_set_def_font,
|
|
||||||
.con_font_copy = fbcon_copy_font,
|
|
||||||
.con_set_palette = fbcon_set_palette,
|
|
||||||
+ .con_set_origin = fbcon_set_origin,
|
|
||||||
.con_invert_region = fbcon_invert_region,
|
|
||||||
.con_screen_pos = fbcon_screen_pos,
|
|
||||||
.con_getxy = fbcon_getxy,
|
|
@ -1,215 +0,0 @@
|
|||||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
index 8c09c306ff67..07e3a4eab811 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
struct splash_blob_priv *bp;
|
|
||||||
struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+ const struct splash_pic_header *ph = pp->pic_header;
|
|
||||||
long dst_xoff, dst_yoff;
|
|
||||||
|
|
||||||
if (pp->blobs_loaded < 1)
|
|
||||||
@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
if (!bp || bp->blob_header->type != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
- dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
|
|
||||||
- dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
|
|
||||||
+ switch (ph->position) {
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT:
|
|
||||||
+ dst_xoff = 0;
|
|
||||||
+ dst_yoff = 0;
|
|
||||||
+
|
|
||||||
+ dst_xoff += ph->position_offset;
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = 0;
|
|
||||||
+
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_yoff = 0;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ dst_yoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+
|
|
||||||
+ dst_yoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT:
|
|
||||||
+ dst_xoff = 0 + ph->position_offset;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height
|
|
||||||
+ - ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT:
|
|
||||||
+ dst_xoff = 0;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case SPLASH_CORNER_TOP_LEFT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ dst_yoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_TOP:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_yoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_TOP_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff += ph->position_offset;
|
|
||||||
+ dst_yoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_BOTTOM_RIGHT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff += ph->position_offset;
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_BOTTOM:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_BOTTOM_LEFT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ dst_yoff += ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+ case SPLASH_CORNER_LEFT:
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+
|
|
||||||
+ dst_xoff -= ph->position_offset;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ /* As a fallback, center the picture. */
|
|
||||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
|
||||||
+ dst_xoff /= 2;
|
|
||||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
|
||||||
+ dst_yoff /= 2;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (dst_xoff < 0
|
|
||||||
|| dst_yoff < 0
|
|
||||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
|
||||||
index 89dc9cca8f0c..71cedcc68933 100644
|
|
||||||
--- a/include/uapi/linux/bootsplash_file.h
|
|
||||||
+++ b/include/uapi/linux/bootsplash_file.h
|
|
||||||
@@ -91,7 +91,32 @@ struct splash_pic_header {
|
|
||||||
*/
|
|
||||||
uint8_t num_blobs;
|
|
||||||
|
|
||||||
- uint8_t padding[27];
|
|
||||||
+ /*
|
|
||||||
+ * Corner to move the picture to / from.
|
|
||||||
+ * 0x00 - Top left
|
|
||||||
+ * 0x01 - Top
|
|
||||||
+ * 0x02 - Top right
|
|
||||||
+ * 0x03 - Right
|
|
||||||
+ * 0x04 - Bottom right
|
|
||||||
+ * 0x05 - Bottom
|
|
||||||
+ * 0x06 - Bottom left
|
|
||||||
+ * 0x07 - Left
|
|
||||||
+ *
|
|
||||||
+ * Flags:
|
|
||||||
+ * 0x10 - Calculate offset from the corner towards the center,
|
|
||||||
+ * rather than from the center towards the corner
|
|
||||||
+ */
|
|
||||||
+ uint8_t position;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Pixel offset from the selected position.
|
|
||||||
+ * Example: If the picture is in the top right corner, it will
|
|
||||||
+ * be placed position_offset pixels from the top and
|
|
||||||
+ * position_offset pixels from the right margin.
|
|
||||||
+ */
|
|
||||||
+ uint16_t position_offset;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[24];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
|
|
||||||
@@ -115,4 +140,22 @@ struct splash_blob_header {
|
|
||||||
uint8_t padding[9];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Enums for on-disk types
|
|
||||||
+ */
|
|
||||||
+enum splash_position {
|
|
||||||
+ SPLASH_CORNER_TOP_LEFT = 0,
|
|
||||||
+ SPLASH_CORNER_TOP = 1,
|
|
||||||
+ SPLASH_CORNER_TOP_RIGHT = 2,
|
|
||||||
+ SPLASH_CORNER_RIGHT = 3,
|
|
||||||
+ SPLASH_CORNER_BOTTOM_RIGHT = 4,
|
|
||||||
+ SPLASH_CORNER_BOTTOM = 5,
|
|
||||||
+ SPLASH_CORNER_BOTTOM_LEFT = 6,
|
|
||||||
+ SPLASH_CORNER_LEFT = 7,
|
|
||||||
+ SPLASH_POS_FLAG_CORNER = 0x10,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 21 Nov 2021 17:00:09 +0100
|
|
||||||
Subject: [PATCH 24/36] media: rockchip: rga: Fix probe bugs
|
|
||||||
|
|
||||||
The check for dst_mmu_pages allocation failure was inverted.
|
|
||||||
|
|
||||||
rga_parse_dt is missing a error return, so if some of the resources
|
|
||||||
return DEFER_PROBE, probe will succeed without these resources.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/platform/rockchip/rga/rga.c | 6 ++++--
|
|
||||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
|
|
||||||
index 4de5e8d..82cc0c0 100644
|
|
||||||
--- a/drivers/media/platform/rockchip/rga/rga.c
|
|
||||||
+++ b/drivers/media/platform/rockchip/rga/rga.c
|
|
||||||
@@ -815,8 +815,10 @@ static int rga_probe(struct platform_device *pdev)
|
|
||||||
mutex_init(&rga->mutex);
|
|
||||||
|
|
||||||
ret = rga_parse_dt(rga);
|
|
||||||
- if (ret)
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(&pdev->dev, "Unable to parse OF data\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
pm_runtime_enable(rga->dev);
|
|
||||||
|
|
||||||
@@ -892,7 +894,7 @@ static int rga_probe(struct platform_device *pdev)
|
|
||||||
}
|
|
||||||
rga->dst_mmu_pages =
|
|
||||||
(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
|
|
||||||
- if (rga->dst_mmu_pages) {
|
|
||||||
+ if (!rga->dst_mmu_pages) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free_src_pages;
|
|
||||||
}
|
|
@ -1,500 +0,0 @@
|
|||||||
--- b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
|
||||||
@@ -122,6 +122,12 @@
|
|
||||||
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
|
|
||||||
enums. */
|
|
||||||
static int logo_shown = FBCON_LOGO_CANSHOW;
|
|
||||||
+/* Software scrollback */
|
|
||||||
+static int fbcon_softback_size = 32768;
|
|
||||||
+static unsigned long softback_buf, softback_curr;
|
|
||||||
+static unsigned long softback_in;
|
|
||||||
+static unsigned long softback_top, softback_end;
|
|
||||||
+static int softback_lines;
|
|
||||||
/* console mappings */
|
|
||||||
static int first_fb_vc;
|
|
||||||
static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
|
||||||
@@ -161,6 +167,8 @@
|
|
||||||
|
|
||||||
static const struct consw fb_con;
|
|
||||||
|
|
||||||
+#define CM_SOFTBACK (8)
|
|
||||||
+
|
|
||||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
|
||||||
|
|
||||||
static int fbcon_set_origin(struct vc_data *);
|
|
||||||
@@ -365,6 +373,18 @@
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void fbcon_update_softback(struct vc_data *vc)
|
|
||||||
+{
|
|
||||||
+ int l = fbcon_softback_size / vc->vc_size_row;
|
|
||||||
+
|
|
||||||
+ if (l > 5)
|
|
||||||
+ softback_end = softback_buf + l * vc->vc_size_row;
|
|
||||||
+ else
|
|
||||||
+ /* Smaller scrollback makes no sense, and 0 would screw
|
|
||||||
+ the operation totally */
|
|
||||||
+ softback_top = 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void fb_flashcursor(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct fb_info *info = container_of(work, struct fb_info, queue);
|
|
||||||
@@ -394,7 +414,7 @@
|
|
||||||
c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
|
||||||
CM_ERASE : CM_DRAW;
|
|
||||||
+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
|
|
||||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
|
||||||
get_color(vc, info, c, 0));
|
|
||||||
console_unlock();
|
|
||||||
}
|
|
||||||
@@ -451,7 +471,13 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strncmp(options, "scrollback:", 11)) {
|
|
||||||
+ options += 11;
|
|
||||||
+ if (*options) {
|
|
||||||
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
|
|
||||||
+ if (*options == 'k' || *options == 'K') {
|
|
||||||
+ fbcon_softback_size *= 1024;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
- pr_warn("Ignoring scrollback size option\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -996,6 +1022,31 @@
|
|
||||||
|
|
||||||
set_blitting_type(vc, info);
|
|
||||||
|
|
||||||
+ if (info->fix.type != FB_TYPE_TEXT) {
|
|
||||||
+ if (fbcon_softback_size) {
|
|
||||||
+ if (!softback_buf) {
|
|
||||||
+ softback_buf =
|
|
||||||
+ (unsigned long)
|
|
||||||
+ kvmalloc(fbcon_softback_size,
|
|
||||||
+ GFP_KERNEL);
|
|
||||||
+ if (!softback_buf) {
|
|
||||||
+ fbcon_softback_size = 0;
|
|
||||||
+ softback_top = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ if (softback_buf) {
|
|
||||||
+ kvfree((void *) softback_buf);
|
|
||||||
+ softback_buf = 0;
|
|
||||||
+ softback_top = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (softback_buf)
|
|
||||||
+ softback_in = softback_top = softback_curr =
|
|
||||||
+ softback_buf;
|
|
||||||
+ softback_lines = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* Setup default font */
|
|
||||||
if (!p->fontdata && !vc->vc_font.data) {
|
|
||||||
if (!fontname[0] || !(font = find_font(fontname)))
|
|
||||||
@@ -1169,6 +1220,9 @@
|
|
||||||
if (logo)
|
|
||||||
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
|
|
||||||
|
|
||||||
+ if (vc == svc && softback_buf)
|
|
||||||
+ fbcon_update_softback(vc);
|
|
||||||
+
|
|
||||||
if (ops->rotate_font && ops->rotate_font(info, vc)) {
|
|
||||||
ops->rotate = FB_ROTATE_UR;
|
|
||||||
set_blitting_type(vc, info);
|
|
||||||
@@ -1331,6 +1385,7 @@
|
|
||||||
{
|
|
||||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
|
||||||
struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
+ int y;
|
|
||||||
int c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
|
|
||||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
|
||||||
@@ -1334,11 +1389,19 @@ static void fbcon_cursor(struct vc_data
|
|
||||||
fbcon_add_cursor_timer(info);
|
|
||||||
|
|
||||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
|
||||||
+ if (mode & CM_SOFTBACK) {
|
|
||||||
+ mode &= ~CM_SOFTBACK;
|
|
||||||
+ y = softback_lines;
|
|
||||||
+ } else {
|
|
||||||
+ if (softback_lines)
|
|
||||||
+ fbcon_set_origin(vc);
|
|
||||||
+ y = 0;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (!ops->cursor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
|
||||||
+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
|
|
||||||
get_color(vc, info, c, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1416,6 +1479,8 @@
|
|
||||||
|
|
||||||
if (con_is_visible(vc)) {
|
|
||||||
update_screen(vc);
|
|
||||||
+ if (softback_buf)
|
|
||||||
+ fbcon_update_softback(vc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1553,6 +1618,99 @@
|
|
||||||
scrollback_current = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
|
|
||||||
+ long delta)
|
|
||||||
+{
|
|
||||||
+ int count = vc->vc_rows;
|
|
||||||
+ unsigned short *d, *s;
|
|
||||||
+ unsigned long n;
|
|
||||||
+ int line = 0;
|
|
||||||
+
|
|
||||||
+ d = (u16 *) softback_curr;
|
|
||||||
+ if (d == (u16 *) softback_in)
|
|
||||||
+ d = (u16 *) vc->vc_origin;
|
|
||||||
+ n = softback_curr + delta * vc->vc_size_row;
|
|
||||||
+ softback_lines -= delta;
|
|
||||||
+ if (delta < 0) {
|
|
||||||
+ if (softback_curr < softback_top && n < softback_buf) {
|
|
||||||
+ n += softback_end - softback_buf;
|
|
||||||
+ if (n < softback_top) {
|
|
||||||
+ softback_lines -=
|
|
||||||
+ (softback_top - n) / vc->vc_size_row;
|
|
||||||
+ n = softback_top;
|
|
||||||
+ }
|
|
||||||
+ } else if (softback_curr >= softback_top
|
|
||||||
+ && n < softback_top) {
|
|
||||||
+ softback_lines -=
|
|
||||||
+ (softback_top - n) / vc->vc_size_row;
|
|
||||||
+ n = softback_top;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ if (softback_curr > softback_in && n >= softback_end) {
|
|
||||||
+ n += softback_buf - softback_end;
|
|
||||||
+ if (n > softback_in) {
|
|
||||||
+ n = softback_in;
|
|
||||||
+ softback_lines = 0;
|
|
||||||
+ }
|
|
||||||
+ } else if (softback_curr <= softback_in && n > softback_in) {
|
|
||||||
+ n = softback_in;
|
|
||||||
+ softback_lines = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (n == softback_curr)
|
|
||||||
+ return;
|
|
||||||
+ softback_curr = n;
|
|
||||||
+ s = (u16 *) softback_curr;
|
|
||||||
+ if (s == (u16 *) softback_in)
|
|
||||||
+ s = (u16 *) vc->vc_origin;
|
|
||||||
+ while (count--) {
|
|
||||||
+ unsigned short *start;
|
|
||||||
+ unsigned short *le;
|
|
||||||
+ unsigned short c;
|
|
||||||
+ int x = 0;
|
|
||||||
+ unsigned short attr = 1;
|
|
||||||
+
|
|
||||||
+ start = s;
|
|
||||||
+ le = advance_row(s, 1);
|
|
||||||
+ do {
|
|
||||||
+ c = scr_readw(s);
|
|
||||||
+ if (attr != (c & 0xff00)) {
|
|
||||||
+ attr = c & 0xff00;
|
|
||||||
+ if (s > start) {
|
|
||||||
+ fbcon_putcs(vc, start, s - start,
|
|
||||||
+ line, x);
|
|
||||||
+ x += s - start;
|
|
||||||
+ start = s;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (c == scr_readw(d)) {
|
|
||||||
+ if (s > start) {
|
|
||||||
+ fbcon_putcs(vc, start, s - start,
|
|
||||||
+ line, x);
|
|
||||||
+ x += s - start + 1;
|
|
||||||
+ start = s + 1;
|
|
||||||
+ } else {
|
|
||||||
+ x++;
|
|
||||||
+ start++;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ s++;
|
|
||||||
+ d++;
|
|
||||||
+ } while (s < le);
|
|
||||||
+ if (s > start)
|
|
||||||
+ fbcon_putcs(vc, start, s - start, line, x);
|
|
||||||
+ line++;
|
|
||||||
+ if (d == (u16 *) softback_end)
|
|
||||||
+ d = (u16 *) softback_buf;
|
|
||||||
+ if (d == (u16 *) softback_in)
|
|
||||||
+ d = (u16 *) vc->vc_origin;
|
|
||||||
+ if (s == (u16 *) softback_end)
|
|
||||||
+ s = (u16 *) softback_buf;
|
|
||||||
+ if (s == (u16 *) softback_in)
|
|
||||||
+ s = (u16 *) vc->vc_origin;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
|
||||||
int line, int count, int dy)
|
|
||||||
{
|
|
||||||
@@ -1692,6 +1850,31 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
|
|
||||||
+ int count)
|
|
||||||
+{
|
|
||||||
+ unsigned short *p;
|
|
||||||
+
|
|
||||||
+ if (vc->vc_num != fg_console)
|
|
||||||
+ return;
|
|
||||||
+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
|
|
||||||
+
|
|
||||||
+ while (count) {
|
|
||||||
+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
|
|
||||||
+ count--;
|
|
||||||
+ p = advance_row(p, 1);
|
|
||||||
+ softback_in += vc->vc_size_row;
|
|
||||||
+ if (softback_in == softback_end)
|
|
||||||
+ softback_in = softback_buf;
|
|
||||||
+ if (softback_in == softback_top) {
|
|
||||||
+ softback_top += vc->vc_size_row;
|
|
||||||
+ if (softback_top == softback_end)
|
|
||||||
+ softback_top = softback_buf;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ softback_curr = softback_in;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
||||||
enum con_scroll dir, unsigned int count)
|
|
||||||
{
|
|
||||||
@@ -1714,6 +1897,8 @@
|
|
||||||
case SM_UP:
|
|
||||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
|
||||||
count = vc->vc_rows;
|
|
||||||
+ if (softback_top)
|
|
||||||
+ fbcon_softback_note(vc, t, count);
|
|
||||||
if (logo_shown >= 0)
|
|
||||||
goto redraw_up;
|
|
||||||
switch (p->scrollmode) {
|
|
||||||
@@ -2084,6 +2269,14 @@
|
|
||||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
|
||||||
ops = info->fbcon_par;
|
|
||||||
|
|
||||||
+ if (softback_top) {
|
|
||||||
+ if (softback_lines)
|
|
||||||
+ fbcon_set_origin(vc);
|
|
||||||
+ softback_top = softback_curr = softback_in = softback_buf;
|
|
||||||
+ softback_lines = 0;
|
|
||||||
+ fbcon_update_softback(vc);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (logo_shown >= 0) {
|
|
||||||
struct vc_data *conp2 = vc_cons[logo_shown].d;
|
|
||||||
|
|
||||||
@@ -2407,6 +2600,9 @@
|
|
||||||
int cnt;
|
|
||||||
char *old_data = NULL;
|
|
||||||
|
|
||||||
+ if (con_is_visible(vc) && softback_lines)
|
|
||||||
+ fbcon_set_origin(vc);
|
|
||||||
+
|
|
||||||
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
|
|
||||||
if (p->userfont)
|
|
||||||
old_data = vc->vc_font.data;
|
|
||||||
@@ -2432,6 +2628,8 @@
|
|
||||||
cols /= w;
|
|
||||||
rows /= h;
|
|
||||||
vc_resize(vc, cols, rows);
|
|
||||||
+ if (con_is_visible(vc) && softback_buf)
|
|
||||||
+ fbcon_update_softback(vc);
|
|
||||||
} else if (con_is_visible(vc)
|
|
||||||
&& vc->vc_mode == KD_TEXT) {
|
|
||||||
fbcon_clear_margins(vc, 0);
|
|
||||||
@@ -2590,7 +2788,19 @@
|
|
||||||
|
|
||||||
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
|
|
||||||
{
|
|
||||||
+ unsigned long p;
|
|
||||||
+ int line;
|
|
||||||
+
|
|
||||||
+ if (vc->vc_num != fg_console || !softback_lines)
|
|
||||||
+ return (u16 *) (vc->vc_origin + offset);
|
|
||||||
+ line = offset / vc->vc_size_row;
|
|
||||||
+ if (line >= softback_lines)
|
|
||||||
+ return (u16 *) (vc->vc_origin + offset -
|
|
||||||
+ softback_lines * vc->vc_size_row);
|
|
||||||
+ p = softback_curr + offset;
|
|
||||||
+ if (p >= softback_end)
|
|
||||||
+ p += softback_buf - softback_end;
|
|
||||||
+ return (u16 *) p;
|
|
||||||
- return (u16 *) (vc->vc_origin + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
|
|
||||||
@@ -2604,7 +2814,22 @@
|
|
||||||
|
|
||||||
x = offset % vc->vc_cols;
|
|
||||||
y = offset / vc->vc_cols;
|
|
||||||
+ if (vc->vc_num == fg_console)
|
|
||||||
+ y += softback_lines;
|
|
||||||
ret = pos + (vc->vc_cols - x) * 2;
|
|
||||||
+ } else if (vc->vc_num == fg_console && softback_lines) {
|
|
||||||
+ unsigned long offset = pos - softback_curr;
|
|
||||||
+
|
|
||||||
+ if (pos < softback_curr)
|
|
||||||
+ offset += softback_end - softback_buf;
|
|
||||||
+ offset /= 2;
|
|
||||||
+ x = offset % vc->vc_cols;
|
|
||||||
+ y = offset / vc->vc_cols;
|
|
||||||
+ ret = pos + (vc->vc_cols - x) * 2;
|
|
||||||
+ if (ret == softback_end)
|
|
||||||
+ ret = softback_buf;
|
|
||||||
+ if (ret == softback_in)
|
|
||||||
+ ret = vc->vc_origin;
|
|
||||||
} else {
|
|
||||||
/* Should not happen */
|
|
||||||
x = y = 0;
|
|
||||||
@@ -2632,11 +2857,106 @@
|
|
||||||
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
|
|
||||||
(((a) & 0x0700) << 4);
|
|
||||||
scr_writew(a, p++);
|
|
||||||
+ if (p == (u16 *) softback_end)
|
|
||||||
+ p = (u16 *) softback_buf;
|
|
||||||
+ if (p == (u16 *) softback_in)
|
|
||||||
+ p = (u16 *) vc->vc_origin;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void fbcon_scrolldelta(struct vc_data *vc, int lines)
|
|
||||||
+{
|
|
||||||
+ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
|
|
||||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
|
||||||
+ struct fbcon_display *disp = &fb_display[fg_console];
|
|
||||||
+ int offset, limit, scrollback_old;
|
|
||||||
+
|
|
||||||
+ if (softback_top) {
|
|
||||||
+ if (vc->vc_num != fg_console)
|
|
||||||
+ return;
|
|
||||||
+ if (vc->vc_mode != KD_TEXT || !lines)
|
|
||||||
+ return;
|
|
||||||
+ if (logo_shown >= 0) {
|
|
||||||
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
|
|
||||||
+
|
|
||||||
+ if (conp2->vc_top == logo_lines
|
|
||||||
+ && conp2->vc_bottom == conp2->vc_rows)
|
|
||||||
+ conp2->vc_top = 0;
|
|
||||||
+ if (logo_shown == vc->vc_num) {
|
|
||||||
+ unsigned long p, q;
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ p = softback_in;
|
|
||||||
+ q = vc->vc_origin +
|
|
||||||
+ logo_lines * vc->vc_size_row;
|
|
||||||
+ for (i = 0; i < logo_lines; i++) {
|
|
||||||
+ if (p == softback_top)
|
|
||||||
+ break;
|
|
||||||
+ if (p == softback_buf)
|
|
||||||
+ p = softback_end;
|
|
||||||
+ p -= vc->vc_size_row;
|
|
||||||
+ q -= vc->vc_size_row;
|
|
||||||
+ scr_memcpyw((u16 *) q, (u16 *) p,
|
|
||||||
+ vc->vc_size_row);
|
|
||||||
+ }
|
|
||||||
+ softback_in = softback_curr = p;
|
|
||||||
+ update_region(vc, vc->vc_origin,
|
|
||||||
+ logo_lines * vc->vc_cols);
|
|
||||||
+ }
|
|
||||||
+ logo_shown = FBCON_LOGO_CANSHOW;
|
|
||||||
+ }
|
|
||||||
+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
|
|
||||||
+ fbcon_redraw_softback(vc, disp, lines);
|
|
||||||
+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
|
|
||||||
+ return;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ if (!scrollback_phys_max)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ scrollback_old = scrollback_current;
|
|
||||||
+ scrollback_current -= lines;
|
|
||||||
+ if (scrollback_current < 0)
|
|
||||||
+ scrollback_current = 0;
|
|
||||||
+ else if (scrollback_current > scrollback_max)
|
|
||||||
+ scrollback_current = scrollback_max;
|
|
||||||
+ if (scrollback_current == scrollback_old)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ if (fbcon_is_inactive(vc, info))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ fbcon_cursor(vc, CM_ERASE);
|
|
||||||
+
|
|
||||||
+ offset = disp->yscroll - scrollback_current;
|
|
||||||
+ limit = disp->vrows;
|
|
||||||
+ switch (disp->scrollmode) {
|
|
||||||
+ case SCROLL_WRAP_MOVE:
|
|
||||||
+ info->var.vmode |= FB_VMODE_YWRAP;
|
|
||||||
+ break;
|
|
||||||
+ case SCROLL_PAN_MOVE:
|
|
||||||
+ case SCROLL_PAN_REDRAW:
|
|
||||||
+ limit -= vc->vc_rows;
|
|
||||||
+ info->var.vmode &= ~FB_VMODE_YWRAP;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ if (offset < 0)
|
|
||||||
+ offset += limit;
|
|
||||||
+ else if (offset >= limit)
|
|
||||||
+ offset -= limit;
|
|
||||||
+
|
|
||||||
+ ops->var.xoffset = 0;
|
|
||||||
+ ops->var.yoffset = offset * vc->vc_font.height;
|
|
||||||
+ ops->update_start(info);
|
|
||||||
+
|
|
||||||
+ if (!scrollback_current)
|
|
||||||
+ fbcon_cursor(vc, CM_DRAW);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fbcon_set_origin(struct vc_data *vc)
|
|
||||||
{
|
|
||||||
+ if (softback_lines)
|
|
||||||
+ fbcon_scrolldelta(vc, softback_lines);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2700,6 +3020,8 @@
|
|
||||||
|
|
||||||
fbcon_set_palette(vc, color_table);
|
|
||||||
update_screen(vc);
|
|
||||||
+ if (softback_buf)
|
|
||||||
+ fbcon_update_softback(vc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -3110,6 +3432,7 @@
|
|
||||||
.con_font_default = fbcon_set_def_font,
|
|
||||||
.con_font_copy = fbcon_copy_font,
|
|
||||||
.con_set_palette = fbcon_set_palette,
|
|
||||||
+ .con_scrolldelta = fbcon_scrolldelta,
|
|
||||||
.con_set_origin = fbcon_set_origin,
|
|
||||||
.con_invert_region = fbcon_invert_region,
|
|
||||||
.con_screen_pos = fbcon_screen_pos,
|
|
||||||
@@ -3344,6 +3667,9 @@
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+ kvfree((void *)softback_buf);
|
|
||||||
+ softback_buf = 0UL;
|
|
||||||
+
|
|
||||||
for_each_registered_fb(i) {
|
|
||||||
int pending = 0;
|
|
||||||
|
|
@ -1,327 +0,0 @@
|
|||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
index 815b007f81ca..c8642142cfea 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
|
|
||||||
console_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void splash_callback_animation(struct work_struct *ignored)
|
|
||||||
+{
|
|
||||||
+ if (bootsplash_would_render_now()) {
|
|
||||||
+ /* This will also re-schedule this delayed worker */
|
|
||||||
+ splash_callback_redraw_vc(ignored);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
|
|
||||||
static bool is_fb_compatible(const struct fb_info *info)
|
|
||||||
{
|
|
||||||
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
|
|
||||||
*/
|
|
||||||
void bootsplash_render_full(struct fb_info *info)
|
|
||||||
{
|
|
||||||
+ bool is_update = false;
|
|
||||||
+
|
|
||||||
mutex_lock(&splash_state.data_lock);
|
|
||||||
|
|
||||||
- if (!is_fb_compatible(info))
|
|
||||||
- goto out;
|
|
||||||
+ /*
|
|
||||||
+ * If we've painted on this FB recently, we don't have to do
|
|
||||||
+ * the sanity checks and background drawing again.
|
|
||||||
+ */
|
|
||||||
+ if (splash_state.splash_fb == info)
|
|
||||||
+ is_update = true;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ if (!is_update) {
|
|
||||||
+ /* Check whether we actually support this FB. */
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+
|
|
||||||
+ if (!is_fb_compatible(info))
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ /* Draw the background only once */
|
|
||||||
+ bootsplash_do_render_background(info, splash_state.file);
|
|
||||||
|
|
||||||
- bootsplash_do_render_background(info, splash_state.file);
|
|
||||||
+ /* Mark this FB as last seen */
|
|
||||||
+ splash_state.splash_fb = info;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- bootsplash_do_render_pictures(info, splash_state.file);
|
|
||||||
+ bootsplash_do_render_pictures(info, splash_state.file, is_update);
|
|
||||||
|
|
||||||
bootsplash_do_render_flush(info);
|
|
||||||
|
|
||||||
+ bootsplash_do_step_animations(splash_state.file);
|
|
||||||
+
|
|
||||||
+ /* Schedule update for animated splash screens */
|
|
||||||
+ if (splash_state.file->frame_ms > 0)
|
|
||||||
+ schedule_delayed_work(&splash_state.dwork_animation,
|
|
||||||
+ msecs_to_jiffies(
|
|
||||||
+ splash_state.file->frame_ms));
|
|
||||||
+
|
|
||||||
out:
|
|
||||||
mutex_unlock(&splash_state.data_lock);
|
|
||||||
}
|
|
||||||
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
|
|
||||||
|
|
||||||
was_enabled = test_and_set_bit(0, &splash_state.enabled);
|
|
||||||
|
|
||||||
- if (!was_enabled)
|
|
||||||
+ if (!was_enabled) {
|
|
||||||
+ /* Force a full redraw when the splash is re-activated */
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
|
|
||||||
*/
|
|
||||||
static int splash_resume(struct device *device)
|
|
||||||
{
|
|
||||||
+ /*
|
|
||||||
+ * Force full redraw on resume since we've probably lost the
|
|
||||||
+ * framebuffer's contents meanwhile
|
|
||||||
+ */
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
if (bootsplash_would_render_now())
|
|
||||||
schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
|
|
||||||
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
|
|
||||||
|
|
||||||
static int splash_suspend(struct device *device)
|
|
||||||
{
|
|
||||||
+ cancel_delayed_work_sync(&splash_state.dwork_animation);
|
|
||||||
cancel_work_sync(&splash_state.work_redraw_vc);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -296,6 +346,8 @@ void bootsplash_init(void)
|
|
||||||
set_bit(0, &splash_state.enabled);
|
|
||||||
|
|
||||||
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
|
||||||
+ INIT_DELAYED_WORK(&splash_state.dwork_animation,
|
|
||||||
+ splash_callback_animation);
|
|
||||||
|
|
||||||
|
|
||||||
if (!splash_state.bootfile || !strlen(splash_state.bootfile))
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
index 0acb383aa4e3..b3a74835d90f 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
|
||||||
@@ -37,6 +37,8 @@ struct splash_pic_priv {
|
|
||||||
|
|
||||||
struct splash_blob_priv *blobs;
|
|
||||||
u16 blobs_loaded;
|
|
||||||
+
|
|
||||||
+ u16 anim_nextframe;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +47,12 @@ struct splash_file_priv {
|
|
||||||
const struct splash_file_header *header;
|
|
||||||
|
|
||||||
struct splash_pic_priv *pics;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * A local copy of the frame delay in the header.
|
|
||||||
+ * We modify it to keep the code simple.
|
|
||||||
+ */
|
|
||||||
+ u16 frame_ms;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@@ -71,6 +79,7 @@ struct splash_priv {
|
|
||||||
struct platform_device *splash_device;
|
|
||||||
|
|
||||||
struct work_struct work_redraw_vc;
|
|
||||||
+ struct delayed_work dwork_animation;
|
|
||||||
|
|
||||||
/* Splash data structures including lock for everything below */
|
|
||||||
struct mutex data_lock;
|
|
||||||
@@ -88,8 +97,10 @@ struct splash_priv {
|
|
||||||
void bootsplash_do_render_background(struct fb_info *info,
|
|
||||||
const struct splash_file_priv *fp);
|
|
||||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
- const struct splash_file_priv *fp);
|
|
||||||
+ const struct splash_file_priv *fp,
|
|
||||||
+ bool is_update);
|
|
||||||
void bootsplash_do_render_flush(struct fb_info *info);
|
|
||||||
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
|
|
||||||
|
|
||||||
|
|
||||||
void bootsplash_free_file(struct splash_file_priv *fp);
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
|
|
||||||
index fd807571ab7d..1f661b2d4cc9 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_load.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_load.c
|
|
||||||
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
{
|
|
||||||
const struct firmware *fw;
|
|
||||||
struct splash_file_priv *fp;
|
|
||||||
+ bool have_anim = false;
|
|
||||||
unsigned int i;
|
|
||||||
const u8 *walker;
|
|
||||||
|
|
||||||
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
|
|
||||||
+ pr_warn("Picture %u: Unsupported animation type %u.\n",
|
|
||||||
+ i, ph->anim_type);
|
|
||||||
+
|
|
||||||
+ ph->anim_type = SPLASH_ANIM_NONE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
pp->pic_header = ph;
|
|
||||||
pp->blobs = vzalloc(ph->num_blobs
|
|
||||||
* sizeof(struct splash_blob_priv));
|
|
||||||
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
/* Walk over pictures and ensure all blob slots are filled */
|
|
||||||
for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+ const struct splash_pic_header *ph = pp->pic_header;
|
|
||||||
|
|
||||||
if (pp->blobs_loaded != pp->pic_header->num_blobs) {
|
|
||||||
pr_err("Picture %u doesn't have all blob slots filled.\n",
|
|
||||||
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
|
||||||
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ if (ph->anim_type
|
|
||||||
+ && ph->num_blobs > 1
|
|
||||||
+ && ph->anim_loop < pp->blobs_loaded)
|
|
||||||
+ have_anim = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (!have_anim)
|
|
||||||
+ /* Disable animation timer if there is nothing to animate */
|
|
||||||
+ fp->frame_ms = 0;
|
|
||||||
+ else
|
|
||||||
+ /* Enforce minimum delay between frames */
|
|
||||||
+ fp->frame_ms = max((u16)20, fp->header->frame_ms);
|
|
||||||
+
|
|
||||||
pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
|
|
||||||
fw->size,
|
|
||||||
fp->header->num_pics,
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
index 07e3a4eab811..76033606ca8a 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
|
||||||
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
|
|
||||||
|
|
||||||
|
|
||||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
- const struct splash_file_priv *fp)
|
|
||||||
+ const struct splash_file_priv *fp,
|
|
||||||
+ bool is_update)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
|
||||||
if (pp->blobs_loaded < 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
- bp = &pp->blobs[0];
|
|
||||||
+ /* Skip static pictures when refreshing animations */
|
|
||||||
+ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ bp = &pp->blobs[pp->anim_nextframe];
|
|
||||||
|
|
||||||
if (!bp || bp->blob_header->type != 0)
|
|
||||||
continue;
|
|
||||||
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
|
|
||||||
info->fbops->fb_copyarea(info, &area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
|
|
||||||
+{
|
|
||||||
+ unsigned int i;
|
|
||||||
+
|
|
||||||
+ /* Step every animation once */
|
|
||||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
|
||||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
|
||||||
+
|
|
||||||
+ if (pp->blobs_loaded < 2
|
|
||||||
+ || pp->pic_header->anim_loop > pp->blobs_loaded)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
|
|
||||||
+ pp->anim_nextframe++;
|
|
||||||
+ if (pp->anim_nextframe >= pp->pic_header->num_blobs)
|
|
||||||
+ pp->anim_nextframe = pp->pic_header->anim_loop;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
|
||||||
index 71cedcc68933..b3af0a3c6487 100644
|
|
||||||
--- a/include/uapi/linux/bootsplash_file.h
|
|
||||||
+++ b/include/uapi/linux/bootsplash_file.h
|
|
||||||
@@ -77,7 +77,17 @@ struct splash_file_header {
|
|
||||||
uint16_t num_blobs;
|
|
||||||
uint8_t num_pics;
|
|
||||||
|
|
||||||
- uint8_t padding[103];
|
|
||||||
+ uint8_t unused_1;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Milliseconds to wait before painting the next frame in
|
|
||||||
+ * an animation.
|
|
||||||
+ * This is actually a minimum, as the system is allowed to
|
|
||||||
+ * stall for longer between frames.
|
|
||||||
+ */
|
|
||||||
+ uint16_t frame_ms;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[100];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +126,23 @@ struct splash_pic_header {
|
|
||||||
*/
|
|
||||||
uint16_t position_offset;
|
|
||||||
|
|
||||||
- uint8_t padding[24];
|
|
||||||
+ /*
|
|
||||||
+ * Animation type.
|
|
||||||
+ * 0 - off
|
|
||||||
+ * 1 - forward loop
|
|
||||||
+ */
|
|
||||||
+ uint8_t anim_type;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Animation loop point.
|
|
||||||
+ * Actual meaning depends on animation type:
|
|
||||||
+ * Type 0 - Unused
|
|
||||||
+ * 1 - Frame at which to restart the forward loop
|
|
||||||
+ * (allowing for "intro" frames)
|
|
||||||
+ */
|
|
||||||
+ uint8_t anim_loop;
|
|
||||||
+
|
|
||||||
+ uint8_t padding[22];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
|
|
||||||
@@ -158,4 +184,9 @@ enum splash_position {
|
|
||||||
SPLASH_POS_FLAG_CORNER = 0x10,
|
|
||||||
};
|
|
||||||
|
|
||||||
+enum splash_anim_type {
|
|
||||||
+ SPLASH_ANIM_NONE = 0,
|
|
||||||
+ SPLASH_ANIM_LOOP_FORWARD = 1,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
#endif
|
|
@ -1,34 +0,0 @@
|
|||||||
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
|
|
||||||
Date: Fri, 8 Jan 2021 00:19:23 +0100
|
|
||||||
Subject: [PATCH 02/36] drm: dw-mipi-dsi-rockchip: Ensure that lane is
|
|
||||||
properly configured
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset="utf-8"
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
???
|
|
||||||
|
|
||||||
Signed-of-by: Kamil Trzciński <ayufan@ayufan.eu>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 8 ++++++++
|
|
||||||
1 file changed, 8 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
index a9acbcc..53c8b40 100644
|
|
||||||
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
@@ -406,6 +406,14 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
|
|
||||||
*/
|
|
||||||
vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
|
|
||||||
|
|
||||||
+ if (dsi->cdata->lanecfg1_grf_reg) {
|
|
||||||
+ regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
|
|
||||||
+ dsi->cdata->lanecfg1);
|
|
||||||
+
|
|
||||||
+ dev_info(dsi->dev, "dw_mipi_dsi_phy_init / dw_mipi_dsi_rockchip_config: %08x => set=%08x\n",
|
|
||||||
+ dsi->cdata->lanecfg1_grf_reg, dsi->cdata->lanecfg1);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
i = max_mbps_to_parameter(dsi->lane_mbps);
|
|
||||||
if (i < 0) {
|
|
||||||
DRM_DEV_ERROR(dsi->dev,
|
|
@ -1,82 +0,0 @@
|
|||||||
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
|
|
||||||
index 2ebaba16f785..416735ab6dc1 100644
|
|
||||||
--- a/drivers/tty/vt/vt.c
|
|
||||||
+++ b/drivers/tty/vt/vt.c
|
|
||||||
@@ -105,6 +105,7 @@
|
|
||||||
#include <linux/ctype.h>
|
|
||||||
#include <linux/bsearch.h>
|
|
||||||
#include <linux/gcd.h>
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
|
|
||||||
#define MAX_NR_CON_DRIVER 16
|
|
||||||
|
|
||||||
@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx)
|
|
||||||
}
|
|
||||||
|
|
||||||
console_blanked = 0;
|
|
||||||
+ bootsplash_mark_dirty();
|
|
||||||
if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
|
|
||||||
/* Low-level driver cannot restore -> do it ourselves */
|
|
||||||
update_screen(vc);
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
index c8642142cfea..13fcaabbc2ca 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void)
|
|
||||||
&& bootsplash_is_enabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
+void bootsplash_mark_dirty(void)
|
|
||||||
+{
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
bool bootsplash_is_enabled(void)
|
|
||||||
{
|
|
||||||
bool was_enabled;
|
|
||||||
@@ -206,9 +213,7 @@ void bootsplash_enable(void)
|
|
||||||
|
|
||||||
if (!was_enabled) {
|
|
||||||
/* Force a full redraw when the splash is re-activated */
|
|
||||||
- mutex_lock(&splash_state.data_lock);
|
|
||||||
- splash_state.splash_fb = NULL;
|
|
||||||
- mutex_unlock(&splash_state.data_lock);
|
|
||||||
+ bootsplash_mark_dirty();
|
|
||||||
|
|
||||||
schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
}
|
|
||||||
@@ -272,9 +277,7 @@ static int splash_resume(struct device *device)
|
|
||||||
* Force full redraw on resume since we've probably lost the
|
|
||||||
* framebuffer's contents meanwhile
|
|
||||||
*/
|
|
||||||
- mutex_lock(&splash_state.data_lock);
|
|
||||||
- splash_state.splash_fb = NULL;
|
|
||||||
- mutex_unlock(&splash_state.data_lock);
|
|
||||||
+ bootsplash_mark_dirty();
|
|
||||||
|
|
||||||
if (bootsplash_would_render_now())
|
|
||||||
schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
|
|
||||||
index c6dd0b43180d..4075098aaadd 100644
|
|
||||||
--- a/include/linux/bootsplash.h
|
|
||||||
+++ b/include/linux/bootsplash.h
|
|
||||||
@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info);
|
|
||||||
|
|
||||||
extern bool bootsplash_would_render_now(void);
|
|
||||||
|
|
||||||
+extern void bootsplash_mark_dirty(void);
|
|
||||||
+
|
|
||||||
extern bool bootsplash_is_enabled(void);
|
|
||||||
extern void bootsplash_disable(void);
|
|
||||||
extern void bootsplash_enable(void);
|
|
||||||
@@ -31,6 +33,8 @@ extern void bootsplash_init(void);
|
|
||||||
|
|
||||||
#define bootsplash_would_render_now() (false)
|
|
||||||
|
|
||||||
+#define bootsplash_mark_dirty()
|
|
||||||
+
|
|
||||||
#define bootsplash_is_enabled() (false)
|
|
||||||
#define bootsplash_disable()
|
|
||||||
#define bootsplash_enable()
|
|
@ -1,48 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 17 Oct 2021 18:04:21 +0200
|
|
||||||
Subject: [PATCH 03/36] drm: rockchip: dw-mipi-dsi: Fix missing
|
|
||||||
clk_disable_unprepare for pllref_clk
|
|
||||||
|
|
||||||
In some error paths, clk_disable_unprepare function was not called.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 10 +++++++---
|
|
||||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
index 53c8b40..095d0f1 100644
|
|
||||||
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
@@ -960,7 +960,7 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
|
|
||||||
ret = clk_prepare_enable(dsi->grf_clk);
|
|
||||||
if (ret) {
|
|
||||||
DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
|
|
||||||
- return ret;
|
|
||||||
+ goto err_pllref_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
dw_mipi_dsi_rockchip_config(dsi);
|
|
||||||
@@ -972,16 +972,20 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
|
|
||||||
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
|
|
||||||
if (ret) {
|
|
||||||
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
|
|
||||||
- return ret;
|
|
||||||
+ goto err_pllref_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
|
|
||||||
if (ret) {
|
|
||||||
DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
|
|
||||||
- return ret;
|
|
||||||
+ goto err_pllref_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
+
|
|
||||||
+err_pllref_disable:
|
|
||||||
+ clk_disable_unprepare(dsi->pllref_clk);
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
|
|
@ -1,42 +0,0 @@
|
|||||||
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
|
|
||||||
index f4166263bb3a..a248429194bb 100644
|
|
||||||
--- a/drivers/tty/vt/keyboard.c
|
|
||||||
+++ b/drivers/tty/vt/keyboard.c
|
|
||||||
@@ -49,6 +49,8 @@
|
|
||||||
|
|
||||||
#include <asm/irq_regs.h>
|
|
||||||
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Exported functions/variables
|
|
||||||
*/
|
|
||||||
@@ -1413,6 +1415,28 @@ static void kbd_keycode(unsigned int key
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+ /* Trap keys when bootsplash is shown */
|
|
||||||
+ if (bootsplash_would_render_now()) {
|
|
||||||
+ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */
|
|
||||||
+ if (keycode >= KEY_F1 && keycode <= KEY_F12) {
|
|
||||||
+ bootsplash_disable();
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * No return here since we want to actually
|
|
||||||
+ * perform the VT switch.
|
|
||||||
+ */
|
|
||||||
+ } else {
|
|
||||||
+ if (keycode == KEY_ESC)
|
|
||||||
+ bootsplash_disable();
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Just drop any other keys.
|
|
||||||
+ * Their effect would be hidden by the splash.
|
|
||||||
+ */
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (kbd->kbdmode == VC_MEDIUMRAW) {
|
|
||||||
/*
|
|
||||||
* This is extended medium raw mode, with keys above 127
|
|
@ -1,145 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 17 Oct 2021 20:14:25 +0200
|
|
||||||
Subject: [PATCH 04/36] drm: bridge: dw-mipi-dsi: Fix enable/disable of dsi
|
|
||||||
controller
|
|
||||||
|
|
||||||
The driver had it all wrong. mode_set is not for enabling the
|
|
||||||
DSI controller, that should be done in pre_enable so that
|
|
||||||
panel driver can initialize the panel (working dsi controller
|
|
||||||
is needed for that). Having dsi powerup in mode_set led to
|
|
||||||
all kind of fun, because disable would be called more often
|
|
||||||
than mode_set.
|
|
||||||
|
|
||||||
The whole panel/dsi enable/disable dance is such (for future
|
|
||||||
reference):
|
|
||||||
|
|
||||||
- dsi: mode set
|
|
||||||
- panel: prepare (we turn on panel power)
|
|
||||||
- dsi: pre enable (we enable and setup DSI)
|
|
||||||
- dsi: enable (we enable video data)
|
|
||||||
- panel: enable (we configure and turn on the display)
|
|
||||||
|
|
||||||
For disable:
|
|
||||||
|
|
||||||
- panel: disable (we turn off the display nicely)
|
|
||||||
- dsi: disable (we disable DSI)
|
|
||||||
- dsi: post disable
|
|
||||||
- panel: unprepare (we power off display power, panel should
|
|
||||||
be safely sleeping now)
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 45 +++++++++++++++++++--------
|
|
||||||
1 file changed, 32 insertions(+), 13 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
||||||
index e44e18a..9cce2ab 100644
|
|
||||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
||||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
|
|
||||||
@@ -266,6 +266,7 @@ struct dw_mipi_dsi {
|
|
||||||
struct dw_mipi_dsi *master; /* dual-dsi master ptr */
|
|
||||||
struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
|
|
||||||
|
|
||||||
+ struct drm_display_mode mode;
|
|
||||||
const struct dw_mipi_dsi_plat_data *plat_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -597,6 +598,8 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
|
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
+ dev_info(dsi->dev, "mode %d\n", (int)mode_flags);
|
|
||||||
+
|
|
||||||
dsi_write(dsi, DSI_PWR_UP, RESET);
|
|
||||||
|
|
||||||
if (mode_flags & MIPI_DSI_MODE_VIDEO) {
|
|
||||||
@@ -871,11 +874,20 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
|
|
||||||
dsi_write(dsi, DSI_INT_MSK1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void dw_mipi_dsi_bridge_disable(struct drm_bridge *bridge)
|
|
||||||
+{
|
|
||||||
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
|
|
||||||
+
|
|
||||||
+ dev_info(dsi->dev, "disable\n");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
|
|
||||||
{
|
|
||||||
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
|
|
||||||
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
|
|
||||||
|
|
||||||
+ dev_info(dsi->dev, "post disable\n");
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Switch to command mode before panel-bridge post_disable &
|
|
||||||
* panel unprepare.
|
|
||||||
@@ -884,15 +896,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
|
|
||||||
*/
|
|
||||||
dw_mipi_dsi_set_mode(dsi, 0);
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * TODO Only way found to call panel-bridge post_disable &
|
|
||||||
- * panel unprepare before the dsi "final" disable...
|
|
||||||
- * This needs to be fixed in the drm_bridge framework and the API
|
|
||||||
- * needs to be updated to manage our own call chains...
|
|
||||||
- */
|
|
||||||
- if (dsi->panel_bridge->funcs->post_disable)
|
|
||||||
- dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
|
|
||||||
-
|
|
||||||
if (phy_ops->power_off)
|
|
||||||
phy_ops->power_off(dsi->plat_data->priv_data);
|
|
||||||
|
|
||||||
@@ -921,7 +924,7 @@ static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
|
|
||||||
return dsi->lanes;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
|
|
||||||
+static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi,
|
|
||||||
const struct drm_display_mode *adjusted_mode)
|
|
||||||
{
|
|
||||||
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
|
|
||||||
@@ -973,16 +976,30 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
|
||||||
{
|
|
||||||
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
|
|
||||||
|
|
||||||
- dw_mipi_dsi_mode_set(dsi, adjusted_mode);
|
|
||||||
+ dev_info(dsi->dev, "mode set\n");
|
|
||||||
+
|
|
||||||
+ /* Store the display mode for plugin/DKMS poweron events */
|
|
||||||
+ memcpy(&dsi->mode, mode, sizeof(dsi->mode));
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dw_mipi_dsi_bridge_pre_enable(struct drm_bridge *bridge)
|
|
||||||
+{
|
|
||||||
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
|
|
||||||
+
|
|
||||||
+ dev_info(dsi->dev, "pre enable\n");
|
|
||||||
+
|
|
||||||
+ /* power up the dsi ctl into a command mode */
|
|
||||||
+ dw_mipi_dsi_enable(dsi, &dsi->mode);
|
|
||||||
if (dsi->slave)
|
|
||||||
- dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
|
|
||||||
+ dw_mipi_dsi_enable(dsi->slave, &dsi->mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
|
|
||||||
{
|
|
||||||
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
|
|
||||||
|
|
||||||
- /* Switch to video mode for panel-bridge enable & panel enable */
|
|
||||||
+ dev_info(dsi->dev, "enable\n");
|
|
||||||
+
|
|
||||||
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
|
|
||||||
if (dsi->slave)
|
|
||||||
dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
|
|
||||||
@@ -1033,7 +1050,9 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
|
|
||||||
|
|
||||||
static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
|
|
||||||
.mode_set = dw_mipi_dsi_bridge_mode_set,
|
|
||||||
+ .pre_enable = dw_mipi_dsi_bridge_pre_enable,
|
|
||||||
.enable = dw_mipi_dsi_bridge_enable,
|
|
||||||
+ .disable = dw_mipi_dsi_bridge_disable,
|
|
||||||
.post_disable = dw_mipi_dsi_bridge_post_disable,
|
|
||||||
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
|
|
||||||
.attach = dw_mipi_dsi_bridge_attach,
|
|
@ -1,21 +0,0 @@
|
|||||||
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
|
|
||||||
index 3ffc1ce29023..bc6a24c9dfa8 100644
|
|
||||||
--- a/drivers/tty/sysrq.c
|
|
||||||
+++ b/drivers/tty/sysrq.c
|
|
||||||
@@ -49,6 +49,7 @@
|
|
||||||
#include <linux/syscalls.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
+#include <linux/bootsplash.h>
|
|
||||||
|
|
||||||
#include <asm/ptrace.h>
|
|
||||||
#include <asm/irq_regs.h>
|
|
||||||
@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key)
|
|
||||||
{
|
|
||||||
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
|
|
||||||
schedule_work(SAK_work);
|
|
||||||
+
|
|
||||||
+ bootsplash_disable();
|
|
||||||
}
|
|
||||||
static struct sysrq_key_op sysrq_SAK_op = {
|
|
||||||
.handler = sysrq_handle_SAK,
|
|
@ -1,28 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 16 Nov 2021 21:16:26 +0100
|
|
||||||
Subject: [PATCH 07/36] drm: dw-mipi-dsi-rockchip: Never allow lane bandwidth
|
|
||||||
to be less than requested
|
|
||||||
|
|
||||||
Bandwidth can be less than requested in some cases, because the search
|
|
||||||
for best values only checked for absolute difference from ideal value.
|
|
||||||
|
|
||||||
This is likely not intentional.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
index 095d0f1..bd488a8 100644
|
|
||||||
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
||||||
@@ -612,7 +612,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
|
|
||||||
continue;
|
|
||||||
|
|
||||||
delta = abs(fout - tmp);
|
|
||||||
- if (delta < min_delta) {
|
|
||||||
+ if (delta < min_delta && fout < tmp) {
|
|
||||||
best_prediv = _prediv;
|
|
||||||
best_fbdiv = _fbdiv;
|
|
||||||
min_delta = delta;
|
|
@ -1,21 +0,0 @@
|
|||||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
index 9a39a6fcfe98..8a9c67e1c5d8 100644
|
|
||||||
--- a/drivers/video/fbdev/core/fbcon.c
|
|
||||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
|
||||||
@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
|
||||||
int y;
|
|
||||||
int c = scr_readw((u16 *) vc->vc_pos);
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * Disable the splash here so we don't have to hook into
|
|
||||||
+ * vt_console_print() in drivers/tty/vt/vt.c
|
|
||||||
+ *
|
|
||||||
+ * We'd disable the splash just before the call to
|
|
||||||
+ * hide_cursor() anyway, so this spot is just fine.
|
|
||||||
+ */
|
|
||||||
+ if (oops_in_progress)
|
|
||||||
+ bootsplash_disable();
|
|
||||||
+
|
|
||||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
|
||||||
|
|
||||||
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
|
|
@ -1,23 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sat, 20 Nov 2021 14:35:52 +0100
|
|
||||||
Subject: [PATCH 09/36] drm: rockchip: cdn-dp: Disable CDN DP on disconnect
|
|
||||||
|
|
||||||
Why not?
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
||||||
index 16497c3..f4dcd9e 100644
|
|
||||||
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
||||||
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
||||||
@@ -934,6 +934,7 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
|
|
||||||
DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n");
|
|
||||||
dp->connected = false;
|
|
||||||
|
|
||||||
+ cdn_dp_disable(dp);
|
|
||||||
/* Connected but not enabled, enable the block */
|
|
||||||
} else if (!dp->active) {
|
|
||||||
DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n");
|
|
@ -1,321 +0,0 @@
|
|||||||
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..742c7b035ded
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
@@ -0,0 +1,11 @@
|
|
||||||
+What: /sys/devices/platform/bootsplash.0/enabled
|
|
||||||
+Date: Oct 2017
|
|
||||||
+KernelVersion: 4.14
|
|
||||||
+Contact: Max Staudt <mstaudt@suse.de>
|
|
||||||
+Description:
|
|
||||||
+ Can be set and read.
|
|
||||||
+
|
|
||||||
+ 0: Splash is disabled.
|
|
||||||
+ 1: Splash is shown whenever fbcon would show a text console
|
|
||||||
+ (i.e. no graphical application is running), and a splash
|
|
||||||
+ file is loaded.
|
|
||||||
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..611f0c558925
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/Documentation/bootsplash.rst
|
|
||||||
@@ -0,0 +1,285 @@
|
|
||||||
+====================
|
|
||||||
+The Linux bootsplash
|
|
||||||
+====================
|
|
||||||
+
|
|
||||||
+:Date: November, 2017
|
|
||||||
+:Author: Max Staudt <mstaudt@suse.de>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+The Linux bootsplash is a graphical replacement for the '``quiet``' boot
|
|
||||||
+option, typically showing a logo and a spinner animation as the system starts.
|
|
||||||
+
|
|
||||||
+Currently, it is a part of the Framebuffer Console support, and can be found
|
|
||||||
+as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long
|
|
||||||
+as it is enabled, it hijacks fbcon's output and draws a splash screen instead.
|
|
||||||
+
|
|
||||||
+Purely compiling in the bootsplash will not render it functional - to actually
|
|
||||||
+render a splash, you will also need a splash theme file. See the example
|
|
||||||
+utility and script in ``tools/bootsplash`` for a live demo.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Motivation
|
|
||||||
+==========
|
|
||||||
+
|
|
||||||
+- The '``quiet``' boot option only suppresses most messages during boot, but
|
|
||||||
+ errors are still shown.
|
|
||||||
+
|
|
||||||
+- A user space implementation can only show a logo once user space has been
|
|
||||||
+ initialized far enough to allow this. A kernel splash can display a splash
|
|
||||||
+ immediately as soon as fbcon can be displayed.
|
|
||||||
+
|
|
||||||
+- Implementing a splash screen in user space (e.g. Plymouth) is problematic
|
|
||||||
+ due to resource conflicts.
|
|
||||||
+
|
|
||||||
+ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb)
|
|
||||||
+ open, then most DRM drivers can't replace it because the address space is
|
|
||||||
+ still busy - thus leading to a VRAM reservation error.
|
|
||||||
+
|
|
||||||
+ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Command line arguments
|
|
||||||
+======================
|
|
||||||
+
|
|
||||||
+``bootsplash.bootfile``
|
|
||||||
+ Which file in the initramfs to load.
|
|
||||||
+
|
|
||||||
+ The splash theme is loaded via request_firmware(), thus to load
|
|
||||||
+ ``/lib/firmware/bootsplash/mytheme`` pass the command line:
|
|
||||||
+
|
|
||||||
+ ``bootsplash.bootfile=bootsplash/mytheme``
|
|
||||||
+
|
|
||||||
+ Note: The splash file *has to be* in the initramfs, as it needs to be
|
|
||||||
+ available when the splash is initialized early on.
|
|
||||||
+
|
|
||||||
+ Default: none, i.e. a non-functional splash, falling back to showing text.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+sysfs run-time configuration
|
|
||||||
+============================
|
|
||||||
+
|
|
||||||
+``/sys/devices/platform/bootsplash.0/enabled``
|
|
||||||
+ Enable/disable the bootsplash.
|
|
||||||
+ The system boots with this set to 1, but will not show a splash unless
|
|
||||||
+ a splash theme file is also loaded.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Kconfig
|
|
||||||
+=======
|
|
||||||
+
|
|
||||||
+``BOOTSPLASH``
|
|
||||||
+ Whether to compile in bootsplash support
|
|
||||||
+ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Bootsplash file format
|
|
||||||
+======================
|
|
||||||
+
|
|
||||||
+A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE``
|
|
||||||
+or specified on the command line as ``bootsplash.bootfile`` will be loaded
|
|
||||||
+and displayed as soon as fbcon is initialized.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Main blocks
|
|
||||||
+-----------
|
|
||||||
+
|
|
||||||
+There are 3 main blocks in each file:
|
|
||||||
+
|
|
||||||
+ - one File header
|
|
||||||
+ - n Picture headers
|
|
||||||
+ - m (Blob header + payload) blocks
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Structures
|
|
||||||
+----------
|
|
||||||
+
|
|
||||||
+The on-disk structures are defined in
|
|
||||||
+``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks:
|
|
||||||
+
|
|
||||||
+ - ``struct splash_file_header``
|
|
||||||
+
|
|
||||||
+ Represents the file header, with splash-wide information including:
|
|
||||||
+
|
|
||||||
+ - The magic string "``Linux bootsplash``" on big-endian platforms
|
|
||||||
+ (the reverse on little endian)
|
|
||||||
+ - The file format version (for incompatible updates, hopefully never)
|
|
||||||
+ - The background color
|
|
||||||
+ - Number of picture and blob blocks
|
|
||||||
+ - Animation speed (we only allow one delay for all animations)
|
|
||||||
+
|
|
||||||
+ The file header is followed by the first picture header.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ - ``struct splash_picture_header``
|
|
||||||
+
|
|
||||||
+ Represents an object (picture) drawn on screen, including its immutable
|
|
||||||
+ properties:
|
|
||||||
+ - Width, height
|
|
||||||
+ - Positioning relative to screen corners or in the center
|
|
||||||
+ - Animation, if any
|
|
||||||
+ - Animation type
|
|
||||||
+ - Number of blobs
|
|
||||||
+
|
|
||||||
+ The picture header is followed by another picture header, up until n
|
|
||||||
+ picture headers (as defined in the file header) have been read. Then,
|
|
||||||
+ the (blob header, payload) pairs follow.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ - ``struct splash_blob_header``
|
|
||||||
+ (followed by payload)
|
|
||||||
+
|
|
||||||
+ Represents one raw data stream. So far, only picture data is defined.
|
|
||||||
+
|
|
||||||
+ The blob header is followed by a payload, then padding to n*16 bytes,
|
|
||||||
+ then (if further blobs are defined in the file header) a further blob
|
|
||||||
+ header.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Alignment
|
|
||||||
+---------
|
|
||||||
+
|
|
||||||
+The bootsplash file is designed to be loaded into memory as-is.
|
|
||||||
+
|
|
||||||
+All structures are a multiple of 16 bytes long, all elements therein are
|
|
||||||
+aligned to multiples of their length, and the payloads are always padded
|
|
||||||
+up to multiples of 16 bytes. This is to allow aligned accesses in all
|
|
||||||
+cases while still simply mapping the structures over an in-memory copy of
|
|
||||||
+the bootsplash file.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Further information
|
|
||||||
+-------------------
|
|
||||||
+
|
|
||||||
+Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further
|
|
||||||
+details and possible values in the file.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Hooks - how the bootsplash is integrated
|
|
||||||
+========================================
|
|
||||||
+
|
|
||||||
+``drivers/video/fbdev/core/fbcon.c``
|
|
||||||
+ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default
|
|
||||||
+ bootsplash file or the one specified on the kernel command line.
|
|
||||||
+
|
|
||||||
+ ``fbcon_switch()`` draws the bootsplash when it's active, and is also
|
|
||||||
+ one of the callers of ``set_blitting_type()``.
|
|
||||||
+
|
|
||||||
+ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the
|
|
||||||
+ bootsplash is active, overriding the text rendering functions.
|
|
||||||
+
|
|
||||||
+ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is
|
|
||||||
+ being printed in order to make a kernel panic visible.
|
|
||||||
+
|
|
||||||
+``drivers/video/fbdev/core/dummyblit.c``
|
|
||||||
+ This contains the dummy text rendering functions used to suppress text
|
|
||||||
+ output while the bootsplash is shown.
|
|
||||||
+
|
|
||||||
+``drivers/tty/vt/keyboard.c``
|
|
||||||
+ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user
|
|
||||||
+ presses ESC or F1-F12 (changing VT). This is to provide a built-in way
|
|
||||||
+ of disabling the splash manually at any time.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+FAQ: Frequently Asked Questions
|
|
||||||
+===============================
|
|
||||||
+
|
|
||||||
+I want to see the log! How do I show the log?
|
|
||||||
+---------------------------------------------
|
|
||||||
+
|
|
||||||
+Press ESC while the splash is shown, or remove the ``bootsplash.bootfile``
|
|
||||||
+parameter from the kernel cmdline. Without that parameter, the bootsplash
|
|
||||||
+will boot disabled.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Why use FB instead of modern DRM/KMS?
|
|
||||||
+-------------------------------------
|
|
||||||
+
|
|
||||||
+This is a semantic problem:
|
|
||||||
+ - What memory to draw the splash to?
|
|
||||||
+ - And what mode will the screen be set to?
|
|
||||||
+
|
|
||||||
+Using the fbdev emulation solves these issues.
|
|
||||||
+
|
|
||||||
+Let's start from a bare KMS system, without fbcon, and without fbdev
|
|
||||||
+emulation. In this case, as long as userspace doesn't open the KMS
|
|
||||||
+device, the state of the screen is undefined. No framebuffer is
|
|
||||||
+allocated in video RAM, and no particular mode is set.
|
|
||||||
+
|
|
||||||
+In this case, we'd have to allocate a framebuffer to show the splash,
|
|
||||||
+and set our mode ourselves. This either wastes a screenful of video RAM
|
|
||||||
+if the splash is to co-exist with the userspace program's own allocated
|
|
||||||
+framebuffer, or there is a flicker as we deactivate and delete the
|
|
||||||
+bootsplash's framebuffer and hand control over to userspace. Since we
|
|
||||||
+may set a different mode than userspace, we'd also have flicker due
|
|
||||||
+to mode switching.
|
|
||||||
+
|
|
||||||
+This logic is already contained in every KMS driver that performs fbdev
|
|
||||||
+emulation. So we might as well use that. And the correct API to do so is
|
|
||||||
+fbdev. Plus, we get compatibility with old, pure fbdev drivers for free.
|
|
||||||
+With the fbdev emulation, there is *always* a well-defined framebuffer
|
|
||||||
+to draw on. And the selection of mode has already been done by the
|
|
||||||
+graphics driver, so we don't need to reinvent that wheel, either.
|
|
||||||
+Finally, if userspace decides to use /dev/fbX, we don't have to worry
|
|
||||||
+about wasting video RAM, either.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Why is the bootsplash integrated in fbcon?
|
|
||||||
+------------------------------------------
|
|
||||||
+
|
|
||||||
+Right now, the bootsplash is drawn from within fbcon, as this allows us
|
|
||||||
+to easily know *when* to draw - i.e. when we're safe from fbcon and
|
|
||||||
+userspace drawing all over our beautiful splash logo.
|
|
||||||
+
|
|
||||||
+Separating them is not easy - see the to-do list below.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+TO DO list for future development
|
|
||||||
+=================================
|
|
||||||
+
|
|
||||||
+Second enable/disable switch for the system
|
|
||||||
+-------------------------------------------
|
|
||||||
+
|
|
||||||
+It may be helpful to differentiate between the system and the user
|
|
||||||
+switching off the bootsplash. Thus, the system may make it disappear and
|
|
||||||
+reappear e.g. for a password prompt, yet once the user has pressed ESC,
|
|
||||||
+it could stay gone.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Fix buggy DRM/KMS drivers
|
|
||||||
+-------------------------
|
|
||||||
+
|
|
||||||
+Currently, the splash code manually checks for fbdev emulation provided by
|
|
||||||
+the ast, cirrus, and mgag200 DRM/KMS drivers.
|
|
||||||
+These drivers use a manual mechanism similar to deferred I/O for their FB
|
|
||||||
+emulation, and thus need to be manually flushed onto the screen in the same
|
|
||||||
+way.
|
|
||||||
+
|
|
||||||
+This may be improved upon in several ways:
|
|
||||||
+
|
|
||||||
+1. Changing these drivers to expose the fbdev BO's memory directly, like
|
|
||||||
+ bochsdrmfb does.
|
|
||||||
+2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the
|
|
||||||
+ framebuffer once the bootsplash has been drawn into it.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+Separating from fbcon
|
|
||||||
+---------------------
|
|
||||||
+
|
|
||||||
+Separating these two components would yield independence from fbcon being
|
|
||||||
+compiled into the kernel, and thus lowering code size in embedded
|
|
||||||
+applications.
|
|
||||||
+
|
|
||||||
+To do this cleanly will involve a clean separation of users of an FB device
|
|
||||||
+within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the
|
|
||||||
+legacy fbcon code and VT code co-operate to switch between fbcon and
|
|
||||||
+userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer
|
|
||||||
+between these components ensues refactoring of old code and checking for
|
|
||||||
+correct locking.
|
|
||||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
||||||
index 5c237445761e..7ffac272434e 100644
|
|
||||||
--- a/MAINTAINERS
|
|
||||||
+++ b/MAINTAINERS
|
|
||||||
@@ -2709,6 +2709,8 @@ BOOTSPLASH
|
|
||||||
M: Max Staudt <mstaudt@suse.de>
|
|
||||||
L: linux-fbdev@vger.kernel.org
|
|
||||||
S: Maintained
|
|
||||||
+F: Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
+F: Documentation/bootsplash.rst
|
|
||||||
F: drivers/video/fbdev/core/bootsplash*.*
|
|
||||||
F: drivers/video/fbdev/core/dummycon.c
|
|
||||||
F: include/linux/bootsplash.h
|
|
@ -1,69 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 17 Oct 2021 12:46:01 +0200
|
|
||||||
Subject: [PATCH 10/36] video: fbdev: Add events for early fb event support
|
|
||||||
|
|
||||||
This patch adds FB_EARLY_EVENT_BLANK and FB_R_EARLY_EVENT_BLANK
|
|
||||||
event mode supports. first, fb_notifier_call_chain() is called with
|
|
||||||
FB_EARLY_EVENT_BLANK and fb_blank() of specific fb driver is called
|
|
||||||
and then fb_notifier_call_chain() is called with FB_EVENT_BLANK again
|
|
||||||
at fb_blank(). and if fb_blank() was failed then fb_nitifier_call_chain()
|
|
||||||
would be called with FB_R_EARLY_EVENT_BLANK to revert the previous effects.
|
|
||||||
|
|
||||||
Signed-off-by: Inki Dae <inki.dae@samsung.com>
|
|
||||||
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
|
|
||||||
---
|
|
||||||
drivers/video/fbdev/core/fbmem.c | 12 +++++++++++-
|
|
||||||
include/linux/fb.h | 5 +++++
|
|
||||||
2 files changed, 16 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
|
|
||||||
index 826175a..fb1651a 100644
|
|
||||||
--- a/drivers/video/fbdev/core/fbmem.c
|
|
||||||
+++ b/drivers/video/fbdev/core/fbmem.c
|
|
||||||
@@ -1067,7 +1067,7 @@ int
|
|
||||||
fb_blank(struct fb_info *info, int blank)
|
|
||||||
{
|
|
||||||
struct fb_event event;
|
|
||||||
- int ret = -EINVAL;
|
|
||||||
+ int ret = -EINVAL, early_ret;
|
|
||||||
|
|
||||||
if (blank > FB_BLANK_POWERDOWN)
|
|
||||||
blank = FB_BLANK_POWERDOWN;
|
|
||||||
@@ -1075,11 +1075,21 @@ fb_blank(struct fb_info *info, int blank)
|
|
||||||
event.info = info;
|
|
||||||
event.data = ␣
|
|
||||||
|
|
||||||
+ early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
|
|
||||||
+
|
|
||||||
if (info->fbops->fb_blank)
|
|
||||||
ret = info->fbops->fb_blank(blank, info);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
|
|
||||||
+ else {
|
|
||||||
+ /*
|
|
||||||
+ * if fb_blank is failed then revert effects of
|
|
||||||
+ * the early blank event.
|
|
||||||
+ */
|
|
||||||
+ if (!early_ret)
|
|
||||||
+ fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
diff --git a/include/linux/fb.h b/include/linux/fb.h
|
|
||||||
index 6f3db99..ffef502a 100644
|
|
||||||
--- a/include/linux/fb.h
|
|
||||||
+++ b/include/linux/fb.h
|
|
||||||
@@ -137,6 +137,11 @@ struct fb_cursor_user {
|
|
||||||
/* A display blank is requested */
|
|
||||||
#define FB_EVENT_BLANK 0x09
|
|
||||||
|
|
||||||
+/* A hardware display blank early change occured */
|
|
||||||
+#define FB_EARLY_EVENT_BLANK 0x10
|
|
||||||
+/* A hardware display blank revert early change occured */
|
|
||||||
+#define FB_R_EARLY_EVENT_BLANK 0x11
|
|
||||||
+
|
|
||||||
struct fb_event {
|
|
||||||
struct fb_info *info;
|
|
||||||
void *data;
|
|
@ -1,129 +0,0 @@
|
|||||||
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
index 742c7b035ded..f8f4b259220e 100644
|
|
||||||
--- a/Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
|
||||||
@@ -9,3 +9,35 @@ Description:
|
|
||||||
1: Splash is shown whenever fbcon would show a text console
|
|
||||||
(i.e. no graphical application is running), and a splash
|
|
||||||
file is loaded.
|
|
||||||
+
|
|
||||||
+What: /sys/devices/platform/bootsplash.0/drop_splash
|
|
||||||
+Date: Oct 2017
|
|
||||||
+KernelVersion: 4.14
|
|
||||||
+Contact: Max Staudt <mstaudt@suse.de>
|
|
||||||
+Description:
|
|
||||||
+ Can only be set.
|
|
||||||
+
|
|
||||||
+ Any value written will cause the current splash theme file
|
|
||||||
+ to be unloaded and the text console to be redrawn.
|
|
||||||
+
|
|
||||||
+What: /sys/devices/platform/bootsplash.0/load_file
|
|
||||||
+Date: Oct 2017
|
|
||||||
+KernelVersion: 4.14
|
|
||||||
+Contact: Max Staudt <mstaudt@suse.de>
|
|
||||||
+Description:
|
|
||||||
+ Can only be set.
|
|
||||||
+
|
|
||||||
+ Any value written will cause the splash to be disabled and
|
|
||||||
+ internal memory structures to be freed.
|
|
||||||
+
|
|
||||||
+ A firmware path written will cause a new theme file to be
|
|
||||||
+ loaded and the current bootsplash to be replaced.
|
|
||||||
+ The current enabled/disabled status is not touched.
|
|
||||||
+ If the splash is already active, it will be redrawn.
|
|
||||||
+
|
|
||||||
+ The path has to be a path in /lib/firmware since
|
|
||||||
+ request_firmware() is used to fetch the data.
|
|
||||||
+
|
|
||||||
+ When setting the splash from the shell, echo -n has to be
|
|
||||||
+ used as any trailing '\n' newline will be interpreted as
|
|
||||||
+ part of the path.
|
|
||||||
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
|
|
||||||
index 611f0c558925..b35aba5093e8 100644
|
|
||||||
--- a/Documentation/bootsplash.rst
|
|
||||||
+++ b/Documentation/bootsplash.rst
|
|
||||||
@@ -67,6 +67,14 @@ sysfs run-time configuration
|
|
||||||
a splash theme file is also loaded.
|
|
||||||
|
|
||||||
|
|
||||||
+``/sys/devices/platform/bootsplash.0/drop_splash``
|
|
||||||
+ Unload splash data and free memory.
|
|
||||||
+
|
|
||||||
+``/sys/devices/platform/bootsplash.0/load_file``
|
|
||||||
+ Load a splash file from ``/lib/firmware/``.
|
|
||||||
+ Note that trailing newlines will be interpreted as part of the file name.
|
|
||||||
+
|
|
||||||
+
|
|
||||||
|
|
||||||
Kconfig
|
|
||||||
=======
|
|
||||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
index 13fcaabbc2ca..16cb0493629d 100644
|
|
||||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
|
||||||
@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device,
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static ssize_t splash_store_drop_splash(struct device *device,
|
|
||||||
+ struct device_attribute *attr,
|
|
||||||
+ const char *buf, size_t count)
|
|
||||||
+{
|
|
||||||
+ struct splash_file_priv *fp;
|
|
||||||
+
|
|
||||||
+ if (!buf || !count || !splash_state.file)
|
|
||||||
+ return count;
|
|
||||||
+
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ fp = splash_state.file;
|
|
||||||
+ splash_state.file = NULL;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
+ /* Redraw the text console */
|
|
||||||
+ schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+
|
|
||||||
+ bootsplash_free_file(fp);
|
|
||||||
+
|
|
||||||
+ return count;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static ssize_t splash_store_load_file(struct device *device,
|
|
||||||
+ struct device_attribute *attr,
|
|
||||||
+ const char *buf, size_t count)
|
|
||||||
+{
|
|
||||||
+ struct splash_file_priv *fp, *fp_old;
|
|
||||||
+
|
|
||||||
+ if (!count)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
|
|
||||||
+ buf);
|
|
||||||
+
|
|
||||||
+ if (!fp)
|
|
||||||
+ return -ENXIO;
|
|
||||||
+
|
|
||||||
+ mutex_lock(&splash_state.data_lock);
|
|
||||||
+ fp_old = splash_state.file;
|
|
||||||
+ splash_state.splash_fb = NULL;
|
|
||||||
+ splash_state.file = fp;
|
|
||||||
+ mutex_unlock(&splash_state.data_lock);
|
|
||||||
+
|
|
||||||
+ /* Update the splash or text console */
|
|
||||||
+ schedule_work(&splash_state.work_redraw_vc);
|
|
||||||
+
|
|
||||||
+ bootsplash_free_file(fp_old);
|
|
||||||
+ return count;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
|
|
||||||
+static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash);
|
|
||||||
+static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file);
|
|
||||||
|
|
||||||
|
|
||||||
static struct attribute *splash_dev_attrs[] = {
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
+ &dev_attr_drop_splash.attr,
|
|
||||||
+ &dev_attr_load_file.attr,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
|
|
||||||
Date: Mon, 4 Jan 2021 17:57:49 +0100
|
|
||||||
Subject: [PATCH 11/36] power: rk818: Configure `rk808-clkout2` function
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset="utf-8"
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
???
|
|
||||||
|
|
||||||
Signed-of-by: Kamil Trzciński <ayufan@ayufan.eu>
|
|
||||||
---
|
|
||||||
drivers/mfd/rk808.c | 1 +
|
|
||||||
include/linux/mfd/rk808.h | 2 ++
|
|
||||||
2 files changed, 3 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
|
|
||||||
index b181fe4..1a6857e 100644
|
|
||||||
--- a/drivers/mfd/rk808.c
|
|
||||||
+++ b/drivers/mfd/rk808.c
|
|
||||||
@@ -303,6 +303,7 @@ static const struct rk808_reg_data rk818_pre_init_reg[] = {
|
|
||||||
{ RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
|
|
||||||
{ RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
|
|
||||||
VB_LO_SEL_3500MV },
|
|
||||||
+ { RK808_CLK32OUT_REG, CLK32KOUT2_FUNC_MASK, CLK32KOUT2_FUNC },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct regmap_irq rk805_irqs[] = {
|
|
||||||
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
|
|
||||||
index a96e6d4..2ec0520 100644
|
|
||||||
--- a/include/linux/mfd/rk808.h
|
|
||||||
+++ b/include/linux/mfd/rk808.h
|
|
||||||
@@ -381,6 +381,8 @@ enum rk805_reg {
|
|
||||||
|
|
||||||
#define VOUT_LO_INT BIT(0)
|
|
||||||
#define CLK32KOUT2_EN BIT(0)
|
|
||||||
+#define CLK32KOUT2_FUNC (0 << 1)
|
|
||||||
+#define CLK32KOUT2_FUNC_MASK BIT(1)
|
|
||||||
|
|
||||||
#define TEMP115C 0x0c
|
|
||||||
#define TEMP_HOTDIE_MSK 0x0c
|
|
@ -1,511 +0,0 @@
|
|||||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
||||||
index 7ffac272434e..ddff07cd794c 100644
|
|
||||||
--- a/MAINTAINERS
|
|
||||||
+++ b/MAINTAINERS
|
|
||||||
@@ -2715,6 +2715,7 @@ F: drivers/video/fbdev/core/bootsplash*.*
|
|
||||||
F: drivers/video/fbdev/core/dummycon.c
|
|
||||||
F: include/linux/bootsplash.h
|
|
||||||
F: include/uapi/linux/bootsplash_file.h
|
|
||||||
+F: tools/bootsplash/*
|
|
||||||
|
|
||||||
BPF (Safe dynamic programs and tools)
|
|
||||||
M: Alexei Starovoitov <ast@kernel.org>
|
|
||||||
diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..091b99a17567
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tools/bootsplash/.gitignore
|
|
||||||
@@ -0,0 +1 @@
|
|
||||||
+bootsplash-packer
|
|
||||||
diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..0ad8e8a84942
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tools/bootsplash/Makefile
|
|
||||||
@@ -0,0 +1,9 @@
|
|
||||||
+CC := $(CROSS_COMPILE)gcc
|
|
||||||
+CFLAGS := -I../../usr/include
|
|
||||||
+
|
|
||||||
+PROGS := bootsplash-packer
|
|
||||||
+
|
|
||||||
+all: $(PROGS)
|
|
||||||
+
|
|
||||||
+clean:
|
|
||||||
+ rm -fr $(PROGS)
|
|
||||||
diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..ffb6a8b69885
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tools/bootsplash/bootsplash-packer.c
|
|
||||||
@@ -0,0 +1,471 @@
|
|
||||||
+/*
|
|
||||||
+ * Kernel based bootsplash.
|
|
||||||
+ *
|
|
||||||
+ * (Splash file packer tool)
|
|
||||||
+ *
|
|
||||||
+ * Authors:
|
|
||||||
+ * Max Staudt <mstaudt@suse.de>
|
|
||||||
+ *
|
|
||||||
+ * SPDX-License-Identifier: GPL-2.0
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <endian.h>
|
|
||||||
+#include <getopt.h>
|
|
||||||
+#include <stdint.h>
|
|
||||||
+#include <stdio.h>
|
|
||||||
+#include <stdlib.h>
|
|
||||||
+#include <string.h>
|
|
||||||
+
|
|
||||||
+#include <linux/bootsplash_file.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void print_help(char *progname)
|
|
||||||
+{
|
|
||||||
+ printf("Usage: %s [OPTIONS] outfile\n", progname);
|
|
||||||
+ printf("\n"
|
|
||||||
+ "Options, executed in order given:\n"
|
|
||||||
+ " -h, --help Print this help message\n"
|
|
||||||
+ "\n"
|
|
||||||
+ " --bg_red <u8> Background color (red part)\n"
|
|
||||||
+ " --bg_green <u8> Background color (green part)\n"
|
|
||||||
+ " --bg_blue <u8> Background color (blue part)\n"
|
|
||||||
+ " --bg_reserved <u8> (do not use)\n"
|
|
||||||
+ " --frame_ms <u16> Minimum milliseconds between animation steps\n"
|
|
||||||
+ "\n"
|
|
||||||
+ " --picture Start describing the next picture\n"
|
|
||||||
+ " --pic_width <u16> Picture width in pixels\n"
|
|
||||||
+ " --pic_height <u16> Picture height in pixels\n"
|
|
||||||
+ " --pic_position <u8> Coarse picture placement:\n"
|
|
||||||
+ " 0x00 - Top left\n"
|
|
||||||
+ " 0x01 - Top\n"
|
|
||||||
+ " 0x02 - Top right\n"
|
|
||||||
+ " 0x03 - Right\n"
|
|
||||||
+ " 0x04 - Bottom right\n"
|
|
||||||
+ " 0x05 - Bottom\n"
|
|
||||||
+ " 0x06 - Bottom left\n"
|
|
||||||
+ " 0x07 - Left\n"
|
|
||||||
+ "\n"
|
|
||||||
+ " Flags:\n"
|
|
||||||
+ " 0x10 - Calculate offset from corner towards center,\n"
|
|
||||||
+ " rather than from center towards corner\n"
|
|
||||||
+ " --pic_position_offset <u16> Distance from base position in pixels\n"
|
|
||||||
+ " --pic_anim_type <u8> Animation type:\n"
|
|
||||||
+ " 0 - None\n"
|
|
||||||
+ " 1 - Forward loop\n"
|
|
||||||
+ " --pic_anim_loop <u8> Loop point for animation\n"
|
|
||||||
+ "\n"
|
|
||||||
+ " --blob <filename> Include next data stream\n"
|
|
||||||
+ " --blob_type <u16> Type of data\n"
|
|
||||||
+ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n"
|
|
||||||
+ " (default: number of last --picture)\n"
|
|
||||||
+ "\n");
|
|
||||||
+ printf("This tool will write %s files.\n\n",
|
|
||||||
+#if __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
+ "Big Endian (BE)");
|
|
||||||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
+ "Little Endian (LE)");
|
|
||||||
+#else
|
|
||||||
+#error
|
|
||||||
+#endif
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+struct blob_entry {
|
|
||||||
+ struct blob_entry *next;
|
|
||||||
+
|
|
||||||
+ char *fn;
|
|
||||||
+
|
|
||||||
+ struct splash_blob_header header;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void dump_file_header(struct splash_file_header *h)
|
|
||||||
+{
|
|
||||||
+ printf(" --- File header ---\n");
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" version: %5u\n", h->version);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" bg_red: %5u\n", h->bg_red);
|
|
||||||
+ printf(" bg_green: %5u\n", h->bg_green);
|
|
||||||
+ printf(" bg_blue: %5u\n", h->bg_blue);
|
|
||||||
+ printf(" bg_reserved: %5u\n", h->bg_reserved);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" num_blobs: %5u\n", h->num_blobs);
|
|
||||||
+ printf(" num_pics: %5u\n", h->num_pics);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" frame_ms: %5u\n", h->frame_ms);
|
|
||||||
+ printf("\n");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dump_pic_header(struct splash_pic_header *ph)
|
|
||||||
+{
|
|
||||||
+ printf(" --- Picture header ---\n");
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" width: %5u\n", ph->width);
|
|
||||||
+ printf(" height: %5u\n", ph->height);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" num_blobs: %5u\n", ph->num_blobs);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" position: %0x3x\n", ph->position);
|
|
||||||
+ printf(" position_offset: %5u\n", ph->position_offset);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" anim_type: %5u\n", ph->anim_type);
|
|
||||||
+ printf(" anim_loop: %5u\n", ph->anim_loop);
|
|
||||||
+ printf("\n");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dump_blob(struct blob_entry *b)
|
|
||||||
+{
|
|
||||||
+ printf(" --- Blob header ---\n");
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" length: %7u\n", b->header.length);
|
|
||||||
+ printf(" type: %7u\n", b->header.type);
|
|
||||||
+ printf("\n");
|
|
||||||
+ printf(" picture_id: %7u\n", b->header.picture_id);
|
|
||||||
+ printf("\n");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#define OPT_MAX(var, max) \
|
|
||||||
+ do { \
|
|
||||||
+ if ((var) > max) { \
|
|
||||||
+ fprintf(stderr, "--%s: Invalid value\n", \
|
|
||||||
+ long_options[option_index].name); \
|
|
||||||
+ break; \
|
|
||||||
+ } \
|
|
||||||
+ } while (0)
|
|
||||||
+
|
|
||||||
+static struct option long_options[] = {
|
|
||||||
+ {"help", 0, 0, 'h'},
|
|
||||||
+ {"bg_red", 1, 0, 10001},
|
|
||||||
+ {"bg_green", 1, 0, 10002},
|
|
||||||
+ {"bg_blue", 1, 0, 10003},
|
|
||||||
+ {"bg_reserved", 1, 0, 10004},
|
|
||||||
+ {"frame_ms", 1, 0, 10005},
|
|
||||||
+ {"picture", 0, 0, 20000},
|
|
||||||
+ {"pic_width", 1, 0, 20001},
|
|
||||||
+ {"pic_height", 1, 0, 20002},
|
|
||||||
+ {"pic_position", 1, 0, 20003},
|
|
||||||
+ {"pic_position_offset", 1, 0, 20004},
|
|
||||||
+ {"pic_anim_type", 1, 0, 20005},
|
|
||||||
+ {"pic_anim_loop", 1, 0, 20006},
|
|
||||||
+ {"blob", 1, 0, 30000},
|
|
||||||
+ {"blob_type", 1, 0, 30001},
|
|
||||||
+ {"blob_picture_id", 1, 0, 30002},
|
|
||||||
+ {NULL, 0, NULL, 0}
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+int main(int argc, char **argv)
|
|
||||||
+{
|
|
||||||
+ FILE *of;
|
|
||||||
+ char *ofn;
|
|
||||||
+ int c;
|
|
||||||
+ int option_index = 0;
|
|
||||||
+
|
|
||||||
+ unsigned long ul;
|
|
||||||
+ struct splash_file_header fh = {};
|
|
||||||
+ struct splash_pic_header ph[255];
|
|
||||||
+ struct blob_entry *blob_first = NULL;
|
|
||||||
+ struct blob_entry *blob_last = NULL;
|
|
||||||
+ struct blob_entry *blob_cur = NULL;
|
|
||||||
+
|
|
||||||
+ if (argc < 2) {
|
|
||||||
+ print_help(argv[0]);
|
|
||||||
+ return EXIT_FAILURE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Parse and and execute user commands */
|
|
||||||
+ while ((c = getopt_long(argc, argv, "h",
|
|
||||||
+ long_options, &option_index)) != -1) {
|
|
||||||
+ switch (c) {
|
|
||||||
+ case 10001: /* bg_red */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ fh.bg_red = ul;
|
|
||||||
+ break;
|
|
||||||
+ case 10002: /* bg_green */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ fh.bg_green = ul;
|
|
||||||
+ break;
|
|
||||||
+ case 10003: /* bg_blue */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ fh.bg_blue = ul;
|
|
||||||
+ break;
|
|
||||||
+ case 10004: /* bg_reserved */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ fh.bg_reserved = ul;
|
|
||||||
+ break;
|
|
||||||
+ case 10005: /* frame_ms */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 65535);
|
|
||||||
+ fh.frame_ms = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ case 20000: /* picture */
|
|
||||||
+ if (fh.num_pics >= 255) {
|
|
||||||
+ fprintf(stderr, "--%s: Picture array full\n",
|
|
||||||
+ long_options[option_index].name);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fh.num_pics++;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20001: /* pic_width */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 65535);
|
|
||||||
+ ph[fh.num_pics - 1].width = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20002: /* pic_height */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 65535);
|
|
||||||
+ ph[fh.num_pics - 1].height = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20003: /* pic_position */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ ph[fh.num_pics - 1].position = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20004: /* pic_position_offset */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ ph[fh.num_pics - 1].position_offset = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20005: /* pic_anim_type */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ ph[fh.num_pics - 1].anim_type = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 20006: /* pic_anim_loop */
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ ph[fh.num_pics - 1].anim_loop = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ case 30000: /* blob */
|
|
||||||
+ if (fh.num_blobs >= 65535) {
|
|
||||||
+ fprintf(stderr, "--%s: Blob array full\n",
|
|
||||||
+ long_options[option_index].name);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ blob_cur = calloc(1, sizeof(struct blob_entry));
|
|
||||||
+ if (!blob_cur) {
|
|
||||||
+ fprintf(stderr, "--%s: Out of memory\n",
|
|
||||||
+ long_options[option_index].name);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ blob_cur->fn = optarg;
|
|
||||||
+ if (fh.num_pics)
|
|
||||||
+ blob_cur->header.picture_id = fh.num_pics - 1;
|
|
||||||
+
|
|
||||||
+ if (!blob_first)
|
|
||||||
+ blob_first = blob_cur;
|
|
||||||
+ if (blob_last)
|
|
||||||
+ blob_last->next = blob_cur;
|
|
||||||
+ blob_last = blob_cur;
|
|
||||||
+ fh.num_blobs++;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 30001: /* blob_type */
|
|
||||||
+ if (!blob_cur) {
|
|
||||||
+ fprintf(stderr, "--%s: No blob selected\n",
|
|
||||||
+ long_options[option_index].name);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ blob_cur->header.type = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case 30002: /* blob_picture_id */
|
|
||||||
+ if (!blob_cur) {
|
|
||||||
+ fprintf(stderr, "--%s: No blob selected\n",
|
|
||||||
+ long_options[option_index].name);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ul = strtoul(optarg, NULL, 0);
|
|
||||||
+ OPT_MAX(ul, 255);
|
|
||||||
+ blob_cur->header.picture_id = ul;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ case 'h':
|
|
||||||
+ case '?':
|
|
||||||
+ default:
|
|
||||||
+ print_help(argv[0]);
|
|
||||||
+ goto EXIT;
|
|
||||||
+ } /* switch (c) */
|
|
||||||
+ } /* while ((c = getopt_long(...)) != -1) */
|
|
||||||
+
|
|
||||||
+ /* Consume and drop lone arguments */
|
|
||||||
+ while (optind < argc) {
|
|
||||||
+ ofn = argv[optind];
|
|
||||||
+ optind++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Read file lengths */
|
|
||||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
|
|
||||||
+ FILE *f;
|
|
||||||
+ long pos;
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ if (!blob_cur->fn)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ f = fopen(blob_cur->fn, "rb");
|
|
||||||
+ if (!f)
|
|
||||||
+ goto ERR_FILE_LEN;
|
|
||||||
+
|
|
||||||
+ if (fseek(f, 0, SEEK_END))
|
|
||||||
+ goto ERR_FILE_LEN;
|
|
||||||
+
|
|
||||||
+ pos = ftell(f);
|
|
||||||
+ if (pos < 0 || pos > (1 << 30))
|
|
||||||
+ goto ERR_FILE_LEN;
|
|
||||||
+
|
|
||||||
+ blob_cur->header.length = pos;
|
|
||||||
+
|
|
||||||
+ fclose(f);
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ERR_FILE_LEN:
|
|
||||||
+ fprintf(stderr, "Error getting file length (or too long): %s\n",
|
|
||||||
+ blob_cur->fn);
|
|
||||||
+ if (f)
|
|
||||||
+ fclose(f);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Set magic headers */
|
|
||||||
+#if __BYTE_ORDER == __BIG_ENDIAN
|
|
||||||
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16);
|
|
||||||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16);
|
|
||||||
+#else
|
|
||||||
+#error
|
|
||||||
+#endif
|
|
||||||
+ fh.version = BOOTSPLASH_VERSION;
|
|
||||||
+
|
|
||||||
+ /* Set blob counts */
|
|
||||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
|
|
||||||
+ if (blob_cur->header.picture_id < fh.num_pics)
|
|
||||||
+ ph[blob_cur->header.picture_id].num_blobs++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Dump structs */
|
|
||||||
+ dump_file_header(&fh);
|
|
||||||
+
|
|
||||||
+ for (ul = 0; ul < fh.num_pics; ul++)
|
|
||||||
+ dump_pic_header(&ph[ul]);
|
|
||||||
+
|
|
||||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next)
|
|
||||||
+ dump_blob(blob_cur);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Write to file */
|
|
||||||
+ printf("Writing splash to file: %s\n", ofn);
|
|
||||||
+ of = fopen(ofn, "wb");
|
|
||||||
+ if (!of)
|
|
||||||
+ goto ERR_WRITING;
|
|
||||||
+
|
|
||||||
+ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1)
|
|
||||||
+ goto ERR_WRITING;
|
|
||||||
+
|
|
||||||
+ for (ul = 0; ul < fh.num_pics; ul++) {
|
|
||||||
+ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of)
|
|
||||||
+ != 1)
|
|
||||||
+ goto ERR_WRITING;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ blob_cur = blob_first;
|
|
||||||
+ while (blob_cur) {
|
|
||||||
+ struct blob_entry *blob_old = blob_cur;
|
|
||||||
+ FILE *f;
|
|
||||||
+ char *buf[256];
|
|
||||||
+ uint32_t left;
|
|
||||||
+
|
|
||||||
+ if (fwrite(&blob_cur->header,
|
|
||||||
+ sizeof(struct splash_blob_header), 1, of) != 1)
|
|
||||||
+ goto ERR_WRITING;
|
|
||||||
+
|
|
||||||
+ if (!blob_cur->header.length || !blob_cur->fn)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ f = fopen(blob_cur->fn, "rb");
|
|
||||||
+ if (!f)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+
|
|
||||||
+ left = blob_cur->header.length;
|
|
||||||
+ while (left >= sizeof(buf)) {
|
|
||||||
+ if (fread(buf, sizeof(buf), 1, f) != 1)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+ if (fwrite(buf, sizeof(buf), 1, of) != 1)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+ left -= sizeof(buf);
|
|
||||||
+ }
|
|
||||||
+ if (left) {
|
|
||||||
+ if (fread(buf, left, 1, f) != 1)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+ if (fwrite(buf, left, 1, of) != 1)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Pad data stream to 16 bytes */
|
|
||||||
+ if (left % 16) {
|
|
||||||
+ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
|
||||||
+ 16 - (left % 16), 1, of) != 1)
|
|
||||||
+ goto ERR_FILE_COPY;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fclose(f);
|
|
||||||
+ blob_cur = blob_cur->next;
|
|
||||||
+ free(blob_old);
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ERR_FILE_COPY:
|
|
||||||
+ if (f)
|
|
||||||
+ fclose(f);
|
|
||||||
+ goto ERR_WRITING;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fclose(of);
|
|
||||||
+
|
|
||||||
+EXIT:
|
|
||||||
+ return EXIT_SUCCESS;
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ERR_WRITING:
|
|
||||||
+ fprintf(stderr, "Error writing splash.\n");
|
|
||||||
+ fprintf(stderr, "The output file is probably corrupt.\n");
|
|
||||||
+ if (of)
|
|
||||||
+ fclose(of);
|
|
||||||
+
|
|
||||||
+ while (blob_cur) {
|
|
||||||
+ struct blob_entry *blob_old = blob_cur;
|
|
||||||
+
|
|
||||||
+ blob_cur = blob_cur->next;
|
|
||||||
+ free(blob_old);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return EXIT_FAILURE;
|
|
||||||
+}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,46 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:30:07 +0100
|
|
||||||
Subject: [PATCH 13/36] power: supply: rk818-battery: Use a more propper
|
|
||||||
compatible string
|
|
||||||
|
|
||||||
Prefix with vendor name.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/mfd/rk808.c | 2 +-
|
|
||||||
drivers/power/supply/rk818_battery.c | 4 ++--
|
|
||||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
|
|
||||||
index 7d1f000..a99fec0 100644
|
|
||||||
--- a/drivers/mfd/rk808.c
|
|
||||||
+++ b/drivers/mfd/rk808.c
|
|
||||||
@@ -205,7 +205,7 @@ static const struct mfd_cell rk817s[] = {
|
|
||||||
static const struct mfd_cell rk818s[] = {
|
|
||||||
{ .name = "rk808-clkout", },
|
|
||||||
{ .name = "rk808-regulator", },
|
|
||||||
- { .name = "rk818-battery", .of_compatible = "rk818-battery", },
|
|
||||||
+ { .name = "rk818-battery", .of_compatible = "rockchip,rk818-battery", },
|
|
||||||
{
|
|
||||||
.name = "rk808-rtc",
|
|
||||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
|
||||||
diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c
|
|
||||||
index f09f456..665f043 100644
|
|
||||||
--- a/drivers/power/supply/rk818_battery.c
|
|
||||||
+++ b/drivers/power/supply/rk818_battery.c
|
|
||||||
@@ -3339,7 +3339,7 @@ static int rk818_bat_parse_dt(struct rk818_battery *di)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct of_device_id rk818_battery_of_match[] = {
|
|
||||||
- {.compatible = "rk818-battery",},
|
|
||||||
+ { .compatible = "rockchip,rk818-battery", },
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -3565,4 +3565,4 @@ module_exit(battery_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_ALIAS("platform:rk818-battery");
|
|
||||||
-MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");
|
|
||||||
\ No newline at end of file
|
|
||||||
+MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");
|
|
@ -1,85 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 14 Nov 2021 21:24:05 +0100
|
|
||||||
Subject: [PATCH 14/36] power: supply: core: Don't ignore max_current of 0
|
|
||||||
when setting current limit
|
|
||||||
|
|
||||||
If we ignore current limit of 0, the dependent power source will not
|
|
||||||
set input current limit to that value when the supplier changes max
|
|
||||||
current to 0. This may happen when USB power is disconnected from the
|
|
||||||
device.
|
|
||||||
|
|
||||||
On next connection, the dependent power supply will start consuming
|
|
||||||
power at the previously set limit even before the PD/BC1.2 power
|
|
||||||
negotiation has a chance to complete.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/power/supply/power_supply_core.c | 47 ++++++++++++++------------------
|
|
||||||
1 file changed, 20 insertions(+), 27 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
|
|
||||||
index fc12a4f..f681372 100644
|
|
||||||
--- a/drivers/power/supply/power_supply_core.c
|
|
||||||
+++ b/drivers/power/supply/power_supply_core.c
|
|
||||||
@@ -375,41 +375,34 @@ int power_supply_is_system_supplied(void)
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
|
|
||||||
|
|
||||||
-static int __power_supply_get_supplier_max_current(struct device *dev,
|
|
||||||
- void *data)
|
|
||||||
-{
|
|
||||||
- union power_supply_propval ret = {0,};
|
|
||||||
- struct power_supply *epsy = dev_get_drvdata(dev);
|
|
||||||
- struct power_supply *psy = data;
|
|
||||||
-
|
|
||||||
- if (__power_supply_is_supplied_by(epsy, psy))
|
|
||||||
- if (!epsy->desc->get_property(epsy,
|
|
||||||
- POWER_SUPPLY_PROP_CURRENT_MAX,
|
|
||||||
- &ret))
|
|
||||||
- return ret.intval;
|
|
||||||
-
|
|
||||||
- return 0;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy)
|
|
||||||
{
|
|
||||||
union power_supply_propval val = {0,};
|
|
||||||
- int curr;
|
|
||||||
+ struct class_dev_iter iter;
|
|
||||||
+ struct power_supply *epsy;
|
|
||||||
+ struct device *dev;
|
|
||||||
+ int ret;
|
|
||||||
|
|
||||||
if (!psy->desc->set_property)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * This function is not intended for use with a supply with multiple
|
|
||||||
- * suppliers, we simply pick the first supply to report a non 0
|
|
||||||
- * max-current.
|
|
||||||
- */
|
|
||||||
- curr = class_for_each_device(power_supply_class, NULL, psy,
|
|
||||||
- __power_supply_get_supplier_max_current);
|
|
||||||
- if (curr <= 0)
|
|
||||||
- return (curr == 0) ? -ENODEV : curr;
|
|
||||||
+ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
|
|
||||||
+ while ((dev = class_dev_iter_next(&iter))) {
|
|
||||||
+ epsy = dev_get_drvdata(dev);
|
|
||||||
+
|
|
||||||
+ if (!__power_supply_is_supplied_by(epsy, psy))
|
|
||||||
+ continue;
|
|
||||||
|
|
||||||
- val.intval = curr;
|
|
||||||
+ ret = epsy->desc->get_property(epsy,
|
|
||||||
+ POWER_SUPPLY_PROP_CURRENT_MAX,
|
|
||||||
+ &val);
|
|
||||||
+ if (!ret)
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ class_dev_iter_exit(&iter);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
|
|
||||||
return psy->desc->set_property(psy,
|
|
||||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
|
|
@ -1,699 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 20:09:02 +0100
|
|
||||||
Subject: [PATCH 15/36] power: supply: rk818-charger: Implement charger driver
|
|
||||||
for RK818 PMIC
|
|
||||||
|
|
||||||
For now this driver is just meant to watch Type-C power supply
|
|
||||||
and apply current limits to RK818, to not overload the Type-C
|
|
||||||
partner.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/mfd/rk808.c | 1 +
|
|
||||||
drivers/power/supply/Kconfig | 8 +
|
|
||||||
drivers/power/supply/Makefile | 1 +
|
|
||||||
drivers/power/supply/rk818_charger.c | 637 +++++++++++++++++++++++++++++++++++
|
|
||||||
4 files changed, 647 insertions(+)
|
|
||||||
create mode 100644 drivers/power/supply/rk818_charger.c
|
|
||||||
|
|
||||||
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
|
|
||||||
index a99fec0..75d18de 100644
|
|
||||||
--- a/drivers/mfd/rk808.c
|
|
||||||
+++ b/drivers/mfd/rk808.c
|
|
||||||
@@ -206,6 +206,7 @@ static const struct mfd_cell rk818s[] = {
|
|
||||||
{ .name = "rk808-clkout", },
|
|
||||||
{ .name = "rk808-regulator", },
|
|
||||||
{ .name = "rk818-battery", .of_compatible = "rockchip,rk818-battery", },
|
|
||||||
+ { .name = "rk818-charger", .of_compatible = "rockchip,rk818-charger", },
|
|
||||||
{
|
|
||||||
.name = "rk808-rtc",
|
|
||||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
|
||||||
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
|
|
||||||
index f5d4434..6bf0834 100644
|
|
||||||
--- a/drivers/power/supply/Kconfig
|
|
||||||
+++ b/drivers/power/supply/Kconfig
|
|
||||||
@@ -862,4 +862,12 @@ config BATTERY_RK818
|
|
||||||
If you say yes here you will get support for the battery of RK818 PMIC.
|
|
||||||
This driver can give support for Rk818 Battery Charge Interface.
|
|
||||||
|
|
||||||
+config CHARGER_RK818
|
|
||||||
+ bool "RK818 Charger driver"
|
|
||||||
+ depends on MFD_RK808
|
|
||||||
+ default n
|
|
||||||
+ help
|
|
||||||
+ If you say yes here you will get support for the charger of RK818 PMIC.
|
|
||||||
+ This driver can give support for Rk818 Charger Interface.
|
|
||||||
+
|
|
||||||
endif # POWER_SUPPLY
|
|
||||||
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
|
|
||||||
index 1c725ee..3a1526f 100644
|
|
||||||
--- a/drivers/power/supply/Makefile
|
|
||||||
+++ b/drivers/power/supply/Makefile
|
|
||||||
@@ -105,3 +105,4 @@ obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o
|
|
||||||
obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
|
|
||||||
obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
|
|
||||||
obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o
|
|
||||||
+obj-$(CONFIG_CHARGER_RK818) += rk818_charger.o
|
|
||||||
diff --git a/drivers/power/supply/rk818_charger.c b/drivers/power/supply/rk818_charger.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000..7b67a0b
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/power/supply/rk818_charger.c
|
|
||||||
@@ -0,0 +1,637 @@
|
|
||||||
+// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
+/*
|
|
||||||
+ * rk818 usb power driver
|
|
||||||
+ *
|
|
||||||
+ * Copyright (c) 2021 Ondřej Jirman <megi@xff.cz>
|
|
||||||
+ */
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/mfd/rk808.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/of_device.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/power_supply.h>
|
|
||||||
+#include <linux/regmap.h>
|
|
||||||
+
|
|
||||||
+#define RK818_CHG_STS_MASK (7u << 4) /* charger status */
|
|
||||||
+#define RK818_CHG_STS_NONE (0u << 4)
|
|
||||||
+#define RK818_CHG_STS_WAKEUP_CUR (1u << 4)
|
|
||||||
+#define RK818_CHG_STS_TRICKLE_CUR (2u << 4)
|
|
||||||
+#define RK818_CHG_STS_CC_OR_CV (3u << 4)
|
|
||||||
+#define RK818_CHG_STS_TERMINATED (4u << 4)
|
|
||||||
+#define RK818_CHG_STS_USB_OV (5u << 4)
|
|
||||||
+#define RK818_CHG_STS_BAT_TEMP_FAULT (6u << 4)
|
|
||||||
+#define RK818_CHG_STS_TIMEOUT (7u << 4)
|
|
||||||
+
|
|
||||||
+/* RK818_SUP_STS_REG */
|
|
||||||
+#define RK818_SUP_STS_USB_VLIM_EN BIT(3) /* input voltage limit enable */
|
|
||||||
+#define RK818_SUP_STS_USB_ILIM_EN BIT(2) /* input current limit enable */
|
|
||||||
+#define RK818_SUP_STS_USB_EXS BIT(1) /* USB power connected */
|
|
||||||
+#define RK818_SUP_STS_USB_EFF BIT(0) /* USB fault */
|
|
||||||
+
|
|
||||||
+/* RK818_USB_CTRL_REG */
|
|
||||||
+#define RK818_USB_CTRL_USB_ILIM_MASK (0xfu)
|
|
||||||
+#define RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET 4
|
|
||||||
+#define RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK (0x7u << 4)
|
|
||||||
+
|
|
||||||
+/* RK818_CHRG_CTRL_REG1 */
|
|
||||||
+#define RK818_CHRG_CTRL_REG1_CHRG_EN BIT(7)
|
|
||||||
+#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET 4
|
|
||||||
+#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK (0x7u << 4)
|
|
||||||
+#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET 0
|
|
||||||
+#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK (0xfu << 0)
|
|
||||||
+
|
|
||||||
+/* RK818_CHRG_CTRL_REG3 */
|
|
||||||
+#define RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL BIT(5)
|
|
||||||
+
|
|
||||||
+struct rk818_charger {
|
|
||||||
+ struct device *dev;
|
|
||||||
+ struct rk808 *rk818;
|
|
||||||
+ struct regmap *regmap;
|
|
||||||
+
|
|
||||||
+ struct power_supply *usb_psy;
|
|
||||||
+ struct power_supply *charger_psy;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+// {{{ USB supply
|
|
||||||
+
|
|
||||||
+static int rk818_usb_set_input_current_max(struct rk818_charger *cg,
|
|
||||||
+ int val)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+ unsigned reg;
|
|
||||||
+
|
|
||||||
+ if (val < 450000)
|
|
||||||
+ reg = 1;
|
|
||||||
+ else if (val < 850000)
|
|
||||||
+ reg = 0;
|
|
||||||
+ else if (val < 1000000)
|
|
||||||
+ reg = 2;
|
|
||||||
+ else if (val < 3000000)
|
|
||||||
+ reg = 3 + (val - 1000000) / 250000;
|
|
||||||
+ else
|
|
||||||
+ reg = 11;
|
|
||||||
+
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_USB_CTRL_REG,
|
|
||||||
+ RK818_USB_CTRL_USB_ILIM_MASK, reg);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "USB input current limit setting failed (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_get_input_current_max(struct rk818_charger *cg,
|
|
||||||
+ int *val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_USB_CTRL_REG, ®);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "USB input current limit getting failed (%d)\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ reg &= RK818_USB_CTRL_USB_ILIM_MASK;
|
|
||||||
+ if (reg == 0)
|
|
||||||
+ *val = 450000;
|
|
||||||
+ else if (reg == 1)
|
|
||||||
+ *val = 80000;
|
|
||||||
+ else if (reg == 2)
|
|
||||||
+ *val = 850000;
|
|
||||||
+ else if (reg < 11)
|
|
||||||
+ *val = 1000000 + (reg - 3) * 250000;
|
|
||||||
+ else
|
|
||||||
+ *val = 3000000;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_set_input_voltage_min(struct rk818_charger *cg,
|
|
||||||
+ int val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (val < 2780000)
|
|
||||||
+ reg = 0;
|
|
||||||
+ else if (val < 3270000)
|
|
||||||
+ reg = (val - 2780000) / 70000;
|
|
||||||
+ else
|
|
||||||
+ reg = 7;
|
|
||||||
+
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_USB_CTRL_REG,
|
|
||||||
+ RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK,
|
|
||||||
+ reg << RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "USB input voltage limit setting failed (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_get_input_voltage_min(struct rk818_charger *cg,
|
|
||||||
+ int *val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_USB_CTRL_REG, ®);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "USB input voltage limit getting failed (%d)\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ reg &= RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK;
|
|
||||||
+ reg >>= RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET;
|
|
||||||
+
|
|
||||||
+ *val = 2780000 + (reg * 70000);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_power_get_property(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp,
|
|
||||||
+ union power_supply_propval *val)
|
|
||||||
+{
|
|
||||||
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_PRESENT:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ val->intval = !!(reg & RK818_SUP_STS_USB_EXS);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_HEALTH:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ if (!(reg & RK818_SUP_STS_USB_EXS)) {
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
|
||||||
+ } else if (reg & RK818_SUP_STS_USB_EFF) {
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
|
||||||
+ } else {
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
|
||||||
+ return rk818_usb_get_input_voltage_min(cg, &val->intval);
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
|
||||||
+ return rk818_usb_get_input_current_max(cg, &val->intval);
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_power_set_property(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp,
|
|
||||||
+ const union power_supply_propval *val)
|
|
||||||
+{
|
|
||||||
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
|
|
||||||
+
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
|
||||||
+ return rk818_usb_set_input_voltage_min(cg, val->intval);
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
|
||||||
+ return rk818_usb_set_input_current_max(cg, val->intval);
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_usb_power_prop_writeable(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp)
|
|
||||||
+{
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
|
||||||
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
|
||||||
+ return 1;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* Sync the input-current-limit with our parent supply (if we have one) */
|
|
||||||
+static void rk818_usb_power_external_power_changed(struct power_supply *psy)
|
|
||||||
+{
|
|
||||||
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
|
|
||||||
+
|
|
||||||
+ power_supply_set_input_current_limit_from_supplier(cg->usb_psy);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static enum power_supply_property rk818_usb_power_props[] = {
|
|
||||||
+ POWER_SUPPLY_PROP_PRESENT,
|
|
||||||
+ POWER_SUPPLY_PROP_HEALTH,
|
|
||||||
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
|
||||||
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static const struct power_supply_desc rk818_usb_desc = {
|
|
||||||
+ .name = "rk818-usb",
|
|
||||||
+ .type = POWER_SUPPLY_TYPE_USB,
|
|
||||||
+ .properties = rk818_usb_power_props,
|
|
||||||
+ .num_properties = ARRAY_SIZE(rk818_usb_power_props),
|
|
||||||
+ .property_is_writeable = rk818_usb_power_prop_writeable,
|
|
||||||
+ .get_property = rk818_usb_power_get_property,
|
|
||||||
+ .set_property = rk818_usb_power_set_property,
|
|
||||||
+ .external_power_changed = rk818_usb_power_external_power_changed,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+// }}}
|
|
||||||
+// {{{ Charger supply
|
|
||||||
+
|
|
||||||
+static int rk818_charger_set_current_max(struct rk818_charger *cg, int val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (val < 1000000)
|
|
||||||
+ reg = 0;
|
|
||||||
+ else if (val < 3000000)
|
|
||||||
+ reg = (val - 1000000) / 200000;
|
|
||||||
+ else
|
|
||||||
+ reg = 10;
|
|
||||||
+
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
|
|
||||||
+ RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK,
|
|
||||||
+ reg << RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "Charging max current setting failed (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_get_current_max(struct rk818_charger *cg, int *val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, ®);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "Charging max current getting failed (%d)\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ reg &= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK;
|
|
||||||
+ reg >>= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET;
|
|
||||||
+
|
|
||||||
+ *val = 1000000 + reg * 200000;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_set_voltage_max(struct rk818_charger *cg, int val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (val < 4050000)
|
|
||||||
+ reg = 0;
|
|
||||||
+ else if (val < 4350000)
|
|
||||||
+ reg = (val - 4050000) / 50000;
|
|
||||||
+ else
|
|
||||||
+ reg = 6;
|
|
||||||
+
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
|
|
||||||
+ RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK,
|
|
||||||
+ reg << RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "Charging end voltage setting failed (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_get_voltage_max(struct rk818_charger *cg, int *val)
|
|
||||||
+{
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, ®);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(cg->dev,
|
|
||||||
+ "Charging end voltage getting failed (%d)\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ reg &= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK;
|
|
||||||
+ reg >>= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET;
|
|
||||||
+
|
|
||||||
+ *val = 4050000 + reg * 50000;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_get_property(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp,
|
|
||||||
+ union power_supply_propval *val)
|
|
||||||
+{
|
|
||||||
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
|
|
||||||
+ unsigned reg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_ONLINE:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, ®);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(cg->dev, "failed to read the charger state (%d)\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ val->intval = !!(reg & RK818_CHRG_CTRL_REG1_CHRG_EN);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_STATUS:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ switch (reg & RK818_CHG_STS_MASK) {
|
|
||||||
+ case RK818_CHG_STS_WAKEUP_CUR:
|
|
||||||
+ case RK818_CHG_STS_TRICKLE_CUR:
|
|
||||||
+ case RK818_CHG_STS_CC_OR_CV:
|
|
||||||
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
|
||||||
+ break;
|
|
||||||
+ case RK818_CHG_STS_TERMINATED:
|
|
||||||
+ default:
|
|
||||||
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ switch (reg & RK818_CHG_STS_MASK) {
|
|
||||||
+ case RK818_CHG_STS_WAKEUP_CUR:
|
|
||||||
+ case RK818_CHG_STS_TRICKLE_CUR:
|
|
||||||
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
|
|
||||||
+ break;
|
|
||||||
+ case RK818_CHG_STS_CC_OR_CV:
|
|
||||||
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
|
||||||
+ break;
|
|
||||||
+ case RK818_CHG_STS_TERMINATED:
|
|
||||||
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG2, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ val->intval = 100000 + ((reg >> 6) & 3) * 50000;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_HEALTH:
|
|
||||||
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ switch (reg & RK818_CHG_STS_MASK) {
|
|
||||||
+ case RK818_CHG_STS_USB_OV:
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
|
||||||
+ break;
|
|
||||||
+ case RK818_CHG_STS_BAT_TEMP_FAULT:
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
|
|
||||||
+ break;
|
|
||||||
+ case RK818_CHG_STS_TIMEOUT:
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
|
||||||
+ return rk818_charger_get_voltage_max(cg, &val->intval);
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
|
|
||||||
+ ret = rk818_charger_get_current_max(cg, &val->intval);
|
|
||||||
+ val->intval /= 10;
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
|
||||||
+ return rk818_charger_get_current_max(cg, &val->intval);
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
|
|
||||||
+ val->intval = 4350000;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
|
||||||
+ val->intval = 3000000;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_set_property(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp,
|
|
||||||
+ const union power_supply_propval *val)
|
|
||||||
+{
|
|
||||||
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_ONLINE:
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
|
|
||||||
+ RK818_CHRG_CTRL_REG1_CHRG_EN,
|
|
||||||
+ val->intval ? RK818_CHRG_CTRL_REG1_CHRG_EN : 0);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_err(cg->dev, "failed to setup the charger (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
|
||||||
+ return rk818_charger_set_voltage_max(cg, val->intval);
|
|
||||||
+
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
|
||||||
+ return rk818_charger_set_current_max(cg, val->intval);
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_prop_writeable(struct power_supply *psy,
|
|
||||||
+ enum power_supply_property psp)
|
|
||||||
+{
|
|
||||||
+ switch (psp) {
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
|
||||||
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
|
||||||
+ case POWER_SUPPLY_PROP_ONLINE:
|
|
||||||
+ return 1;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static enum power_supply_property rk818_charger_props[] = {
|
|
||||||
+ POWER_SUPPLY_PROP_ONLINE,
|
|
||||||
+ POWER_SUPPLY_PROP_HEALTH,
|
|
||||||
+ POWER_SUPPLY_PROP_STATUS,
|
|
||||||
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
|
|
||||||
+ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
|
|
||||||
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
|
|
||||||
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
|
||||||
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
|
||||||
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
|
||||||
+ POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * TODO: This functionality should be in a battery driver/supply, but that one
|
|
||||||
+ * is such a mess, I don't want to touch it now. Let's have a separate supply
|
|
||||||
+ * for controlling the charger for now, and a prayer for the poor soul that
|
|
||||||
+ * will have to understand and clean up the battery driver.
|
|
||||||
+ */
|
|
||||||
+static const struct power_supply_desc rk818_charger_desc = {
|
|
||||||
+ .name = "rk818-charger",
|
|
||||||
+ .type = POWER_SUPPLY_TYPE_BATTERY,
|
|
||||||
+ .properties = rk818_charger_props,
|
|
||||||
+ .num_properties = ARRAY_SIZE(rk818_charger_props),
|
|
||||||
+ .property_is_writeable = rk818_charger_prop_writeable,
|
|
||||||
+ .get_property = rk818_charger_get_property,
|
|
||||||
+ .set_property = rk818_charger_set_property,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+// }}}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent);
|
|
||||||
+ struct power_supply_config psy_cfg = { };
|
|
||||||
+ struct device *dev = &pdev->dev;
|
|
||||||
+ struct rk818_charger *cg;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
|
|
||||||
+ if (!cg)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ cg->rk818 = rk818;
|
|
||||||
+ cg->dev = dev;
|
|
||||||
+ cg->regmap = rk818->regmap;
|
|
||||||
+ platform_set_drvdata(pdev, cg);
|
|
||||||
+
|
|
||||||
+ psy_cfg.drv_data = cg;
|
|
||||||
+ psy_cfg.of_node = dev->of_node;
|
|
||||||
+
|
|
||||||
+ cg->usb_psy = devm_power_supply_register(dev, &rk818_usb_desc,
|
|
||||||
+ &psy_cfg);
|
|
||||||
+ if (IS_ERR(cg->usb_psy))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(cg->usb_psy),
|
|
||||||
+ "register usb power supply fail\n");
|
|
||||||
+
|
|
||||||
+ cg->charger_psy = devm_power_supply_register(dev, &rk818_charger_desc,
|
|
||||||
+ &psy_cfg);
|
|
||||||
+ if (IS_ERR(cg->charger_psy))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(cg->charger_psy),
|
|
||||||
+ "register charger power supply fail\n");
|
|
||||||
+
|
|
||||||
+ /* disable voltage limit and enable input current limit */
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_SUP_STS_REG,
|
|
||||||
+ RK818_SUP_STS_USB_ILIM_EN | RK818_SUP_STS_USB_VLIM_EN,
|
|
||||||
+ RK818_SUP_STS_USB_ILIM_EN);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_warn(cg->dev, "failed to enable input current limit (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ /* make sure analog control loop is enabled */
|
|
||||||
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG3,
|
|
||||||
+ RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL,
|
|
||||||
+ 0);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_warn(cg->dev, "failed to enable analog control loop (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ /* enable charger and set some reasonable limits on each boot */
|
|
||||||
+ ret = regmap_write(cg->regmap, RK818_CHRG_CTRL_REG1,
|
|
||||||
+ RK818_CHRG_CTRL_REG1_CHRG_EN
|
|
||||||
+ | (1) /* 1.2A */
|
|
||||||
+ | (5 << 4) /* 4.3V */);
|
|
||||||
+ if (ret)
|
|
||||||
+ dev_warn(cg->dev, "failed to enable charger (%d)\n", ret);
|
|
||||||
+
|
|
||||||
+ power_supply_set_input_current_limit_from_supplier(cg->usb_psy);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_remove(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ //struct rk818_charger *cg = platform_get_drvdata(pdev);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void rk818_charger_shutdown(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_suspend(struct platform_device *pdev,
|
|
||||||
+ pm_message_t state)
|
|
||||||
+{
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int rk818_charger_resume(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct of_device_id rk818_charger_of_match[] = {
|
|
||||||
+ { .compatible = "rockchip,rk818-charger", },
|
|
||||||
+ { },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct platform_driver rk818_charger_driver = {
|
|
||||||
+ .probe = rk818_charger_probe,
|
|
||||||
+ .remove = rk818_charger_remove,
|
|
||||||
+ .suspend = rk818_charger_suspend,
|
|
||||||
+ .resume = rk818_charger_resume,
|
|
||||||
+ .shutdown = rk818_charger_shutdown,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "rk818-charger",
|
|
||||||
+ .of_match_table = rk818_charger_of_match,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+module_platform_driver(rk818_charger_driver);
|
|
||||||
+
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
+MODULE_ALIAS("platform:rk818-charger");
|
|
||||||
+MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>");
|
|
@ -1,47 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:28:27 +0100
|
|
||||||
Subject: [PATCH 26/36] usb: typec: fusb302: Set the current before enabling
|
|
||||||
pullups
|
|
||||||
|
|
||||||
This seems more reasonable and should avoid short period of incorrect
|
|
||||||
current setting being applied to CC pin.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 16 ++++++++--------
|
|
||||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 72f9001..776a949 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -635,6 +635,14 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* adjust current for SRC */
|
|
||||||
+ ret = fusb302_set_src_current(chip, cc_src_current[cc]);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ fusb302_log(chip, "cannot set src current %s, ret=%d",
|
|
||||||
+ typec_cc_status_name[cc], ret);
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
|
|
||||||
switches0_mask, switches0_data);
|
|
||||||
if (ret < 0) {
|
|
||||||
@@ -645,14 +653,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
|
|
||||||
chip->cc1 = TYPEC_CC_OPEN;
|
|
||||||
chip->cc2 = TYPEC_CC_OPEN;
|
|
||||||
|
|
||||||
- /* adjust current for SRC */
|
|
||||||
- ret = fusb302_set_src_current(chip, cc_src_current[cc]);
|
|
||||||
- if (ret < 0) {
|
|
||||||
- fusb302_log(chip, "cannot set src current %s, ret=%d",
|
|
||||||
- typec_cc_status_name[cc], ret);
|
|
||||||
- goto done;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
/* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
|
|
||||||
switch (cc) {
|
|
||||||
case TYPEC_CC_RP_DEF:
|
|
@ -1,108 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:29:06 +0100
|
|
||||||
Subject: [PATCH 27/36] usb: typec: fusb302: Extend debugging interface with
|
|
||||||
driver state dumps
|
|
||||||
|
|
||||||
This is useful for debugging.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 78 ++++++++++++++++++++++++++++++++++++++++
|
|
||||||
1 file changed, 78 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 776a949..1a758e3 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -207,6 +207,81 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
|
|
||||||
}
|
|
||||||
DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
|
|
||||||
|
|
||||||
+static const char * const typec_cc_status_name[];
|
|
||||||
+static const char * const cc_polarity_name[];
|
|
||||||
+static const char * const toggling_mode_name[] = {
|
|
||||||
+ [TOGGLING_MODE_OFF] = "Off",
|
|
||||||
+ [TOGGLING_MODE_DRP] = "DRP",
|
|
||||||
+ [TOGGLING_MODE_SNK] = "SNK",
|
|
||||||
+ [TOGGLING_MODE_SRC] = "SRC",
|
|
||||||
+};
|
|
||||||
+static const char * const src_current_status_name[] = {
|
|
||||||
+ [SRC_CURRENT_DEFAULT] = "Default",
|
|
||||||
+ [SRC_CURRENT_MEDIUM] = "Medium",
|
|
||||||
+ [SRC_CURRENT_HIGH] = "High",
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define FUSB_REG(n) { n, #n },
|
|
||||||
+struct fusb_reg {
|
|
||||||
+ u8 addr;
|
|
||||||
+ const char* name;
|
|
||||||
+} fusb_regs[] = {
|
|
||||||
+ FUSB_REG(FUSB_REG_DEVICE_ID)
|
|
||||||
+ FUSB_REG(FUSB_REG_SWITCHES0)
|
|
||||||
+ FUSB_REG(FUSB_REG_SWITCHES1)
|
|
||||||
+ FUSB_REG(FUSB_REG_MEASURE)
|
|
||||||
+ FUSB_REG(FUSB_REG_CONTROL0)
|
|
||||||
+ FUSB_REG(FUSB_REG_CONTROL1)
|
|
||||||
+ FUSB_REG(FUSB_REG_CONTROL2)
|
|
||||||
+ FUSB_REG(FUSB_REG_CONTROL3)
|
|
||||||
+ FUSB_REG(FUSB_REG_MASK)
|
|
||||||
+ FUSB_REG(FUSB_REG_POWER)
|
|
||||||
+ FUSB_REG(FUSB_REG_RESET)
|
|
||||||
+ FUSB_REG(FUSB_REG_MASKA)
|
|
||||||
+ FUSB_REG(FUSB_REG_MASKB)
|
|
||||||
+ FUSB_REG(FUSB_REG_STATUS0A)
|
|
||||||
+ FUSB_REG(FUSB_REG_STATUS1A)
|
|
||||||
+ FUSB_REG(FUSB_REG_INTERRUPTA)
|
|
||||||
+ FUSB_REG(FUSB_REG_INTERRUPTB)
|
|
||||||
+ FUSB_REG(FUSB_REG_STATUS0)
|
|
||||||
+ FUSB_REG(FUSB_REG_STATUS1)
|
|
||||||
+ FUSB_REG(FUSB_REG_INTERRUPT)
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int fusb302_i2c_read(struct fusb302_chip *chip,
|
|
||||||
+ u8 address, u8 *data);
|
|
||||||
+
|
|
||||||
+static int fusb302_debug_regs_show(struct seq_file *s, void *v)
|
|
||||||
+{
|
|
||||||
+ struct fusb302_chip *chip = (struct fusb302_chip *)s->private;
|
|
||||||
+ int i, ret;
|
|
||||||
+
|
|
||||||
+ seq_printf(s, "chip->intr_togdone = %d\n", chip->intr_togdone);
|
|
||||||
+ seq_printf(s, "chip->intr_bc_lvl = %d\n", chip->intr_bc_lvl);
|
|
||||||
+ seq_printf(s, "chip->intr_comp_chng = %d\n", chip->intr_comp_chng);
|
|
||||||
+ seq_printf(s, "chip->vconn_on = %d\n", chip->vconn_on);
|
|
||||||
+ seq_printf(s, "chip->vbus_on = %d\n", chip->vbus_on);
|
|
||||||
+ seq_printf(s, "chip->charge_on = %d\n", chip->charge_on);
|
|
||||||
+ seq_printf(s, "chip->vbus_present = %d\n", chip->vbus_present);
|
|
||||||
+ seq_printf(s, "chip->cc_polarity = %s\n", cc_polarity_name[chip->cc_polarity]);
|
|
||||||
+ seq_printf(s, "chip->cc1 = %s\n", typec_cc_status_name[chip->cc1]);
|
|
||||||
+ seq_printf(s, "chip->cc2 = %s\n", typec_cc_status_name[chip->cc2]);
|
|
||||||
+ seq_printf(s, "chip->toggling_mode = %s\n", toggling_mode_name[chip->toggling_mode]);
|
|
||||||
+ seq_printf(s, "chip->src_current_status = %s\n", src_current_status_name[chip->src_current_status]);
|
|
||||||
+
|
|
||||||
+ seq_printf(s, "\nRegisters:\n");
|
|
||||||
+ for (i = 0; i < ARRAY_SIZE(fusb_regs); i++) {
|
|
||||||
+ u8 val = 0;
|
|
||||||
+
|
|
||||||
+ ret = fusb302_i2c_read(chip, fusb_regs[i].addr, &val);
|
|
||||||
+ if (ret >= 0)
|
|
||||||
+ seq_printf(s, "%s = %02hhx\n", fusb_regs[i].name, val);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+DEFINE_SHOW_ATTRIBUTE(fusb302_debug_regs);
|
|
||||||
+
|
|
||||||
static void fusb302_debugfs_init(struct fusb302_chip *chip)
|
|
||||||
{
|
|
||||||
char name[NAME_MAX];
|
|
||||||
@@ -216,6 +291,9 @@ static void fusb302_debugfs_init(struct fusb302_chip *chip)
|
|
||||||
chip->dentry = debugfs_create_dir(name, usb_debug_root);
|
|
||||||
debugfs_create_file("log", S_IFREG | 0444, chip->dentry, chip,
|
|
||||||
&fusb302_debug_fops);
|
|
||||||
+
|
|
||||||
+ debugfs_create_file("regs", S_IFREG | 0444, chip->dentry, chip,
|
|
||||||
+ &fusb302_debug_regs_fops);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fusb302_debugfs_exit(struct fusb302_chip *chip)
|
|
@ -1,72 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 17:53:27 +0100
|
|
||||||
Subject: [PATCH 28/36] usb: typec: fusb302: Retry reading of CC pins status
|
|
||||||
if activity is detected
|
|
||||||
|
|
||||||
This is just for testing, to see if this ever happens. It should
|
|
||||||
also help when this happens.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 34 ++++++++++++++++++++++++++++++++--
|
|
||||||
1 file changed, 32 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 1a758e3..7386805 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -1317,6 +1317,36 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int fusb302_get_status0_stable(struct fusb302_chip *chip, u8 *status0)
|
|
||||||
+{
|
|
||||||
+ int ret, tries = 0;
|
|
||||||
+ u8 reg;
|
|
||||||
+
|
|
||||||
+try_again:
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, ®);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ if (reg & FUSB_REG_STATUS0_ACTIVITY) {
|
|
||||||
+ fusb302_log(chip, "activity reading CC status");
|
|
||||||
+ if (++tries == 5) {
|
|
||||||
+ fusb302_log(chip, "failed to read stable status0 value");
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * The best we can do is to return at least something.
|
|
||||||
+ */
|
|
||||||
+ *status0 = reg;
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ usleep_range(50, 100);
|
|
||||||
+ goto try_again;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ *status0 = reg;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/* On error returns < 0, otherwise a typec_cc_status value */
|
|
||||||
static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
enum typec_cc_polarity cc_polarity,
|
|
||||||
@@ -1344,7 +1374,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
usleep_range(50, 100);
|
|
||||||
- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
|
|
||||||
+ ret = fusb302_get_status0_stable(chip, &status0);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
@@ -1360,7 +1390,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
usleep_range(50, 100);
|
|
||||||
- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
|
|
||||||
+ ret = fusb302_get_status0_stable(chip, &status0);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
@ -1,186 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 17:55:34 +0100
|
|
||||||
Subject: [PATCH 29/36] usb: typec: fusb302: More useful of logging status on
|
|
||||||
interrupt
|
|
||||||
|
|
||||||
This is just for debugging. It prints more info that's useful to
|
|
||||||
see how hardware state changes in time.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 121 +++++++++++++++++++++++++++++++++------
|
|
||||||
1 file changed, 104 insertions(+), 17 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 7386805..70b0e15 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -68,7 +68,7 @@ static const u8 rd_mda_value[] = {
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LOG_BUFFER_ENTRIES 1024
|
|
||||||
-#define LOG_BUFFER_ENTRY_SIZE 128
|
|
||||||
+#define LOG_BUFFER_ENTRY_SIZE 256
|
|
||||||
|
|
||||||
struct fusb302_chip {
|
|
||||||
struct device *dev;
|
|
||||||
@@ -1598,6 +1598,84 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void fusb302_print_state(struct fusb302_chip *chip)
|
|
||||||
+{
|
|
||||||
+ u8 ctl0, ctl2, measure, status0, status1a, sw0, mask;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_CONTROL0, &ctl0);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_CONTROL2, &ctl2);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_MEASURE, &measure);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS1A, &status1a);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &sw0);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_MASK, &mask);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ //FUSB_REG(FUSB_REG_POWER) // power control
|
|
||||||
+
|
|
||||||
+ const char* host_cur = "?";
|
|
||||||
+ switch ((ctl0 >> 2) & 3) {
|
|
||||||
+ case 0: host_cur = "none"; break;
|
|
||||||
+ case 1: host_cur = "80uA"; break;
|
|
||||||
+ case 2: host_cur = "160uA"; break;
|
|
||||||
+ case 3: host_cur = "330uA"; break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ const char* bc_lvl = "?";
|
|
||||||
+ switch (status0 & 3) {
|
|
||||||
+ case 0: bc_lvl = "0-200mV"; break;
|
|
||||||
+ case 1: bc_lvl = "200-660mV"; break;
|
|
||||||
+ case 2: bc_lvl = "660-1230mV"; break;
|
|
||||||
+ case 3: bc_lvl = ">1230mV"; break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // status0
|
|
||||||
+ unsigned vbusok = !!(status0 & BIT(7));
|
|
||||||
+ unsigned activity = !!(status0 & BIT(6));
|
|
||||||
+ unsigned comp = !!(status0 & BIT(5));
|
|
||||||
+ unsigned wake = !!(status0 & BIT(2));
|
|
||||||
+
|
|
||||||
+ // measure
|
|
||||||
+ unsigned mdac = ((measure & 0x3f) + 1) * 42 * (measure & BIT(6) ? 10 : 1);
|
|
||||||
+
|
|
||||||
+ // status1a
|
|
||||||
+ unsigned togss = (status1a >> 3) & 7;
|
|
||||||
+ const char* togss_s = "?";
|
|
||||||
+ switch (togss) {
|
|
||||||
+ case 0: togss_s = "running"; break;
|
|
||||||
+ case 1: togss_s = "src1"; break;
|
|
||||||
+ case 2: togss_s = "src2"; break;
|
|
||||||
+ case 5: togss_s = "snk1"; break;
|
|
||||||
+ case 6: togss_s = "snk2"; break;
|
|
||||||
+ case 7: togss_s = "audio"; break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // ctl2 print as is
|
|
||||||
+
|
|
||||||
+#define SW(n) (!!(sw0 & BIT(n)))
|
|
||||||
+
|
|
||||||
+ fusb302_log(chip, "state: cc(puen=%u%u vconn=%u%u meas=%u%u pdwn=%u%u) "
|
|
||||||
+ "host_cur=%s mdac=%umV comp=%u bc_lvl=%s vbusok=%u act=%u "
|
|
||||||
+ "wake=%u togss=%s ctl2=0x%02x mask=0x%02x",
|
|
||||||
+ SW(6), SW(7), SW(4), SW(5), SW(2), SW(3), SW(0), SW(1),
|
|
||||||
+ host_cur, mdac, comp, bc_lvl, vbusok, activity,
|
|
||||||
+ wake, togss_s, ctl2, mask);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void fusb302_irq_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct fusb302_chip *chip = container_of(work, struct fusb302_chip,
|
|
||||||
@@ -1607,6 +1685,7 @@ static void fusb302_irq_work(struct work_struct *work)
|
|
||||||
u8 interrupta;
|
|
||||||
u8 interruptb;
|
|
||||||
u8 status0;
|
|
||||||
+ u8 mda;
|
|
||||||
bool vbus_present;
|
|
||||||
bool comp_result;
|
|
||||||
bool intr_togdone;
|
|
||||||
@@ -1632,9 +1711,10 @@ static void fusb302_irq_work(struct work_struct *work)
|
|
||||||
ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
|
|
||||||
if (ret < 0)
|
|
||||||
goto done;
|
|
||||||
- fusb302_log(chip,
|
|
||||||
- "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x, status0: 0x%02x",
|
|
||||||
- interrupt, interrupta, interruptb, status0);
|
|
||||||
+ fusb302_log(chip, "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x",
|
|
||||||
+ interrupt, interrupta, interruptb);
|
|
||||||
+
|
|
||||||
+ fusb302_print_state(chip);
|
|
||||||
|
|
||||||
if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) {
|
|
||||||
vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
|
|
||||||
@@ -1646,32 +1726,39 @@ static void fusb302_irq_work(struct work_struct *work)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- if ((interrupta & FUSB_REG_INTERRUPTA_TOGDONE) && intr_togdone) {
|
|
||||||
+ if (interrupta & FUSB_REG_INTERRUPTA_TOGDONE) {
|
|
||||||
fusb302_log(chip, "IRQ: TOGDONE");
|
|
||||||
- ret = fusb302_handle_togdone(chip);
|
|
||||||
- if (ret < 0) {
|
|
||||||
- fusb302_log(chip,
|
|
||||||
- "handle togdone error, ret=%d", ret);
|
|
||||||
- goto done;
|
|
||||||
+ if (intr_togdone) {
|
|
||||||
+ ret = fusb302_handle_togdone(chip);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ fusb302_log(chip,
|
|
||||||
+ "handle togdone error, ret=%d", ret);
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- if ((interrupt & FUSB_REG_INTERRUPT_BC_LVL) && intr_bc_lvl) {
|
|
||||||
+ if (interrupt & FUSB_REG_INTERRUPT_BC_LVL) {
|
|
||||||
fusb302_log(chip, "IRQ: BC_LVL, handler pending");
|
|
||||||
/*
|
|
||||||
* as BC_LVL interrupt can be affected by PD activity,
|
|
||||||
* apply delay to for the handler to wait for the PD
|
|
||||||
* signaling to finish.
|
|
||||||
*/
|
|
||||||
- mod_delayed_work(chip->wq, &chip->bc_lvl_handler,
|
|
||||||
- msecs_to_jiffies(T_BC_LVL_DEBOUNCE_DELAY_MS));
|
|
||||||
+ if (intr_bc_lvl)
|
|
||||||
+ mod_delayed_work(chip->wq, &chip->bc_lvl_handler,
|
|
||||||
+ msecs_to_jiffies(T_BC_LVL_DEBOUNCE_DELAY_MS));
|
|
||||||
}
|
|
||||||
|
|
||||||
- if ((interrupt & FUSB_REG_INTERRUPT_COMP_CHNG) && intr_comp_chng) {
|
|
||||||
+ if (interrupt & FUSB_REG_INTERRUPT_COMP_CHNG) {
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_MEASURE, &mda);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ goto done;
|
|
||||||
+
|
|
||||||
comp_result = !!(status0 & FUSB_REG_STATUS0_COMP);
|
|
||||||
- fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s",
|
|
||||||
- comp_result ? "true" : "false");
|
|
||||||
- if (comp_result) {
|
|
||||||
+ fusb302_log(chip, "IRQ: COMP_CHNG, cc* %s mdac (%u mV)",
|
|
||||||
+ comp_result ? ">" : "<", ((mda & 0x3f) + 1) * 42 * (mda & BIT(6) ? 10 : 1));
|
|
||||||
+ if (comp_result && intr_comp_chng) {
|
|
||||||
/* cc level > Rd_threshold, detach */
|
|
||||||
chip->cc1 = TYPEC_CC_OPEN;
|
|
||||||
chip->cc2 = TYPEC_CC_OPEN;
|
|
@ -1,39 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 17:57:06 +0100
|
|
||||||
Subject: [PATCH 30/36] usb: typec: fusb302: Update VBUS state even if VBUS
|
|
||||||
interrupt is not triggered
|
|
||||||
|
|
||||||
This seems to improve robustness.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 14 ++++++++------
|
|
||||||
1 file changed, 8 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 70b0e15..1d5affa 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -1716,14 +1716,16 @@ static void fusb302_irq_work(struct work_struct *work)
|
|
||||||
|
|
||||||
fusb302_print_state(chip);
|
|
||||||
|
|
||||||
- if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) {
|
|
||||||
- vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
|
|
||||||
+ vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
|
|
||||||
+ if (interrupt & FUSB_REG_INTERRUPT_VBUSOK)
|
|
||||||
fusb302_log(chip, "IRQ: VBUS_OK, vbus=%s",
|
|
||||||
vbus_present ? "On" : "Off");
|
|
||||||
- if (vbus_present != chip->vbus_present) {
|
|
||||||
- chip->vbus_present = vbus_present;
|
|
||||||
- tcpm_vbus_change(chip->tcpm_port);
|
|
||||||
- }
|
|
||||||
+ if (vbus_present != chip->vbus_present) {
|
|
||||||
+ chip->vbus_present = vbus_present;
|
|
||||||
+ if (!(interrupt & FUSB_REG_INTERRUPT_VBUSOK))
|
|
||||||
+ fusb302_log(chip, "IRQ: VBUS changed without interrupt, vbus=%s",
|
|
||||||
+ vbus_present ? "On" : "Off");
|
|
||||||
+ tcpm_vbus_change(chip->tcpm_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interrupta & FUSB_REG_INTERRUPTA_TOGDONE) {
|
|
@ -1,160 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 17:58:05 +0100
|
|
||||||
Subject: [PATCH 31/36] usb: typec: fusb302: Make tcpm/fusb302 logs less
|
|
||||||
polluted by PD comm stuff
|
|
||||||
|
|
||||||
This adds clarity to debugging.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 18 ++++++++++--------
|
|
||||||
drivers/usb/typec/tcpm/tcpm.c | 18 ++++++++++--------
|
|
||||||
2 files changed, 20 insertions(+), 16 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 1d5affa..ae3b930 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -787,7 +787,7 @@ static int tcpm_get_cc(struct tcpc_dev *dev, enum typec_cc_status *cc1,
|
|
||||||
mutex_lock(&chip->lock);
|
|
||||||
*cc1 = chip->cc1;
|
|
||||||
*cc2 = chip->cc2;
|
|
||||||
- fusb302_log(chip, "cc1=%s, cc2=%s", typec_cc_status_name[*cc1],
|
|
||||||
+ fusb302_log(chip, "tcpm_get_cc => cc1=%s, cc2=%s (cached)", typec_cc_status_name[*cc1],
|
|
||||||
typec_cc_status_name[*cc2]);
|
|
||||||
mutex_unlock(&chip->lock);
|
|
||||||
|
|
||||||
@@ -1073,8 +1073,8 @@ static int fusb302_pd_send_message(struct fusb302_chip *chip,
|
|
||||||
ret = fusb302_i2c_block_write(chip, FUSB_REG_FIFOS, pos, buf);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
- fusb302_log(chip, "sending PD message header: %x", msg->header);
|
|
||||||
- fusb302_log(chip, "sending PD message len: %d", len);
|
|
||||||
+ //fusb302_log(chip, "sending PD message header: %x", msg->header);
|
|
||||||
+ //fusb302_log(chip, "sending PD message len: %d", len);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1365,8 +1365,10 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
+ //XXX resolve activity conflicts while measuring
|
|
||||||
+
|
|
||||||
fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
|
|
||||||
- fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
|
|
||||||
+ //fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
|
|
||||||
|
|
||||||
/* Step 2: Set compararator volt to differentiate between Open and Rd */
|
|
||||||
ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
|
|
||||||
@@ -1378,7 +1380,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
- fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
|
|
||||||
+ //fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
|
|
||||||
if (status0 & FUSB_REG_STATUS0_COMP) {
|
|
||||||
*cc = TYPEC_CC_OPEN;
|
|
||||||
return 0;
|
|
||||||
@@ -1394,7 +1396,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
- fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
|
|
||||||
+ //fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
|
|
||||||
if (status0 & FUSB_REG_STATUS0_COMP)
|
|
||||||
*cc = TYPEC_CC_RD;
|
|
||||||
else
|
|
||||||
@@ -1559,8 +1561,8 @@ static int fusb302_pd_read_message(struct fusb302_chip *chip,
|
|
||||||
ret = fusb302_i2c_block_read(chip, FUSB_REG_FIFOS, 4, crc);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
- fusb302_log(chip, "PD message header: %x", msg->header);
|
|
||||||
- fusb302_log(chip, "PD message len: %d", len);
|
|
||||||
+ //fusb302_log(chip, "PD message header: %x", msg->header);
|
|
||||||
+ //fusb302_log(chip, "PD message len: %d", len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we've read off a GoodCRC message. If so then indicate to
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
|
|
||||||
index 59d4fa2..0451441 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/tcpm.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/tcpm.c
|
|
||||||
@@ -776,7 +776,7 @@ static void tcpm_debugfs_exit(const struct tcpm_port *port) { }
|
|
||||||
|
|
||||||
static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
|
|
||||||
{
|
|
||||||
- tcpm_log(port, "cc:=%d", cc);
|
|
||||||
+ //tcpm_log(port, "cc:=%d", cc);
|
|
||||||
port->cc_req = cc;
|
|
||||||
port->tcpc->set_cc(port->tcpc, cc);
|
|
||||||
}
|
|
||||||
@@ -869,10 +869,12 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
|
|
||||||
unsigned long timeout;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
if (msg)
|
|
||||||
tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header));
|
|
||||||
else
|
|
||||||
tcpm_log(port, "PD TX, type: %#x", type);
|
|
||||||
+ */
|
|
||||||
|
|
||||||
reinit_completion(&port->tx_complete);
|
|
||||||
ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev);
|
|
||||||
@@ -918,7 +920,7 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
|
|
||||||
void tcpm_pd_transmit_complete(struct tcpm_port *port,
|
|
||||||
enum tcpm_transmit_status status)
|
|
||||||
{
|
|
||||||
- tcpm_log(port, "PD TX complete, status: %u", status);
|
|
||||||
+ //tcpm_log(port, "PD TX complete, status: %u", status);
|
|
||||||
port->tx_status = status;
|
|
||||||
complete(&port->tx_complete);
|
|
||||||
}
|
|
||||||
@@ -951,7 +953,7 @@ static int tcpm_set_polarity(struct tcpm_port *port,
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- tcpm_log(port, "polarity %d", polarity);
|
|
||||||
+ //tcpm_log(port, "polarity %d", polarity);
|
|
||||||
|
|
||||||
ret = port->tcpc->set_polarity(port->tcpc, polarity);
|
|
||||||
if (ret < 0)
|
|
||||||
@@ -966,7 +968,7 @@ static int tcpm_set_vconn(struct tcpm_port *port, bool enable)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- tcpm_log(port, "vconn:=%d", enable);
|
|
||||||
+ //tcpm_log(port, "vconn:=%d", enable);
|
|
||||||
|
|
||||||
ret = port->tcpc->set_vconn(port->tcpc, enable);
|
|
||||||
if (!ret) {
|
|
||||||
@@ -2871,8 +2873,8 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
|
|
||||||
|
|
||||||
mutex_lock(&port->lock);
|
|
||||||
|
|
||||||
- tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
|
|
||||||
- port->attached);
|
|
||||||
+ //tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
|
|
||||||
+ //port->attached);
|
|
||||||
|
|
||||||
if (port->attached) {
|
|
||||||
enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
|
|
||||||
@@ -5041,7 +5043,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
|
|
||||||
|
|
||||||
static void _tcpm_pd_vbus_on(struct tcpm_port *port)
|
|
||||||
{
|
|
||||||
- tcpm_log_force(port, "VBUS on");
|
|
||||||
+ tcpm_log_force(port, "VBUS event received: on");
|
|
||||||
port->vbus_present = true;
|
|
||||||
/*
|
|
||||||
* When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
|
|
||||||
@@ -5131,7 +5133,7 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
|
|
||||||
|
|
||||||
static void _tcpm_pd_vbus_off(struct tcpm_port *port)
|
|
||||||
{
|
|
||||||
- tcpm_log_force(port, "VBUS off");
|
|
||||||
+ tcpm_log_force(port, "VBUS event received: off");
|
|
||||||
port->vbus_present = false;
|
|
||||||
port->vbus_never_low = false;
|
|
||||||
switch (port->state) {
|
|
@ -1,34 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 14 Nov 2021 01:14:25 +0100
|
|
||||||
Subject: [PATCH 32/36] usb: typec: fusb302: Add OF extcon support
|
|
||||||
|
|
||||||
It's possible to create a dependency cycle between fusb302 and
|
|
||||||
other drivers via extcon device, so we retrieve the device on
|
|
||||||
demand after probe and not during probe.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 10 ++++++++++
|
|
||||||
1 file changed, 10 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index ae3b930..0c5dd00 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -518,6 +518,16 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
|
|
||||||
int current_limit = 0;
|
|
||||||
unsigned long timeout;
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * To avoid cycles in OF dependencies, we get extcon when necessary
|
|
||||||
+ * outside of probe function.
|
|
||||||
+ */
|
|
||||||
+ if (of_property_read_bool(chip->dev->of_node, "extcon") && !chip->extcon) {
|
|
||||||
+ chip->extcon = extcon_get_edev_by_phandle(chip->dev, 0);
|
|
||||||
+ if (IS_ERR(chip->extcon))
|
|
||||||
+ chip->extcon = NULL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (!chip->extcon)
|
|
||||||
return 0;
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sat, 20 Nov 2021 14:33:58 +0100
|
|
||||||
Subject: [PATCH 33/36] usb: typec: fusb302: Fix register definitions
|
|
||||||
|
|
||||||
MEASURE_VBUS bit is at position 6. MDAC bits are also wrong.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302_reg.h | 16 +++++++---------
|
|
||||||
1 file changed, 7 insertions(+), 9 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h
|
|
||||||
index edc0e4b..f37d226 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302_reg.h
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302_reg.h
|
|
||||||
@@ -27,14 +27,13 @@
|
|
||||||
#define FUSB_REG_SWITCHES1_TXCC2_EN BIT(1)
|
|
||||||
#define FUSB_REG_SWITCHES1_TXCC1_EN BIT(0)
|
|
||||||
#define FUSB_REG_MEASURE 0x04
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC5 BIT(7)
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC4 BIT(6)
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC3 BIT(5)
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC2 BIT(4)
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC1 BIT(3)
|
|
||||||
-#define FUSB_REG_MEASURE_MDAC0 BIT(2)
|
|
||||||
-#define FUSB_REG_MEASURE_VBUS BIT(1)
|
|
||||||
-#define FUSB_REG_MEASURE_XXXX5 BIT(0)
|
|
||||||
+#define FUSB_REG_MEASURE_VBUS BIT(6)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC5 BIT(5)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC4 BIT(4)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC3 BIT(3)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC2 BIT(2)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC1 BIT(1)
|
|
||||||
+#define FUSB_REG_MEASURE_MDAC0 BIT(0)
|
|
||||||
#define FUSB_REG_CONTROL0 0x06
|
|
||||||
#define FUSB_REG_CONTROL0_TX_FLUSH BIT(6)
|
|
||||||
#define FUSB_REG_CONTROL0_INT_MASK BIT(5)
|
|
||||||
@@ -105,7 +104,6 @@
|
|
||||||
#define FUSB_REG_STATUS0A_RX_SOFT_RESET BIT(1)
|
|
||||||
#define FUSB_REG_STATUS0A_RX_HARD_RESET BIT(0)
|
|
||||||
#define FUSB_REG_STATUS1A 0x3D
|
|
||||||
-#define FUSB_REG_STATUS1A_TOGSS BIT(3)
|
|
||||||
#define FUSB_REG_STATUS1A_TOGSS_RUNNING 0x0
|
|
||||||
#define FUSB_REG_STATUS1A_TOGSS_SRC1 0x1
|
|
||||||
#define FUSB_REG_STATUS1A_TOGSS_SRC2 0x2
|
|
@ -1,37 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sat, 20 Nov 2021 14:35:10 +0100
|
|
||||||
Subject: [PATCH 34/36] usb: typec: fusb302: Clear interrupts before we start
|
|
||||||
toggling
|
|
||||||
|
|
||||||
This is recommended by the datasheet.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/tcpm/fusb302.c | 7 +++++++
|
|
||||||
1 file changed, 7 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
index 0c5dd00..011dce5 100644
|
|
||||||
--- a/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
+++ b/drivers/usb/typec/tcpm/fusb302.c
|
|
||||||
@@ -586,6 +586,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
|
|
||||||
enum toggling_mode mode)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
+ u8 reg;
|
|
||||||
|
|
||||||
/* first disable toggling */
|
|
||||||
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_CONTROL2,
|
|
||||||
@@ -644,6 +645,12 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
|
|
||||||
} else {
|
|
||||||
/* Datasheet says vconn MUST be off when toggling */
|
|
||||||
WARN(chip->vconn_on, "Vconn is on during toggle start");
|
|
||||||
+
|
|
||||||
+ /* clear interrupts */
|
|
||||||
+ ret = fusb302_i2c_read(chip, FUSB_REG_INTERRUPT, ®);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
/* unmask TOGDONE interrupt */
|
|
||||||
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
|
|
||||||
FUSB_REG_MASKA_TOGDONE);
|
|
@ -1,388 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:24:40 +0100
|
|
||||||
Subject: [PATCH 35/36] usb: typec: typec-extcon: Add typec -> extcon bridge
|
|
||||||
driver
|
|
||||||
|
|
||||||
This bridge connects standard Type C port interfaces for controling
|
|
||||||
muxes, switches and usb roles to muxes, switches and usb role
|
|
||||||
drivers controlled via extcon interface.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/usb/typec/Kconfig | 7 +
|
|
||||||
drivers/usb/typec/Makefile | 1 +
|
|
||||||
drivers/usb/typec/typec-extcon.c | 337 +++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 345 insertions(+)
|
|
||||||
create mode 100644 drivers/usb/typec/typec-extcon.c
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
|
|
||||||
index ab480f3..01ecc5e 100644
|
|
||||||
--- a/drivers/usb/typec/Kconfig
|
|
||||||
+++ b/drivers/usb/typec/Kconfig
|
|
||||||
@@ -88,6 +88,13 @@ config TYPEC_QCOM_PMIC
|
|
||||||
It will also enable the VBUS output to connected devices when a
|
|
||||||
DFP connection is made.
|
|
||||||
|
|
||||||
+config TYPEC_EXTCON
|
|
||||||
+ tristate "Type-C switch/mux -> extcon interface bridge driver"
|
|
||||||
+ depends on USB_ROLE_SWITCH
|
|
||||||
+ help
|
|
||||||
+ Say Y or M here if your system needs bridging between typec class
|
|
||||||
+ and extcon interfaces.
|
|
||||||
+
|
|
||||||
source "drivers/usb/typec/mux/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/usb/typec/altmodes/Kconfig"
|
|
||||||
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
|
|
||||||
index a0adb89..d9d8293 100644
|
|
||||||
--- a/drivers/usb/typec/Makefile
|
|
||||||
+++ b/drivers/usb/typec/Makefile
|
|
||||||
@@ -8,4 +8,5 @@ obj-$(CONFIG_TYPEC_TPS6598X) += tipd/
|
|
||||||
obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o
|
|
||||||
obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom-pmic-typec.o
|
|
||||||
obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o
|
|
||||||
+obj-$(CONFIG_TYPEC_EXTCON) += typec-extcon.o
|
|
||||||
obj-$(CONFIG_TYPEC) += mux/
|
|
||||||
diff --git a/drivers/usb/typec/typec-extcon.c b/drivers/usb/typec/typec-extcon.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000..143ff24
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/usb/typec/typec-extcon.c
|
|
||||||
@@ -0,0 +1,337 @@
|
|
||||||
+/*
|
|
||||||
+ * typec -> extcon bridge
|
|
||||||
+ * Copyright (c) 2021 Ondřej Jirman <megi@xff.cz>
|
|
||||||
+ *
|
|
||||||
+ * This driver bridges standard type-c interfaces to drivers that
|
|
||||||
+ * expect extcon interface.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/power_supply.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/usb/pd.h>
|
|
||||||
+#include <linux/usb/role.h>
|
|
||||||
+#include <linux/usb/typec.h>
|
|
||||||
+#include <linux/usb/typec_dp.h>
|
|
||||||
+#include <linux/usb/typec_mux.h>
|
|
||||||
+#include <linux/extcon-provider.h>
|
|
||||||
+
|
|
||||||
+struct typec_extcon {
|
|
||||||
+ struct device *dev;
|
|
||||||
+
|
|
||||||
+ /* consumers */
|
|
||||||
+ struct usb_role_switch *role_sw;
|
|
||||||
+ struct typec_switch *sw;
|
|
||||||
+ struct typec_mux *mux;
|
|
||||||
+
|
|
||||||
+ /* providers */
|
|
||||||
+ struct extcon_dev *extcon;
|
|
||||||
+ struct notifier_block extcon_nb;
|
|
||||||
+
|
|
||||||
+ /* cached state from typec controller */
|
|
||||||
+ enum usb_role role;
|
|
||||||
+ enum typec_orientation orientation;
|
|
||||||
+ struct typec_altmode alt;
|
|
||||||
+ unsigned long mode;
|
|
||||||
+ bool has_alt;
|
|
||||||
+ struct mutex lock;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static const unsigned int typec_extcon_cable[] = {
|
|
||||||
+ EXTCON_DISP_DP,
|
|
||||||
+
|
|
||||||
+ EXTCON_USB,
|
|
||||||
+ EXTCON_USB_HOST,
|
|
||||||
+
|
|
||||||
+ EXTCON_CHG_USB_SDP,
|
|
||||||
+ EXTCON_CHG_USB_CDP,
|
|
||||||
+ EXTCON_CHG_USB_DCP,
|
|
||||||
+ EXTCON_CHG_USB_ACA,
|
|
||||||
+
|
|
||||||
+ EXTCON_NONE,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void typec_extcon_set_cable(struct typec_extcon *tce, int id, bool on,
|
|
||||||
+ union extcon_property_value prop_ss,
|
|
||||||
+ union extcon_property_value prop_or)
|
|
||||||
+{
|
|
||||||
+ union extcon_property_value cur_ss, cur_or;
|
|
||||||
+ bool prop_diff = false;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = extcon_get_property(tce->extcon, id,
|
|
||||||
+ EXTCON_PROP_USB_SS, &cur_ss);
|
|
||||||
+ if (ret || cur_ss.intval != prop_ss.intval)
|
|
||||||
+ prop_diff = true;
|
|
||||||
+
|
|
||||||
+ ret = extcon_get_property(tce->extcon, id,
|
|
||||||
+ EXTCON_PROP_USB_TYPEC_POLARITY, &cur_or);
|
|
||||||
+ if (ret || cur_or.intval != prop_or.intval)
|
|
||||||
+ prop_diff = true;
|
|
||||||
+
|
|
||||||
+ if (!on && extcon_get_state(tce->extcon, id)) {
|
|
||||||
+ extcon_set_state_sync(tce->extcon, id, false);
|
|
||||||
+ } else if (on && (!extcon_get_state(tce->extcon, id) || prop_diff)) {
|
|
||||||
+ extcon_set_state(tce->extcon, id, true);
|
|
||||||
+ extcon_set_property(tce->extcon, id,
|
|
||||||
+ EXTCON_PROP_USB_SS, prop_ss);
|
|
||||||
+ extcon_set_property(tce->extcon, id,
|
|
||||||
+ EXTCON_PROP_USB_TYPEC_POLARITY, prop_or);
|
|
||||||
+ extcon_sync(tce->extcon, id);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_sync_extcon(struct typec_extcon *tce)
|
|
||||||
+{
|
|
||||||
+ union extcon_property_value prop_ss, prop_or;
|
|
||||||
+ bool has_dp = false;
|
|
||||||
+
|
|
||||||
+ mutex_lock(&tce->lock);
|
|
||||||
+
|
|
||||||
+ /* connector is disconnected */
|
|
||||||
+ if (tce->orientation == TYPEC_ORIENTATION_NONE) {
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_USB, false, prop_ss, prop_or);
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_USB_HOST, false, prop_ss, prop_or);
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_DISP_DP, false, prop_ss, prop_or);
|
|
||||||
+
|
|
||||||
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_SDP, false);
|
|
||||||
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_DCP, false);
|
|
||||||
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_CDP, false);
|
|
||||||
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_ACA, false);
|
|
||||||
+
|
|
||||||
+ goto out_unlock;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ prop_or.intval = tce->orientation == TYPEC_ORIENTATION_NORMAL ? 0 : 1;
|
|
||||||
+ prop_ss.intval = 0;
|
|
||||||
+
|
|
||||||
+ if (tce->has_alt && tce->alt.svid == USB_TYPEC_DP_SID) {
|
|
||||||
+ switch (tce->mode) {
|
|
||||||
+ case TYPEC_STATE_SAFE:
|
|
||||||
+ break;
|
|
||||||
+ case TYPEC_DP_STATE_C:
|
|
||||||
+ case TYPEC_DP_STATE_E:
|
|
||||||
+ has_dp = true;
|
|
||||||
+ break;
|
|
||||||
+ case TYPEC_DP_STATE_D:
|
|
||||||
+ has_dp = true;
|
|
||||||
+ fallthrough;
|
|
||||||
+ case TYPEC_STATE_USB:
|
|
||||||
+ prop_ss.intval = 1;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ dev_err(tce->dev, "unhandled mux mode=%lu\n", tce->mode);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_USB,
|
|
||||||
+ tce->role == USB_ROLE_DEVICE, prop_ss, prop_or);
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_USB_HOST,
|
|
||||||
+ tce->role == USB_ROLE_HOST, prop_ss, prop_or);
|
|
||||||
+
|
|
||||||
+ typec_extcon_set_cable(tce, EXTCON_DISP_DP, has_dp, prop_ss, prop_or);
|
|
||||||
+
|
|
||||||
+out_unlock:
|
|
||||||
+ mutex_unlock(&tce->lock);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_sw_set(struct typec_switch *sw,
|
|
||||||
+ enum typec_orientation orientation)
|
|
||||||
+{
|
|
||||||
+ struct typec_extcon *tce = typec_switch_get_drvdata(sw);
|
|
||||||
+
|
|
||||||
+ dev_dbg(tce->dev, "SW SET: orientation=%d\n", orientation);
|
|
||||||
+
|
|
||||||
+ mutex_lock(&tce->lock);
|
|
||||||
+ tce->orientation = orientation;
|
|
||||||
+ mutex_unlock(&tce->lock);
|
|
||||||
+
|
|
||||||
+ typec_extcon_sync_extcon(tce);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_mux_set(struct typec_mux *mux,
|
|
||||||
+ struct typec_mux_state *state)
|
|
||||||
+{
|
|
||||||
+ struct typec_extcon *tce = typec_mux_get_drvdata(mux);
|
|
||||||
+ struct typec_altmode *alt = state->alt;
|
|
||||||
+
|
|
||||||
+ dev_dbg(tce->dev, "MUX SET: state->mode=%lu\n", state->mode);
|
|
||||||
+ if (alt)
|
|
||||||
+ dev_dbg(tce->dev, " ...alt: svid=%04hx mode=%d vdo=%08x active=%u\n",
|
|
||||||
+ alt->svid, alt->mode, alt->vdo, alt->active);
|
|
||||||
+
|
|
||||||
+ mutex_lock(&tce->lock);
|
|
||||||
+ tce->mode = state->mode;
|
|
||||||
+ tce->has_alt = alt != NULL;
|
|
||||||
+ if (alt)
|
|
||||||
+ tce->alt = *alt;
|
|
||||||
+ mutex_unlock(&tce->lock);
|
|
||||||
+
|
|
||||||
+ typec_extcon_sync_extcon(tce);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_usb_set_role(struct usb_role_switch *sw,
|
|
||||||
+ enum usb_role role)
|
|
||||||
+{
|
|
||||||
+ struct typec_extcon *tce = usb_role_switch_get_drvdata(sw);
|
|
||||||
+
|
|
||||||
+ dev_dbg(tce->dev, "ROLE SET: role=%d\n", role);
|
|
||||||
+
|
|
||||||
+ mutex_lock(&tce->lock);
|
|
||||||
+ tce->role = role;
|
|
||||||
+ mutex_unlock(&tce->lock);
|
|
||||||
+
|
|
||||||
+ typec_extcon_sync_extcon(tce);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_notifier(struct notifier_block *nb,
|
|
||||||
+ unsigned long action, void *data)
|
|
||||||
+{
|
|
||||||
+ struct typec_extcon *tce = container_of(nb, struct typec_extcon, extcon_nb);
|
|
||||||
+
|
|
||||||
+ bool sdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_SDP);
|
|
||||||
+ bool cdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_CDP);
|
|
||||||
+ bool dcp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_DCP);
|
|
||||||
+ bool usb = extcon_get_state(tce->extcon, EXTCON_USB);
|
|
||||||
+ bool usb_host = extcon_get_state(tce->extcon, EXTCON_USB_HOST);
|
|
||||||
+ bool dp = extcon_get_state(tce->extcon, EXTCON_DISP_DP);
|
|
||||||
+
|
|
||||||
+ dev_info(tce->dev, "extcon changed sdp=%d cdp=%d dcp=%d usb=%d usb_host=%d dp=%d\n",
|
|
||||||
+ sdp, cdp, dcp, usb, usb_host, dp);
|
|
||||||
+
|
|
||||||
+ return NOTIFY_OK;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct typec_switch_desc sw_desc = { };
|
|
||||||
+ struct typec_mux_desc mux_desc = { };
|
|
||||||
+ struct usb_role_switch_desc role_desc = { };
|
|
||||||
+ struct device *dev = &pdev->dev;
|
|
||||||
+ struct typec_extcon *tce;
|
|
||||||
+ int ret = 0;
|
|
||||||
+
|
|
||||||
+ tce = devm_kzalloc(dev, sizeof(*tce), GFP_KERNEL);
|
|
||||||
+ if (!tce)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ tce->dev = &pdev->dev;
|
|
||||||
+ mutex_init(&tce->lock);
|
|
||||||
+ tce->mode = TYPEC_STATE_SAFE;
|
|
||||||
+
|
|
||||||
+ sw_desc.drvdata = tce;
|
|
||||||
+ sw_desc.fwnode = dev->fwnode;
|
|
||||||
+ sw_desc.set = typec_extcon_sw_set;
|
|
||||||
+
|
|
||||||
+ tce->sw = typec_switch_register(dev, &sw_desc);
|
|
||||||
+ if (IS_ERR(tce->sw))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(tce->sw),
|
|
||||||
+ "Error registering typec switch\n");
|
|
||||||
+
|
|
||||||
+ mux_desc.drvdata = tce;
|
|
||||||
+ mux_desc.fwnode = dev->fwnode;
|
|
||||||
+ mux_desc.set = typec_extcon_mux_set;
|
|
||||||
+
|
|
||||||
+ tce->mux = typec_mux_register(dev, &mux_desc);
|
|
||||||
+ if (IS_ERR(tce->mux)) {
|
|
||||||
+ ret = dev_err_probe(dev, PTR_ERR(tce->mux),
|
|
||||||
+ "Error registering typec mux\n");
|
|
||||||
+ goto err_sw;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ role_desc.driver_data = tce;
|
|
||||||
+ role_desc.fwnode = dev->fwnode;
|
|
||||||
+ role_desc.name = fwnode_get_name(dev->fwnode);
|
|
||||||
+ role_desc.set = typec_extcon_usb_set_role;
|
|
||||||
+
|
|
||||||
+ tce->role_sw = usb_role_switch_register(dev, &role_desc);
|
|
||||||
+ if (IS_ERR(tce->role_sw)) {
|
|
||||||
+ ret = dev_err_probe(dev, PTR_ERR(tce->role_sw),
|
|
||||||
+ "Error registering USB role switch\n");
|
|
||||||
+ goto err_mux;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ tce->extcon = devm_extcon_dev_allocate(dev, typec_extcon_cable);
|
|
||||||
+ if (IS_ERR(tce->extcon)) {
|
|
||||||
+ ret = PTR_ERR(tce->extcon);
|
|
||||||
+ goto err_role;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = devm_extcon_dev_register(dev, tce->extcon);
|
|
||||||
+ if (ret) {
|
|
||||||
+ ret = dev_err_probe(dev, ret, "failed to register extcon device\n");
|
|
||||||
+ goto err_role;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_USB,
|
|
||||||
+ EXTCON_PROP_USB_SS);
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_USB,
|
|
||||||
+ EXTCON_PROP_USB_TYPEC_POLARITY);
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
|
|
||||||
+ EXTCON_PROP_USB_SS);
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
|
|
||||||
+ EXTCON_PROP_USB_TYPEC_POLARITY);
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
|
|
||||||
+ EXTCON_PROP_USB_SS);
|
|
||||||
+ extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
|
|
||||||
+ EXTCON_PROP_USB_TYPEC_POLARITY);
|
|
||||||
+
|
|
||||||
+ tce->extcon_nb.notifier_call = typec_extcon_notifier;
|
|
||||||
+ ret = devm_extcon_register_notifier_all(dev, tce->extcon, &tce->extcon_nb);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err_probe(dev, ret, "Failed to register extcon notifier\n");
|
|
||||||
+ goto err_role;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err_role:
|
|
||||||
+ usb_role_switch_unregister(tce->role_sw);
|
|
||||||
+err_mux:
|
|
||||||
+ typec_mux_unregister(tce->mux);
|
|
||||||
+err_sw:
|
|
||||||
+ typec_switch_unregister(tce->sw);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int typec_extcon_remove(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct typec_extcon *tce = platform_get_drvdata(pdev);
|
|
||||||
+
|
|
||||||
+ usb_role_switch_unregister(tce->role_sw);
|
|
||||||
+ typec_mux_unregister(tce->mux);
|
|
||||||
+ typec_switch_unregister(tce->sw);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct of_device_id typec_extcon_of_match_table[] = {
|
|
||||||
+ { .compatible = "linux,typec-extcon-bridge" },
|
|
||||||
+ { },
|
|
||||||
+};
|
|
||||||
+MODULE_DEVICE_TABLE(of, typec_extcon_of_match_table);
|
|
||||||
+
|
|
||||||
+static struct platform_driver typec_extcon_driver = {
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "typec-extcon",
|
|
||||||
+ .of_match_table = typec_extcon_of_match_table,
|
|
||||||
+ },
|
|
||||||
+ .probe = typec_extcon_probe,
|
|
||||||
+ .remove = typec_extcon_remove,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+module_platform_driver(typec_extcon_driver);
|
|
||||||
+
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
+MODULE_AUTHOR("Ondrej Jirman <megous@megous.com>");
|
|
||||||
+MODULE_DESCRIPTION("typec -> extcon bridge driver");
|
|
@ -1,64 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 17:32:18 +0100
|
|
||||||
Subject: [PATCH 36/36] phy: rockchip-typec: Make sure the plug orientation is
|
|
||||||
respected
|
|
||||||
|
|
||||||
RK3399 TRM says about bit 8:
|
|
||||||
|
|
||||||
typec_conn_dir_sel: TypeC connect direction select
|
|
||||||
|
|
||||||
- 0: select typec_conn_dir (bit0 of this register) to TypeC PHY
|
|
||||||
- 1: select TCPC ouput typec_con_dir to TypeC PHY (default value)
|
|
||||||
|
|
||||||
This means that by default, typec_conn_dir bit is not respected.
|
|
||||||
Fix setting of typec_conn_dir by setting typec_conn_dir to 0 first.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/phy/rockchip/phy-rockchip-typec.c | 5 +++++
|
|
||||||
1 file changed, 5 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
|
|
||||||
index d2bbdc9..fa10ee9 100644
|
|
||||||
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
|
|
||||||
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
|
|
||||||
@@ -350,6 +350,7 @@ struct usb3phy_reg {
|
|
||||||
* struct rockchip_usb3phy_port_cfg - usb3-phy port configuration.
|
|
||||||
* @reg: the base address for usb3-phy config.
|
|
||||||
* @typec_conn_dir: the register of type-c connector direction.
|
|
||||||
+ * @typec_conn_dir_sel: the register of type-c connector direction source.
|
|
||||||
* @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
|
|
||||||
* @external_psm: the register of type-c phy external psm clock.
|
|
||||||
* @pipe_status: the register of type-c phy pipe status.
|
|
||||||
@@ -360,6 +361,7 @@ struct usb3phy_reg {
|
|
||||||
struct rockchip_usb3phy_port_cfg {
|
|
||||||
unsigned int reg;
|
|
||||||
struct usb3phy_reg typec_conn_dir;
|
|
||||||
+ struct usb3phy_reg typec_conn_dir_sel;
|
|
||||||
struct usb3phy_reg usb3tousb2_en;
|
|
||||||
struct usb3phy_reg external_psm;
|
|
||||||
struct usb3phy_reg pipe_status;
|
|
||||||
@@ -434,6 +436,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
|
|
||||||
{
|
|
||||||
.reg = 0xff7c0000,
|
|
||||||
.typec_conn_dir = { 0xe580, 0, 16 },
|
|
||||||
+ .typec_conn_dir_sel = { 0xe580, 8, 16+8 },
|
|
||||||
.usb3tousb2_en = { 0xe580, 3, 19 },
|
|
||||||
.external_psm = { 0xe588, 14, 30 },
|
|
||||||
.pipe_status = { 0xe5c0, 0, 0 },
|
|
||||||
@@ -444,6 +447,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
|
|
||||||
{
|
|
||||||
.reg = 0xff800000,
|
|
||||||
.typec_conn_dir = { 0xe58c, 0, 16 },
|
|
||||||
+ .typec_conn_dir_sel = { 0xe58c, 8, 16+8 },
|
|
||||||
.usb3tousb2_en = { 0xe58c, 3, 19 },
|
|
||||||
.external_psm = { 0xe594, 14, 30 },
|
|
||||||
.pipe_status = { 0xe5c0, 16, 16 },
|
|
||||||
@@ -739,6 +743,7 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
|
|
||||||
|
|
||||||
reset_control_deassert(tcphy->tcphy_rst);
|
|
||||||
|
|
||||||
+ property_enable(tcphy, &cfg->typec_conn_dir_sel, 0);
|
|
||||||
property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip);
|
|
||||||
tcphy_dp_aux_set_flip(tcphy);
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 22 Oct 2021 18:10:18 +0200
|
|
||||||
Subject: [PATCH 20/36] media: i2c: imx258: Add support for powerdown gpio
|
|
||||||
|
|
||||||
On some boards powerdown signal needs to be deasserted for this
|
|
||||||
sensor to be enabled.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/imx258.c | 12 ++++++++++++
|
|
||||||
1 file changed, 12 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
|
|
||||||
index c249507..be5adcc 100644
|
|
||||||
--- a/drivers/media/i2c/imx258.c
|
|
||||||
+++ b/drivers/media/i2c/imx258.c
|
|
||||||
@@ -612,6 +612,8 @@ struct imx258 {
|
|
||||||
struct v4l2_ctrl *hblank;
|
|
||||||
struct v4l2_ctrl *exposure;
|
|
||||||
|
|
||||||
+ struct gpio_desc *pwdn_gpio;
|
|
||||||
+
|
|
||||||
/* Current mode */
|
|
||||||
const struct imx258_mode *cur_mode;
|
|
||||||
|
|
||||||
@@ -1010,6 +1012,8 @@ static int imx258_power_on(struct device *dev)
|
|
||||||
struct imx258 *imx258 = to_imx258(sd);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
+ gpiod_set_value_cansleep(imx258->pwdn_gpio, 0);
|
|
||||||
+
|
|
||||||
ret = clk_prepare_enable(imx258->clk);
|
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "failed to enable clock\n");
|
|
||||||
@@ -1024,6 +1028,8 @@ static int imx258_power_off(struct device *dev)
|
|
||||||
|
|
||||||
clk_disable_unprepare(imx258->clk);
|
|
||||||
|
|
||||||
+ gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1284,6 +1290,12 @@ static int imx258_probe(struct i2c_client *client)
|
|
||||||
if (ret || val != 180)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
+ /* request optional power down pin */
|
|
||||||
+ imx258->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
|
|
||||||
+ GPIOD_OUT_HIGH);
|
|
||||||
+ if (IS_ERR(imx258->pwdn_gpio))
|
|
||||||
+ return PTR_ERR(imx258->pwdn_gpio);
|
|
||||||
+
|
|
||||||
/* Initialize subdev */
|
|
||||||
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 22 Oct 2021 18:11:26 +0200
|
|
||||||
Subject: [PATCH 21/36] media: i2c: imx258: Don't be too strict about clock
|
|
||||||
rate
|
|
||||||
|
|
||||||
On Pinephone Pro, we are not able to set 19.2MHz precisely.
|
|
||||||
Allow some slack in clock rate.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/imx258.c | 9 +++++++--
|
|
||||||
1 file changed, 7 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
|
|
||||||
index be5adcc..e64fadc 100644
|
|
||||||
--- a/drivers/media/i2c/imx258.c
|
|
||||||
+++ b/drivers/media/i2c/imx258.c
|
|
||||||
@@ -79,7 +79,9 @@
|
|
||||||
#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
|
|
||||||
|
|
||||||
/* Input clock frequency in Hz */
|
|
||||||
+#define IMX258_INPUT_CLOCK_FREQ_MIN 19000000
|
|
||||||
#define IMX258_INPUT_CLOCK_FREQ 19200000
|
|
||||||
+#define IMX258_INPUT_CLOCK_FREQ_MAX 19400000
|
|
||||||
|
|
||||||
struct imx258_reg {
|
|
||||||
u16 address;
|
|
||||||
@@ -1277,8 +1279,11 @@ static int imx258_probe(struct i2c_client *client)
|
|
||||||
} else {
|
|
||||||
val = clk_get_rate(imx258->clk);
|
|
||||||
}
|
|
||||||
- if (val != IMX258_INPUT_CLOCK_FREQ) {
|
|
||||||
- dev_err(&client->dev, "input clock frequency not supported\n");
|
|
||||||
+
|
|
||||||
+ if (val < IMX258_INPUT_CLOCK_FREQ_MIN
|
|
||||||
+ || val > IMX258_INPUT_CLOCK_FREQ_MAX) {
|
|
||||||
+ dev_err(&client->dev, "input clock frequency %u not supported\n",
|
|
||||||
+ val);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 22 Oct 2021 21:44:13 +0200
|
|
||||||
Subject: [PATCH 22/36] media: i2c: imx258: Add support for reset gpio
|
|
||||||
|
|
||||||
It was documented in DT, but not implemented.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/imx258.c | 14 +++++++++++++-
|
|
||||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
|
|
||||||
index e64fadc..ec6e919 100644
|
|
||||||
--- a/drivers/media/i2c/imx258.c
|
|
||||||
+++ b/drivers/media/i2c/imx258.c
|
|
||||||
@@ -615,6 +615,7 @@ struct imx258 {
|
|
||||||
struct v4l2_ctrl *exposure;
|
|
||||||
|
|
||||||
struct gpio_desc *pwdn_gpio;
|
|
||||||
+ struct gpio_desc *reset_gpio;
|
|
||||||
|
|
||||||
/* Current mode */
|
|
||||||
const struct imx258_mode *cur_mode;
|
|
||||||
@@ -1020,7 +1021,11 @@ static int imx258_power_on(struct device *dev)
|
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "failed to enable clock\n");
|
|
||||||
|
|
||||||
- return ret;
|
|
||||||
+ gpiod_set_value_cansleep(imx258->reset_gpio, 0);
|
|
||||||
+
|
|
||||||
+ usleep_range(400, 500);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx258_power_off(struct device *dev)
|
|
||||||
@@ -1030,6 +1035,7 @@ static int imx258_power_off(struct device *dev)
|
|
||||||
|
|
||||||
clk_disable_unprepare(imx258->clk);
|
|
||||||
|
|
||||||
+ gpiod_set_value_cansleep(imx258->reset_gpio, 1);
|
|
||||||
gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -1301,6 +1307,12 @@ static int imx258_probe(struct i2c_client *client)
|
|
||||||
if (IS_ERR(imx258->pwdn_gpio))
|
|
||||||
return PTR_ERR(imx258->pwdn_gpio);
|
|
||||||
|
|
||||||
+ /* request optional reset pin */
|
|
||||||
+ imx258->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
|
|
||||||
+ GPIOD_OUT_HIGH);
|
|
||||||
+ if (IS_ERR(imx258->reset_gpio))
|
|
||||||
+ return PTR_ERR(imx258->reset_gpio);
|
|
||||||
+
|
|
||||||
/* Initialize subdev */
|
|
||||||
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 22 Oct 2021 21:44:30 +0200
|
|
||||||
Subject: [PATCH 23/36] media: i2c: imx258: Add support for power supplies
|
|
||||||
|
|
||||||
They were documented in DT, but not implemented.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/imx258.c | 39 +++++++++++++++++++++++++++++++++++++--
|
|
||||||
1 file changed, 37 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
|
|
||||||
index ec6e919..2570b51 100644
|
|
||||||
--- a/drivers/media/i2c/imx258.c
|
|
||||||
+++ b/drivers/media/i2c/imx258.c
|
|
||||||
@@ -602,6 +602,15 @@ static const struct imx258_mode supported_modes[] = {
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+/* regulator supplies */
|
|
||||||
+static const char * const imx258_supply_names[] = {
|
|
||||||
+ "vana", /* Analog (2.8V) supply */
|
|
||||||
+ "vdig", /* Digital Core (1.5V) supply */
|
|
||||||
+ "vif", /* Digital I/O (1.8V) supply */
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define IMX258_SUPPLY_COUNT ARRAY_SIZE(imx258_supply_names)
|
|
||||||
+
|
|
||||||
struct imx258 {
|
|
||||||
struct v4l2_subdev sd;
|
|
||||||
struct media_pad pad;
|
|
||||||
@@ -616,6 +625,7 @@ struct imx258 {
|
|
||||||
|
|
||||||
struct gpio_desc *pwdn_gpio;
|
|
||||||
struct gpio_desc *reset_gpio;
|
|
||||||
+ struct regulator_bulk_data supplies[IMX258_SUPPLY_COUNT];
|
|
||||||
|
|
||||||
/* Current mode */
|
|
||||||
const struct imx258_mode *cur_mode;
|
|
||||||
@@ -1015,11 +1025,26 @@ static int imx258_power_on(struct device *dev)
|
|
||||||
struct imx258 *imx258 = to_imx258(sd);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
+ ret = regulator_bulk_enable(IMX258_SUPPLY_COUNT, imx258->supplies);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(dev, "failed to enable regulators\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ mdelay(20);
|
|
||||||
+
|
|
||||||
gpiod_set_value_cansleep(imx258->pwdn_gpio, 0);
|
|
||||||
|
|
||||||
+ mdelay(5);
|
|
||||||
+
|
|
||||||
ret = clk_prepare_enable(imx258->clk);
|
|
||||||
- if (ret)
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(dev, "failed to enable clock\n");
|
|
||||||
+ regulator_bulk_disable(IMX258_SUPPLY_COUNT, imx258->supplies);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ usleep_range(1000, 2000);
|
|
||||||
|
|
||||||
gpiod_set_value_cansleep(imx258->reset_gpio, 0);
|
|
||||||
|
|
||||||
@@ -1038,6 +1063,8 @@ static int imx258_power_off(struct device *dev)
|
|
||||||
gpiod_set_value_cansleep(imx258->reset_gpio, 1);
|
|
||||||
gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
|
|
||||||
|
|
||||||
+ regulator_bulk_disable(IMX258_SUPPLY_COUNT, imx258->supplies);
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1266,7 +1293,7 @@ static void imx258_free_controls(struct imx258 *imx258)
|
|
||||||
static int imx258_probe(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
struct imx258 *imx258;
|
|
||||||
- int ret;
|
|
||||||
+ int ret, i;
|
|
||||||
u32 val = 0;
|
|
||||||
|
|
||||||
imx258 = devm_kzalloc(&client->dev, sizeof(*imx258), GFP_KERNEL);
|
|
||||||
@@ -1301,6 +1328,14 @@ static int imx258_probe(struct i2c_client *client)
|
|
||||||
if (ret || val != 180)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
+ for (i = 0; i < IMX258_SUPPLY_COUNT; i++)
|
|
||||||
+ imx258->supplies[i].supply = imx258_supply_names[i];
|
|
||||||
+ ret = devm_regulator_bulk_get(&client->dev,
|
|
||||||
+ IMX258_SUPPLY_COUNT,
|
|
||||||
+ imx258->supplies);
|
|
||||||
+ if (ret)
|
|
||||||
+ return dev_err_probe(&client->dev, ret, "Failed to get supplies\n");
|
|
||||||
+
|
|
||||||
/* request optional power down pin */
|
|
||||||
imx258->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
|
|
||||||
GPIOD_OUT_HIGH);
|
|
@ -1,52 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 24 Jan 2020 18:25:12 +0100
|
|
||||||
Subject: [PATCH 091/194] media: ov5640: Add more framerates to the driver
|
|
||||||
(some of them even work!)
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 14 +++++++++++---
|
|
||||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index ddbd713..624a3c0 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -112,7 +112,11 @@ enum ov5640_mode_id {
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ov5640_frame_rate {
|
|
||||||
- OV5640_15_FPS = 0,
|
|
||||||
+ OV5640_2_FPS = 0,
|
|
||||||
+ OV5640_3_FPS,
|
|
||||||
+ OV5640_5_FPS,
|
|
||||||
+ OV5640_7_FPS,
|
|
||||||
+ OV5640_15_FPS,
|
|
||||||
OV5640_30_FPS,
|
|
||||||
OV5640_60_FPS,
|
|
||||||
OV5640_NUM_FRAMERATES,
|
|
||||||
@@ -156,6 +160,10 @@ MODULE_PARM_DESC(virtual_channel,
|
|
||||||
"MIPI CSI-2 virtual channel (0..3), default 0");
|
|
||||||
|
|
||||||
static const int ov5640_framerates[] = {
|
|
||||||
+ [OV5640_2_FPS] = 2,
|
|
||||||
+ [OV5640_3_FPS] = 3,
|
|
||||||
+ [OV5640_5_FPS] = 5,
|
|
||||||
+ [OV5640_7_FPS] = 7,
|
|
||||||
[OV5640_15_FPS] = 15,
|
|
||||||
[OV5640_30_FPS] = 30,
|
|
||||||
[OV5640_60_FPS] = 60,
|
|
||||||
@@ -2193,11 +2201,11 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
|
|
||||||
u32 width, u32 height)
|
|
||||||
{
|
|
||||||
const struct ov5640_mode_info *mode;
|
|
||||||
- enum ov5640_frame_rate rate = OV5640_15_FPS;
|
|
||||||
+ enum ov5640_frame_rate rate = OV5640_2_FPS;
|
|
||||||
int minfps, maxfps, best_fps, fps;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
- minfps = ov5640_framerates[OV5640_15_FPS];
|
|
||||||
+ minfps = ov5640_framerates[OV5640_2_FPS];
|
|
||||||
maxfps = ov5640_framerates[OV5640_60_FPS];
|
|
||||||
|
|
||||||
if (fi->numerator == 0) {
|
|
@ -1,47 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Fri, 24 Jan 2020 18:25:59 +0100
|
|
||||||
Subject: [PATCH 158/465] media: ov5640: [Experiment] Try to disable
|
|
||||||
denoising/sharpening
|
|
||||||
|
|
||||||
Not sure how this works exactly. More tests are needed.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 17 +++++++++++++++++
|
|
||||||
1 file changed, 17 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index 624a3c0..2f6f97e 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -1772,6 +1772,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
|
|
||||||
bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
|
|
||||||
unsigned long rate;
|
|
||||||
int ret;
|
|
||||||
+ u8 tmp;
|
|
||||||
|
|
||||||
dn_mode = mode->dn_mode;
|
|
||||||
orig_dn_mode = orig_mode->dn_mode;
|
|
||||||
@@ -1844,6 +1845,22 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
+ ret = ov5640_read_reg(sensor, 0x5308, &tmp);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_write_reg(sensor, 0x5308, tmp | 0x10 | 0x40);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_write_reg(sensor, 0x5306, 0);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_write_reg(sensor, 0x5302, 0);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
sensor->pending_mode_change = false;
|
|
||||||
sensor->last_mode = mode;
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 26 Jan 2020 00:19:40 +0100
|
|
||||||
Subject: [PATCH 093/194] media: ov5640: Sleep after poweroff to ensure next
|
|
||||||
poweron is not too early
|
|
||||||
|
|
||||||
It's easy to use v4l2 userspace api in such a way that user can trigger
|
|
||||||
a brownout on the sensor instead of a proper powerdown and powerup.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index 2f6f97e..8a53c0c 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -1971,6 +1971,7 @@ static void ov5640_set_power_off(struct ov5640_dev *sensor)
|
|
||||||
ov5640_power(sensor, false);
|
|
||||||
regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
|
|
||||||
clk_disable_unprepare(sensor->xclk);
|
|
||||||
+ msleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
|
|
@ -1,86 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 26 Jan 2020 00:28:10 +0100
|
|
||||||
Subject: [PATCH 094/194] media: ov5640: Don't powerup the sensor during
|
|
||||||
driver probe
|
|
||||||
|
|
||||||
It causes autofocus clicking during boot on some devices, and
|
|
||||||
it's enough to do it when turning on the sensor power by media
|
|
||||||
pipeline via s_power callback, later on.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 40 ++++++++--------------------------------
|
|
||||||
1 file changed, 8 insertions(+), 32 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index 8a53c0c..75f71e6 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -1932,6 +1932,7 @@ static void ov5640_reset(struct ov5640_dev *sensor)
|
|
||||||
static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = sensor->i2c_client;
|
|
||||||
+ u16 chip_id;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(sensor->xclk);
|
|
||||||
@@ -1956,6 +1957,13 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
|
||||||
if (ret)
|
|
||||||
goto power_off;
|
|
||||||
|
|
||||||
+ ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
|
|
||||||
+ __func__);
|
|
||||||
+ goto power_off;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
power_off:
|
|
||||||
@@ -3039,34 +3047,6 @@ static int ov5640_get_regulators(struct ov5640_dev *sensor)
|
|
||||||
sensor->supplies);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int ov5640_check_chip_id(struct ov5640_dev *sensor)
|
|
||||||
-{
|
|
||||||
- struct i2c_client *client = sensor->i2c_client;
|
|
||||||
- int ret = 0;
|
|
||||||
- u16 chip_id;
|
|
||||||
-
|
|
||||||
- ret = ov5640_set_power_on(sensor);
|
|
||||||
- if (ret)
|
|
||||||
- return ret;
|
|
||||||
-
|
|
||||||
- ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
|
|
||||||
- if (ret) {
|
|
||||||
- dev_err(&client->dev, "%s: failed to read chip identifier\n",
|
|
||||||
- __func__);
|
|
||||||
- goto power_off;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (chip_id != 0x5640) {
|
|
||||||
- dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
|
|
||||||
- __func__, chip_id);
|
|
||||||
- ret = -ENXIO;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
-power_off:
|
|
||||||
- ov5640_set_power_off(sensor);
|
|
||||||
- return ret;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static int ov5640_probe(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
struct device *dev = &client->dev;
|
|
||||||
@@ -3184,10 +3164,6 @@ static int ov5640_probe(struct i2c_client *client)
|
|
||||||
|
|
||||||
mutex_init(&sensor->lock);
|
|
||||||
|
|
||||||
- ret = ov5640_check_chip_id(sensor);
|
|
||||||
- if (ret)
|
|
||||||
- goto entity_cleanup;
|
|
||||||
-
|
|
||||||
ret = ov5640_init_controls(sensor);
|
|
||||||
if (ret)
|
|
||||||
goto entity_cleanup;
|
|
@ -1,405 +0,0 @@
|
|||||||
From: Martijn Braam <martijn@brixit.nl>
|
|
||||||
Date: Mon, 28 Sep 2020 14:26:11 +0200
|
|
||||||
Subject: [PATCH 120/194] media: ov5640: Implement autofocus
|
|
||||||
|
|
||||||
The autofocus functionality needs a firmware blob loaded into the
|
|
||||||
internal microcontroller.
|
|
||||||
|
|
||||||
V4L2 doesn't have an api to control all autofocus functionality, but
|
|
||||||
this at least makes it possible to focus on the center of the sensor.
|
|
||||||
|
|
||||||
Signed-off-by: Martijn Braam <martijn@brixit.nl>
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 273 +++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
1 file changed, 273 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index 75f71e6..246563e 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -9,6 +9,7 @@
|
|
||||||
#include <linux/clkdev.h>
|
|
||||||
#include <linux/ctype.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
+#include <linux/firmware.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/gpio/consumer.h>
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
@@ -31,7 +32,11 @@
|
|
||||||
|
|
||||||
#define OV5640_DEFAULT_SLAVE_ID 0x3c
|
|
||||||
|
|
||||||
+#define OV5640_REG_SYS_RESET00 0x3000
|
|
||||||
+#define OV5640_REG_SYS_RESET01 0x3001
|
|
||||||
#define OV5640_REG_SYS_RESET02 0x3002
|
|
||||||
+#define OV5640_REG_SYS_CLOCK_ENABLE00 0x3004
|
|
||||||
+#define OV5640_REG_SYS_CLOCK_ENABLE01 0x3005
|
|
||||||
#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
|
|
||||||
#define OV5640_REG_SYS_CTRL0 0x3008
|
|
||||||
#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
|
|
||||||
@@ -41,6 +46,14 @@
|
|
||||||
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
|
|
||||||
#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018
|
|
||||||
#define OV5640_REG_PAD_OUTPUT00 0x3019
|
|
||||||
+#define OV5640_REG_FW_CMD_MAIN 0x3022
|
|
||||||
+#define OV5640_REG_FW_CMD_ACK 0x3023
|
|
||||||
+#define OV5640_REG_FW_CMD_PARA0 0x3024
|
|
||||||
+#define OV5640_REG_FW_CMD_PARA1 0x3025
|
|
||||||
+#define OV5640_REG_FW_CMD_PARA2 0x3026
|
|
||||||
+#define OV5640_REG_FW_CMD_PARA3 0x3027
|
|
||||||
+#define OV5640_REG_FW_CMD_PARA4 0x3028
|
|
||||||
+#define OV5640_REG_FW_STATUS 0x3029
|
|
||||||
#define OV5640_REG_SYSTEM_CONTROL1 0x302e
|
|
||||||
#define OV5640_REG_SC_PLL_CTRL0 0x3034
|
|
||||||
#define OV5640_REG_SC_PLL_CTRL1 0x3035
|
|
||||||
@@ -59,6 +72,7 @@
|
|
||||||
#define OV5640_REG_AEC_PK_MANUAL 0x3503
|
|
||||||
#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
|
|
||||||
#define OV5640_REG_AEC_PK_VTS 0x350c
|
|
||||||
+#define OV5640_REG_VCM_CONTROL4 0x3606
|
|
||||||
#define OV5640_REG_TIMING_DVPHO 0x3808
|
|
||||||
#define OV5640_REG_TIMING_DVPVO 0x380a
|
|
||||||
#define OV5640_REG_TIMING_HTS 0x380c
|
|
||||||
@@ -96,6 +110,20 @@
|
|
||||||
#define OV5640_REG_SDE_CTRL4 0x5584
|
|
||||||
#define OV5640_REG_SDE_CTRL5 0x5585
|
|
||||||
#define OV5640_REG_AVG_READOUT 0x56a1
|
|
||||||
+#define OV5640_REG_FIRMWARE_BASE 0x8000
|
|
||||||
+
|
|
||||||
+#define OV5640_FW_STATUS_S_FIRMWARE 0x7f
|
|
||||||
+#define OV5640_FW_STATUS_S_STARTUP 0x7e
|
|
||||||
+#define OV5640_FW_STATUS_S_IDLE 0x70
|
|
||||||
+#define OV5640_FW_STATUS_S_FOCUSING 0x00
|
|
||||||
+#define OV5640_FW_STATUS_S_FOCUSED 0x10
|
|
||||||
+
|
|
||||||
+#define OV5640_FW_CMD_TRIGGER_FOCUS 0x03
|
|
||||||
+#define OV5640_FW_CMD_CONTINUOUS_FOCUS 0x04
|
|
||||||
+#define OV5640_FW_CMD_GET_FOCUS_RESULT 0x07
|
|
||||||
+#define OV5640_FW_CMD_RELEASE_FOCUS 0x08
|
|
||||||
+#define OV5640_FW_CMD_ZONE_CONFIG 0x12
|
|
||||||
+#define OV5640_FW_CMD_DEFAULT_ZONES 0x80
|
|
||||||
|
|
||||||
enum ov5640_mode_id {
|
|
||||||
OV5640_MODE_QQVGA_160_120 = 0,
|
|
||||||
@@ -222,6 +250,12 @@ struct ov5640_ctrls {
|
|
||||||
struct v4l2_ctrl *auto_gain;
|
|
||||||
struct v4l2_ctrl *gain;
|
|
||||||
};
|
|
||||||
+ struct {
|
|
||||||
+ struct v4l2_ctrl *focus_auto;
|
|
||||||
+ struct v4l2_ctrl *af_start;
|
|
||||||
+ struct v4l2_ctrl *af_stop;
|
|
||||||
+ struct v4l2_ctrl *af_status;
|
|
||||||
+ };
|
|
||||||
struct v4l2_ctrl *brightness;
|
|
||||||
struct v4l2_ctrl *light_freq;
|
|
||||||
struct v4l2_ctrl *saturation;
|
|
||||||
@@ -265,6 +299,8 @@ struct ov5640_dev {
|
|
||||||
|
|
||||||
bool pending_mode_change;
|
|
||||||
bool streaming;
|
|
||||||
+
|
|
||||||
+ bool af_initialized;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
|
|
||||||
@@ -1929,6 +1965,118 @@ static void ov5640_reset(struct ov5640_dev *sensor)
|
|
||||||
usleep_range(20000, 25000);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor,
|
|
||||||
+ const struct firmware *fw)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = sensor->i2c_client;
|
|
||||||
+ const u8 *data = (const u8 *)fw->data;
|
|
||||||
+ u8 fw_status;
|
|
||||||
+ int i;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ // Putting MCU in reset state
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ // Write firmware
|
|
||||||
+ for (i = 0; i < fw->size / sizeof(u8); i++)
|
|
||||||
+ ov5640_write_reg(sensor,
|
|
||||||
+ OV5640_REG_FIRMWARE_BASE + i,
|
|
||||||
+ data[i]);
|
|
||||||
+
|
|
||||||
+ // Reset MCU state
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA0, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA1, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA2, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA3, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA4, 0x00);
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_STATUS, 0x7f);
|
|
||||||
+
|
|
||||||
+ // Start AF MCU
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ dev_info(&client->dev, "firmware upload success\n");
|
|
||||||
+
|
|
||||||
+ // Wait for firmware to be ready
|
|
||||||
+ for (i = 0; i < 5; i++) {
|
|
||||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
|
|
||||||
+ if (fw_status == OV5640_FW_STATUS_S_IDLE) {
|
|
||||||
+ dev_info(&client->dev, "fw started after %d ms\n", i * 50);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+ msleep(50);
|
|
||||||
+ }
|
|
||||||
+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x, retrying...\n", fw_status);
|
|
||||||
+
|
|
||||||
+ // Putting MCU in reset state
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ // Start AF MCU
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ // Wait for firmware to be ready
|
|
||||||
+ for (i = 0; i < 5; i++) {
|
|
||||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
|
|
||||||
+ if (fw_status == OV5640_FW_STATUS_S_IDLE) {
|
|
||||||
+ dev_info(&client->dev, "fw started after %d ms\n", i * 50);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+ msleep(50);
|
|
||||||
+ }
|
|
||||||
+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x\n", fw_status);
|
|
||||||
+ return -ETIMEDOUT;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ov5640_af_init(struct ov5640_dev *sensor)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = sensor->i2c_client;
|
|
||||||
+ const char* fwname = "ov5640_af.bin";
|
|
||||||
+ const struct firmware *fw;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (sensor->af_initialized) {
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (firmware_request_nowarn(&fw, fwname, &client->dev) == 0) {
|
|
||||||
+ ret = ov5640_copy_fw_to_device(sensor, fw);
|
|
||||||
+ if (ret == 0)
|
|
||||||
+ sensor->af_initialized = 1;
|
|
||||||
+ } else {
|
|
||||||
+ dev_warn(&client->dev, "%s: no autofocus firmware available (%s)\n",
|
|
||||||
+ __func__, fwname);
|
|
||||||
+ ret = -1;
|
|
||||||
+ }
|
|
||||||
+ release_firmware(fw);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ // Enable AF systems
|
|
||||||
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE00,
|
|
||||||
+ (BIT(6) | BIT(5)), (BIT(6) | BIT(5)));
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE01,
|
|
||||||
+ BIT(6), BIT(6));
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ // Set lens focus driver on
|
|
||||||
+ ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = sensor->i2c_client;
|
|
||||||
@@ -1950,6 +2098,8 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
|
||||||
goto xclk_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ sensor->af_initialized = 0;
|
|
||||||
+
|
|
||||||
ov5640_reset(sensor);
|
|
||||||
ov5640_power(sensor, true);
|
|
||||||
|
|
||||||
@@ -2467,6 +2617,35 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
|
|
||||||
is_jpeg ? (BIT(5) | BIT(3)) : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int ov5640_fw_command(struct ov5640_dev *sensor, int command)
|
|
||||||
+{
|
|
||||||
+ u8 fw_ack;
|
|
||||||
+ int i;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x01);
|
|
||||||
+ if(ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, command);
|
|
||||||
+ if(ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < 100; i++) {
|
|
||||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_CMD_ACK, &fw_ack);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ if (fw_ack == 0){
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ msleep(50);
|
|
||||||
+ }
|
|
||||||
+ return -ETIMEDOUT;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Sensor Controls.
|
|
||||||
*/
|
|
||||||
@@ -2583,6 +2762,41 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int ov5640_set_ctrl_focus(struct ov5640_dev *sensor, int command)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = sensor->i2c_client;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_af_init(sensor);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(&client->dev, "%s: no autofocus firmware loaded\n",
|
|
||||||
+ __func__);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (command == OV5640_FW_CMD_RELEASE_FOCUS) {
|
|
||||||
+ dev_dbg(&client->dev, "%s: Releasing autofocus\n",
|
|
||||||
+ __func__);
|
|
||||||
+ return ov5640_fw_command(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // Restart zone config
|
|
||||||
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_ZONE_CONFIG);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ // Set default focus zones
|
|
||||||
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_DEFAULT_ZONES);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ dev_dbg(&client->dev, "%s: Triggering autofocus\n",
|
|
||||||
+ __func__);
|
|
||||||
+
|
|
||||||
+ // Start focussing
|
|
||||||
+ return ov5640_fw_command(sensor, command);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
|
|
||||||
{
|
|
||||||
struct ov5640_ctrls *ctrls = &sensor->ctrls;
|
|
||||||
@@ -2689,6 +2903,32 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
|
|
||||||
(BIT(2) | BIT(1)) : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int ov5640_get_af_status(struct ov5640_dev *sensor)
|
|
||||||
+{
|
|
||||||
+ u8 fw_status;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ switch (fw_status) {
|
|
||||||
+ case OV5640_FW_STATUS_S_FIRMWARE:
|
|
||||||
+ case OV5640_FW_STATUS_S_STARTUP:
|
|
||||||
+ return V4L2_AUTO_FOCUS_STATUS_FAILED;
|
|
||||||
+ break;
|
|
||||||
+ case OV5640_FW_STATUS_S_IDLE:
|
|
||||||
+ return V4L2_AUTO_FOCUS_STATUS_IDLE;
|
|
||||||
+ break;
|
|
||||||
+ case OV5640_FW_STATUS_S_FOCUSED:
|
|
||||||
+ return V4L2_AUTO_FOCUS_STATUS_REACHED;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ return V4L2_AUTO_FOCUS_STATUS_BUSY;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
|
||||||
{
|
|
||||||
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
|
|
||||||
@@ -2710,6 +2950,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
|
||||||
return val;
|
|
||||||
sensor->ctrls.exposure->val = val;
|
|
||||||
break;
|
|
||||||
+ case V4L2_CID_FOCUS_AUTO:
|
|
||||||
+ val = ov5640_get_af_status(sensor);
|
|
||||||
+ if (val < 0)
|
|
||||||
+ return val;
|
|
||||||
+ sensor->ctrls.af_status->val = val;
|
|
||||||
+ break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -2741,6 +2987,18 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
||||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
||||||
ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
|
|
||||||
break;
|
|
||||||
+ case V4L2_CID_FOCUS_AUTO:
|
|
||||||
+ if (ctrl->val)
|
|
||||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_CONTINUOUS_FOCUS);
|
|
||||||
+ else
|
|
||||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
|
||||||
+ break;
|
|
||||||
+ case V4L2_CID_AUTO_FOCUS_START:
|
|
||||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_TRIGGER_FOCUS);
|
|
||||||
+ break;
|
|
||||||
+ case V4L2_CID_AUTO_FOCUS_STOP:
|
|
||||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
|
||||||
+ break;
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
|
|
||||||
break;
|
|
||||||
@@ -2813,6 +3071,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
|
|
||||||
ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
|
|
||||||
0, 1023, 1, 0);
|
|
||||||
|
|
||||||
+ /* Autofocus */
|
|
||||||
+ ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_AUTO,
|
|
||||||
+ 0, 1, 1, 0);
|
|
||||||
+ ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_START,
|
|
||||||
+ 0, 1, 1, 0);
|
|
||||||
+ ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_STOP,
|
|
||||||
+ 0, 1, 1, 0);
|
|
||||||
+ ctrls->af_status = v4l2_ctrl_new_std(hdl, ops,
|
|
||||||
+ V4L2_CID_AUTO_FOCUS_STATUS, 0,
|
|
||||||
+ (V4L2_AUTO_FOCUS_STATUS_BUSY |
|
|
||||||
+ V4L2_AUTO_FOCUS_STATUS_REACHED |
|
|
||||||
+ V4L2_AUTO_FOCUS_STATUS_FAILED),
|
|
||||||
+ 0, V4L2_AUTO_FOCUS_STATUS_IDLE);
|
|
||||||
+
|
|
||||||
ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
|
|
||||||
0, 255, 1, 64);
|
|
||||||
ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
|
|
||||||
@@ -2846,6 +3118,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
|
|
||||||
v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
|
|
||||||
v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
|
|
||||||
v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
|
|
||||||
+ v4l2_ctrl_cluster(4, &ctrls->focus_auto);
|
|
||||||
|
|
||||||
sensor->sd.ctrl_handler = hdl;
|
|
||||||
return 0;
|
|
@ -1,23 +0,0 @@
|
|||||||
From: Martijn Braam <martijn@brixit.nl>
|
|
||||||
Date: Wed, 7 Oct 2020 17:33:43 +0200
|
|
||||||
Subject: [PATCH 121/194] media: ov5640: set default ae target lower
|
|
||||||
|
|
||||||
The OV5640 tries to overexpose all photos by about 1 stop. This makes
|
|
||||||
the exposure target one stop lower.
|
|
||||||
---
|
|
||||||
drivers/media/i2c/ov5640.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
|
||||||
index 246563e..f01bf29 100644
|
|
||||||
--- a/drivers/media/i2c/ov5640.c
|
|
||||||
+++ b/drivers/media/i2c/ov5640.c
|
|
||||||
@@ -3355,7 +3355,7 @@ static int ov5640_probe(struct i2c_client *client)
|
|
||||||
&ov5640_mode_data[OV5640_MODE_VGA_640_480];
|
|
||||||
sensor->last_mode = sensor->current_mode;
|
|
||||||
|
|
||||||
- sensor->ae_target = 52;
|
|
||||||
+ sensor->ae_target = 28;
|
|
||||||
|
|
||||||
/* optional indication of physical rotation of sensor */
|
|
||||||
ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
|
|
@ -1,464 +0,0 @@
|
|||||||
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
|
|
||||||
Date: Wed, 8 Sep 2021 13:50:04 +0200
|
|
||||||
Subject: [PATCH 05/36] drm: panel: hx8394: Add driver for HX8394 based
|
|
||||||
HannStar HSD060BHW4 panel
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset="utf-8"
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Signed-off-by: Kamil Trzciński <ayufan@ayufan.eu>
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/panel/Kconfig | 9 +
|
|
||||||
drivers/gpu/drm/panel/Makefile | 1 +
|
|
||||||
drivers/gpu/drm/panel/panel-himax-hx8394.c | 410 +++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 420 insertions(+)
|
|
||||||
create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
|
|
||||||
index cfc8d64..166bd4a 100644
|
|
||||||
--- a/drivers/gpu/drm/panel/Kconfig
|
|
||||||
+++ b/drivers/gpu/drm/panel/Kconfig
|
|
||||||
@@ -129,6 +129,15 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
|
|
||||||
Say Y if you want to enable support for panels based on the
|
|
||||||
Feiyang FY07024DI26A30-D MIPI-DSI interface.
|
|
||||||
|
|
||||||
+config DRM_PANEL_HIMAX_HX8394
|
|
||||||
+ tristate "HIMAX HX8394 MIPI-DSI LCD panel"
|
|
||||||
+ depends on OF
|
|
||||||
+ depends on DRM_MIPI_DSI
|
|
||||||
+ depends on BACKLIGHT_CLASS_DEVICE
|
|
||||||
+ help
|
|
||||||
+ Say Y if you want to enable support for panels based on the
|
|
||||||
+ HIMAX HX8394 MIPI-DSI interface.
|
|
||||||
+
|
|
||||||
config DRM_PANEL_ILITEK_IL9322
|
|
||||||
tristate "Ilitek ILI9322 320x240 QVGA panels"
|
|
||||||
depends on OF && SPI
|
|
||||||
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
|
|
||||||
index bca4cc1..486926c 100644
|
|
||||||
--- a/drivers/gpu/drm/panel/Makefile
|
|
||||||
+++ b/drivers/gpu/drm/panel/Makefile
|
|
||||||
@@ -67,3 +67,4 @@ obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
|
|
||||||
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
|
|
||||||
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
|
|
||||||
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o
|
|
||||||
+obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
|
|
||||||
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000..14659cb
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
@@ -0,0 +1,410 @@
|
|
||||||
+// SPDX-License-Identifier: GPL-2.0
|
|
||||||
+/*
|
|
||||||
+ * Driver for panels based on Himax HX8394 controller, souch as:
|
|
||||||
+ *
|
|
||||||
+ * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) Kamil Trzciński
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/debugfs.h>
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/gpio/consumer.h>
|
|
||||||
+#include <linux/media-bus-format.h>
|
|
||||||
+#include <linux/mod_devicetable.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/of_device.h>
|
|
||||||
+#include <linux/regulator/consumer.h>
|
|
||||||
+
|
|
||||||
+#include <video/display_timing.h>
|
|
||||||
+#include <video/mipi_display.h>
|
|
||||||
+
|
|
||||||
+#include <drm/drm_mipi_dsi.h>
|
|
||||||
+#include <drm/drm_modes.h>
|
|
||||||
+#include <drm/drm_panel.h>
|
|
||||||
+
|
|
||||||
+#define DRV_NAME "panel-himax-hx8394"
|
|
||||||
+
|
|
||||||
+struct hx8394 {
|
|
||||||
+ struct device *dev;
|
|
||||||
+ struct drm_panel panel;
|
|
||||||
+ struct gpio_desc *reset_gpio;
|
|
||||||
+ struct regulator *vcc;
|
|
||||||
+ struct regulator *iovcc;
|
|
||||||
+ bool prepared;
|
|
||||||
+
|
|
||||||
+ struct dentry *debugfs;
|
|
||||||
+ const struct hx8394_panel_desc *desc;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct hx8394_panel_desc {
|
|
||||||
+ const struct drm_display_mode *mode;
|
|
||||||
+ unsigned int lanes;
|
|
||||||
+ unsigned long mode_flags;
|
|
||||||
+ enum mipi_dsi_pixel_format format;
|
|
||||||
+ int (*init_sequence)(struct hx8394 *ctx);
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
|
|
||||||
+{
|
|
||||||
+ return container_of(panel, struct hx8394, panel);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#define dsi_generic_write_seq(dsi, seq...) do { \
|
|
||||||
+ static const u8 d[] = { seq }; \
|
|
||||||
+ int ret; \
|
|
||||||
+ ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
|
|
||||||
+ if (ret < 0) \
|
|
||||||
+ return ret; \
|
|
||||||
+ } while (0)
|
|
||||||
+
|
|
||||||
+#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
|
|
||||||
+ static const u8 d[] = { seq }; \
|
|
||||||
+ int ret; \
|
|
||||||
+ ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
|
|
||||||
+ if (ret < 0) \
|
|
||||||
+ return ret; \
|
|
||||||
+ } while (0)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
|
|
||||||
+{
|
|
||||||
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
+
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb9, 0xff, 0x83, 0x94);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb1, 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x78, 0x0c, 0x07);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb4, 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, 0x7c);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, 0x00, 0x0c, 0x40);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xcc, 0x0b);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb6, 0x7d, 0x7d);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xd4, 0x02);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xbd, 0x01);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xb1, 0x00);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xbd, 0x00);
|
|
||||||
+ dsi_dcs_write_seq(dsi, 0xc6, 0xed);
|
|
||||||
+
|
|
||||||
+ // msleep(0xfa);
|
|
||||||
+ // dsi_dcs_write_seq(dsi, 0x11);
|
|
||||||
+ // msleep(0x32);
|
|
||||||
+ // dsi_dcs_write_seq(dsi, 0x29);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct drm_display_mode hsd060bhw4_mode = {
|
|
||||||
+ .hdisplay = 720,
|
|
||||||
+ .hsync_start = 720 + 40,
|
|
||||||
+ .hsync_end = 720 + 40 + 40,
|
|
||||||
+ .htotal = 720 + 40 + 40 + 40,
|
|
||||||
+ .vdisplay = 1440,
|
|
||||||
+ .vsync_start = 1440 + 18,
|
|
||||||
+ .vsync_end = 1440 + 18 + 10,
|
|
||||||
+ .vtotal = 1440 + 18 + 10 + 17,
|
|
||||||
+ .clock = 69000,
|
|
||||||
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
|
||||||
+ .width_mm = 68,
|
|
||||||
+ .height_mm = 136,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static const struct drm_display_mode hsd060bhw4_mode2 = {
|
|
||||||
+ .hdisplay = 720,
|
|
||||||
+ .hsync_start = 720 + 50,
|
|
||||||
+ .hsync_end = 720 + 50 + 10,
|
|
||||||
+ .htotal = 720 + 50 + 10 + 50,
|
|
||||||
+ .vdisplay = 1440,
|
|
||||||
+ .vsync_start = 1440 + 17,
|
|
||||||
+ .vsync_end = 1440 + 17 + 4,
|
|
||||||
+ .vtotal = 1440 + 17 + 4 + 10,
|
|
||||||
+ .clock = 60000,
|
|
||||||
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
|
||||||
+ .width_mm = 68,
|
|
||||||
+ .height_mm = 136,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static const struct hx8394_panel_desc hsd060bhw4_desc = {
|
|
||||||
+ .mode = &hsd060bhw4_mode,
|
|
||||||
+ .lanes = 4,
|
|
||||||
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,// | MIPI_DSI_MODE_LPM,//, // 0x843
|
|
||||||
+ .format = MIPI_DSI_FMT_RGB888,
|
|
||||||
+ .init_sequence = hsd060bhw4_init_sequence,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int hx8394_enable(struct drm_panel *panel)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = ctx->desc->init_sequence(ctx);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ msleep(20);
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Panel is operational 120 msec after reset */
|
|
||||||
+ msleep(60);
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_dcs_set_display_on(dsi);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ dev_dbg(ctx->dev, "Panel init sequence done\n");
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_disable(struct drm_panel *panel)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_dcs_set_display_off(dsi);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_unprepare(struct drm_panel *panel)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+
|
|
||||||
+ if (!ctx->prepared)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
+ regulator_disable(ctx->iovcc);
|
|
||||||
+ regulator_disable(ctx->vcc);
|
|
||||||
+ ctx->prepared = false;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_prepare(struct drm_panel *panel)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (ctx->prepared)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ dev_dbg(ctx->dev, "Resetting the panel\n");
|
|
||||||
+ ret = regulator_enable(ctx->vcc);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+ ret = regulator_enable(ctx->iovcc);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
|
|
||||||
+ goto disable_vcc;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
+ mdelay(0x32);
|
|
||||||
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
|
||||||
+ msleep(0x64);
|
|
||||||
+
|
|
||||||
+ ctx->prepared = true;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+disable_vcc:
|
|
||||||
+ regulator_disable(ctx->vcc);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_get_modes(struct drm_panel *panel,
|
|
||||||
+ struct drm_connector *connector)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ struct drm_display_mode *mode;
|
|
||||||
+
|
|
||||||
+ mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
|
|
||||||
+ if (!mode) {
|
|
||||||
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
|
|
||||||
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
|
|
||||||
+ drm_mode_vrefresh(ctx->desc->mode));
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ drm_mode_set_name(mode);
|
|
||||||
+
|
|
||||||
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
|
||||||
+ connector->display_info.width_mm = mode->width_mm;
|
|
||||||
+ connector->display_info.height_mm = mode->height_mm;
|
|
||||||
+ drm_mode_probed_add(connector, mode);
|
|
||||||
+
|
|
||||||
+ return 1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct drm_panel_funcs hx8394_drm_funcs = {
|
|
||||||
+ .disable = hx8394_disable,
|
|
||||||
+ .unprepare = hx8394_unprepare,
|
|
||||||
+ .prepare = hx8394_prepare,
|
|
||||||
+ .enable = hx8394_enable,
|
|
||||||
+ .get_modes = hx8394_get_modes,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int allpixelson_set(void *data, u64 val)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = data;
|
|
||||||
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
+
|
|
||||||
+ dev_dbg(ctx->dev, "Setting all pixels on\n");
|
|
||||||
+ dsi_generic_write_seq(dsi, 0x23);
|
|
||||||
+ msleep(val * 1000);
|
|
||||||
+ /* Reset the panel to get video back */
|
|
||||||
+ drm_panel_disable(&ctx->panel);
|
|
||||||
+ drm_panel_unprepare(&ctx->panel);
|
|
||||||
+ drm_panel_prepare(&ctx->panel);
|
|
||||||
+ drm_panel_enable(&ctx->panel);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
|
|
||||||
+ allpixelson_set, "%llu\n");
|
|
||||||
+
|
|
||||||
+static void hx8394_debugfs_init(struct hx8394 *ctx)
|
|
||||||
+{
|
|
||||||
+ ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
|
|
||||||
+
|
|
||||||
+ debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
|
|
||||||
+ &allpixelson_fops);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void hx8394_debugfs_remove(struct hx8394 *ctx)
|
|
||||||
+{
|
|
||||||
+ debugfs_remove_recursive(ctx->debugfs);
|
|
||||||
+ ctx->debugfs = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_probe(struct mipi_dsi_device *dsi)
|
|
||||||
+{
|
|
||||||
+ struct device *dev = &dsi->dev;
|
|
||||||
+ struct hx8394 *ctx;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
|
||||||
+ if (!ctx)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
|
||||||
+ if (IS_ERR(ctx->reset_gpio))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
|
|
||||||
+
|
|
||||||
+ mipi_dsi_set_drvdata(dsi, ctx);
|
|
||||||
+
|
|
||||||
+ ctx->dev = dev;
|
|
||||||
+ ctx->desc = of_device_get_match_data(dev);
|
|
||||||
+
|
|
||||||
+ dsi->mode_flags = ctx->desc->mode_flags;
|
|
||||||
+ dsi->format = ctx->desc->format;
|
|
||||||
+ dsi->lanes = ctx->desc->lanes;
|
|
||||||
+
|
|
||||||
+ ctx->vcc = devm_regulator_get(dev, "vcc");
|
|
||||||
+ if (IS_ERR(ctx->vcc))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
|
|
||||||
+
|
|
||||||
+ ctx->iovcc = devm_regulator_get(dev, "iovcc");
|
|
||||||
+ if (IS_ERR(ctx->iovcc))
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
|
|
||||||
+ "Failed to request iovcc regulator\n");
|
|
||||||
+
|
|
||||||
+ drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
|
|
||||||
+ DRM_MODE_CONNECTOR_DSI);
|
|
||||||
+
|
|
||||||
+ ret = drm_panel_of_backlight(&ctx->panel);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ drm_panel_add(&ctx->panel);
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_attach(dsi);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
|
|
||||||
+ drm_panel_remove(&ctx->panel);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
|
|
||||||
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
|
|
||||||
+ drm_mode_vrefresh(ctx->desc->mode),
|
|
||||||
+ mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
|
|
||||||
+
|
|
||||||
+ hx8394_debugfs_init(ctx);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void hx8394_shutdown(struct mipi_dsi_device *dsi)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = drm_panel_unprepare(&ctx->panel);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ ret = drm_panel_disable(&ctx->panel);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hx8394_remove(struct mipi_dsi_device *dsi)
|
|
||||||
+{
|
|
||||||
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ hx8394_shutdown(dsi);
|
|
||||||
+
|
|
||||||
+ ret = mipi_dsi_detach(dsi);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ drm_panel_remove(&ctx->panel);
|
|
||||||
+
|
|
||||||
+ hx8394_debugfs_remove(ctx);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct of_device_id hx8394_of_match[] = {
|
|
||||||
+ { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
|
|
||||||
+ { /* sentinel */ }
|
|
||||||
+};
|
|
||||||
+MODULE_DEVICE_TABLE(of, hx8394_of_match);
|
|
||||||
+
|
|
||||||
+static struct mipi_dsi_driver hx8394_driver = {
|
|
||||||
+ .probe = hx8394_probe,
|
|
||||||
+ .remove = hx8394_remove,
|
|
||||||
+ .shutdown = hx8394_shutdown,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = DRV_NAME,
|
|
||||||
+ .of_match_table = hx8394_of_match,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+module_mipi_dsi_driver(hx8394_driver);
|
|
||||||
+
|
|
||||||
+MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
|
|
||||||
+MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
|
|
||||||
+MODULE_LICENSE("GPL v2");
|
|
@ -1,226 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 17 Oct 2021 18:03:05 +0200
|
|
||||||
Subject: [PATCH 06/36] drm: panel: hx8394: Improve the panel driver (make it
|
|
||||||
work with DSI fixes)
|
|
||||||
|
|
||||||
Powerup/down should be done in prepare/unprepare. Enable/disable is just
|
|
||||||
for initialization. Fix timings and reset order according to datasheet.
|
|
||||||
|
|
||||||
Reset panel on probe.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/panel/panel-himax-hx8394.c | 84 ++++++++++++++++++------------
|
|
||||||
1 file changed, 52 insertions(+), 32 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
index 14659cb..2f69b94 100644
|
|
||||||
--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
@@ -89,11 +89,6 @@ static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
|
|
||||||
dsi_dcs_write_seq(dsi, 0xbd, 0x00);
|
|
||||||
dsi_dcs_write_seq(dsi, 0xc6, 0xed);
|
|
||||||
|
|
||||||
- // msleep(0xfa);
|
|
||||||
- // dsi_dcs_write_seq(dsi, 0x11);
|
|
||||||
- // msleep(0x32);
|
|
||||||
- // dsi_dcs_write_seq(dsi, 0x29);
|
|
||||||
-
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -141,30 +136,38 @@ static int hx8394_enable(struct drm_panel *panel)
|
|
||||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
+ dev_info(ctx->dev, "enable\n");
|
|
||||||
+
|
|
||||||
ret = ctx->desc->init_sequence(ctx);
|
|
||||||
- if (ret < 0) {
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
- msleep(20);
|
|
||||||
-
|
|
||||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
|
||||||
- if (ret < 0) {
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Panel is operational 120 msec after reset */
|
|
||||||
- msleep(60);
|
|
||||||
+ msleep(120);
|
|
||||||
|
|
||||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
|
||||||
- if (ret)
|
|
||||||
- return ret;
|
|
||||||
-
|
|
||||||
- dev_dbg(ctx->dev, "Panel init sequence done\n");
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret);
|
|
||||||
+ goto sleep_in;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
+
|
|
||||||
+sleep_in:
|
|
||||||
+ /* This will probably fail, but let's try orderly power off anyway. */
|
|
||||||
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
|
||||||
+ if (!ret)
|
|
||||||
+ msleep(50);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hx8394_disable(struct drm_panel *panel)
|
|
||||||
@@ -173,13 +176,15 @@ static int hx8394_disable(struct drm_panel *panel)
|
|
||||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- ret = mipi_dsi_dcs_set_display_off(dsi);
|
|
||||||
- if (ret < 0)
|
|
||||||
- dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
|
|
||||||
+ dev_info(ctx->dev, "disable\n");
|
|
||||||
|
|
||||||
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
|
||||||
- if (ret < 0)
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ msleep(50); /* about 3 frames */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -187,13 +192,19 @@ static int hx8394_disable(struct drm_panel *panel)
|
|
||||||
static int hx8394_unprepare(struct drm_panel *panel)
|
|
||||||
{
|
|
||||||
struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ //struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
+ //int ret;
|
|
||||||
|
|
||||||
if (!ctx->prepared)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
+ dev_info(ctx->dev, "unprepare\n");
|
|
||||||
+
|
|
||||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
+
|
|
||||||
regulator_disable(ctx->iovcc);
|
|
||||||
regulator_disable(ctx->vcc);
|
|
||||||
+
|
|
||||||
ctx->prepared = false;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -202,33 +213,38 @@ static int hx8394_unprepare(struct drm_panel *panel)
|
|
||||||
static int hx8394_prepare(struct drm_panel *panel)
|
|
||||||
{
|
|
||||||
struct hx8394 *ctx = panel_to_hx8394(panel);
|
|
||||||
+ //struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (ctx->prepared)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
- dev_dbg(ctx->dev, "Resetting the panel\n");
|
|
||||||
+ dev_info(ctx->dev, "prepare\n");
|
|
||||||
+
|
|
||||||
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
+
|
|
||||||
ret = regulator_enable(ctx->vcc);
|
|
||||||
- if (ret < 0) {
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
ret = regulator_enable(ctx->iovcc);
|
|
||||||
- if (ret < 0) {
|
|
||||||
+ if (ret) {
|
|
||||||
dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
|
|
||||||
goto disable_vcc;
|
|
||||||
}
|
|
||||||
|
|
||||||
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
- mdelay(0x32);
|
|
||||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
|
||||||
- msleep(0x64);
|
|
||||||
+
|
|
||||||
+ msleep(180);
|
|
||||||
|
|
||||||
ctx->prepared = true;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
disable_vcc:
|
|
||||||
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
|
||||||
regulator_disable(ctx->vcc);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -273,9 +289,11 @@ static int allpixelson_set(void *data, u64 val)
|
|
||||||
dev_dbg(ctx->dev, "Setting all pixels on\n");
|
|
||||||
dsi_generic_write_seq(dsi, 0x23);
|
|
||||||
msleep(val * 1000);
|
|
||||||
+
|
|
||||||
/* Reset the panel to get video back */
|
|
||||||
drm_panel_disable(&ctx->panel);
|
|
||||||
drm_panel_unprepare(&ctx->panel);
|
|
||||||
+
|
|
||||||
drm_panel_prepare(&ctx->panel);
|
|
||||||
drm_panel_enable(&ctx->panel);
|
|
||||||
|
|
||||||
@@ -309,9 +327,10 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
|
|
||||||
if (!ctx)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
|
||||||
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
|
||||||
if (IS_ERR(ctx->reset_gpio))
|
|
||||||
- return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
|
||||||
+ "Failed to get reset gpio\n");
|
|
||||||
|
|
||||||
mipi_dsi_set_drvdata(dsi, ctx);
|
|
||||||
|
|
||||||
@@ -324,7 +343,8 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
|
|
||||||
|
|
||||||
ctx->vcc = devm_regulator_get(dev, "vcc");
|
|
||||||
if (IS_ERR(ctx->vcc))
|
|
||||||
- return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
|
|
||||||
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc),
|
|
||||||
+ "Failed to request vcc regulator\n");
|
|
||||||
|
|
||||||
ctx->iovcc = devm_regulator_get(dev, "iovcc");
|
|
||||||
if (IS_ERR(ctx->iovcc))
|
|
||||||
@@ -342,7 +362,7 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
|
|
||||||
|
|
||||||
ret = mipi_dsi_attach(dsi);
|
|
||||||
if (ret < 0) {
|
|
||||||
- dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
|
|
||||||
+ dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
|
|
||||||
drm_panel_remove(&ctx->panel);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -361,13 +381,13 @@ static void hx8394_shutdown(struct mipi_dsi_device *dsi)
|
|
||||||
struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- ret = drm_panel_unprepare(&ctx->panel);
|
|
||||||
- if (ret < 0)
|
|
||||||
- dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
|
|
||||||
-
|
|
||||||
ret = drm_panel_disable(&ctx->panel);
|
|
||||||
if (ret < 0)
|
|
||||||
dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ ret = drm_panel_unprepare(&ctx->panel);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hx8394_remove(struct mipi_dsi_device *dsi)
|
|
@ -1,29 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 16 Nov 2021 21:19:42 +0100
|
|
||||||
Subject: [PATCH 08/36] drm: panel: hx8394: Fix mode clock for the pinephone
|
|
||||||
pro panel
|
|
||||||
|
|
||||||
The actual rate that was set by CRU was 66.333 MHz The panel does
|
|
||||||
not actually work at 69 MHz, now that CRU can generate the requested
|
|
||||||
clock rate precisely.
|
|
||||||
|
|
||||||
Change the clock rate.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/gpu/drm/panel/panel-himax-hx8394.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
index 2f69b94..7a2f74a 100644
|
|
||||||
--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
|
|
||||||
@@ -101,7 +101,7 @@ static const struct drm_display_mode hsd060bhw4_mode = {
|
|
||||||
.vsync_start = 1440 + 18,
|
|
||||||
.vsync_end = 1440 + 18 + 10,
|
|
||||||
.vtotal = 1440 + 18 + 10 + 17,
|
|
||||||
- .clock = 69000,
|
|
||||||
+ .clock = 66000, /*XXX: only 66MHz works */
|
|
||||||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
|
||||||
.width_mm = 68,
|
|
||||||
.height_mm = 136,
|
|
@ -1,97 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 25 Apr 2021 03:16:42 +0200
|
|
||||||
Subject: input: goodix: Add option to power off the controller during suspend
|
|
||||||
|
|
||||||
For whatever reason the controller is not suspended on Pinephone
|
|
||||||
by the default procedure. It consumes quite a bit of power (~40mW)
|
|
||||||
during system sleep, and more when the screen is touched.
|
|
||||||
|
|
||||||
Let's power off the controller during system sleep instead.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/input/touchscreen/goodix.c | 37 +++++++++++++++++++++++++++++++++++++
|
|
||||||
drivers/input/touchscreen/goodix.h | 1 +
|
|
||||||
2 files changed, 38 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
|
|
||||||
index b5cc917..90a3584 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.c
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.c
|
|
||||||
@@ -1133,6 +1133,7 @@ static void goodix_disable_regulators(void *arg)
|
|
||||||
static int goodix_ts_probe(struct i2c_client *client,
|
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
|
||||||
+ struct device_node *np = client->dev.of_node;
|
|
||||||
struct goodix_ts_data *ts;
|
|
||||||
const char *cfg_name;
|
|
||||||
int error;
|
|
||||||
@@ -1152,6 +1153,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
|
||||||
i2c_set_clientdata(client, ts);
|
|
||||||
init_completion(&ts->firmware_loading_complete);
|
|
||||||
ts->contact_size = GOODIX_CONTACT_SIZE;
|
|
||||||
+ ts->poweroff_in_suspend = of_property_read_bool(np, "poweroff-in-suspend");
|
|
||||||
|
|
||||||
error = goodix_get_gpio_config(ts);
|
|
||||||
if (error)
|
|
||||||
@@ -1261,6 +1263,15 @@ static int __maybe_unused goodix_suspend(struct device *dev)
|
|
||||||
if (ts->load_cfg_from_disk)
|
|
||||||
wait_for_completion(&ts->firmware_loading_complete);
|
|
||||||
|
|
||||||
+ if (ts->poweroff_in_suspend) {
|
|
||||||
+ goodix_free_irq(ts);
|
|
||||||
+ goodix_irq_direction_output(ts, 0);
|
|
||||||
+ gpiod_direction_output(ts->gpiod_rst, 0);
|
|
||||||
+ regulator_disable(ts->avdd28);
|
|
||||||
+ regulator_disable(ts->vddio);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* We need gpio pins to suspend/resume */
|
|
||||||
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
|
|
||||||
disable_irq(client->irq);
|
|
||||||
@@ -1306,6 +1317,32 @@ static int __maybe_unused goodix_resume(struct device *dev)
|
|
||||||
u8 config_ver;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+ if (ts->poweroff_in_suspend) {
|
|
||||||
+ error = regulator_enable(ts->avdd28);
|
|
||||||
+ if (error) {
|
|
||||||
+ dev_err(dev, "Regulator avdd28 enable failed.\n");
|
|
||||||
+ return error;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ error = regulator_enable(ts->vddio);
|
|
||||||
+ if (error) {
|
|
||||||
+ dev_err(dev, "Regulator vddio enable failed.\n");
|
|
||||||
+ return error;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ error = goodix_reset(ts);
|
|
||||||
+ if (error) {
|
|
||||||
+ dev_err(dev, "Controller reset failed.\n");
|
|
||||||
+ return error;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ error = goodix_request_irq(ts);
|
|
||||||
+ if (error)
|
|
||||||
+ return error;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
|
|
||||||
enable_irq(client->irq);
|
|
||||||
return 0;
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
|
|
||||||
index 62138f9..3bb51ea 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.h
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.h
|
|
||||||
@@ -101,6 +101,7 @@ struct goodix_ts_data {
|
|
||||||
u8 main_clk[GOODIX_MAIN_CLK_LEN];
|
|
||||||
int bak_ref_len;
|
|
||||||
u8 *bak_ref;
|
|
||||||
+ bool poweroff_in_suspend;
|
|
||||||
};
|
|
||||||
|
|
||||||
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
|
|
@ -1,49 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sat, 1 May 2021 01:28:07 +0200
|
|
||||||
Subject: input: goodix: Don't disable regulators during suspend
|
|
||||||
|
|
||||||
It does no harm to disable them, but on Pinephone we have other
|
|
||||||
peripherals attached to the same power supplies, whose drivers
|
|
||||||
will not reference the regulator, so powering down the regulators
|
|
||||||
from Goodix driver will break those other devices.
|
|
||||||
|
|
||||||
Until those drivers gain the regulator support, don't disable
|
|
||||||
the regulators in Goodix driver.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/input/touchscreen/goodix.c | 14 --------------
|
|
||||||
1 file changed, 14 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
|
|
||||||
index 90a3584..5f78dc1 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.c
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.c
|
|
||||||
@@ -1267,8 +1267,6 @@ static int __maybe_unused goodix_suspend(struct device *dev)
|
|
||||||
goodix_free_irq(ts);
|
|
||||||
goodix_irq_direction_output(ts, 0);
|
|
||||||
gpiod_direction_output(ts->gpiod_rst, 0);
|
|
||||||
- regulator_disable(ts->avdd28);
|
|
||||||
- regulator_disable(ts->vddio);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1318,18 +1316,6 @@ static int __maybe_unused goodix_resume(struct device *dev)
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (ts->poweroff_in_suspend) {
|
|
||||||
- error = regulator_enable(ts->avdd28);
|
|
||||||
- if (error) {
|
|
||||||
- dev_err(dev, "Regulator avdd28 enable failed.\n");
|
|
||||||
- return error;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- error = regulator_enable(ts->vddio);
|
|
||||||
- if (error) {
|
|
||||||
- dev_err(dev, "Regulator vddio enable failed.\n");
|
|
||||||
- return error;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
error = goodix_reset(ts);
|
|
||||||
if (error) {
|
|
||||||
dev_err(dev, "Controller reset failed.\n");
|
|
@ -1,53 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 18 Oct 2021 03:56:14 +0200
|
|
||||||
Subject: [PATCH 17/36] input: touchscreen: goodix: Respect IRQ flags from DT
|
|
||||||
when asked to
|
|
||||||
|
|
||||||
Sometimes the IRQ flags determined from toucschreen config don't
|
|
||||||
work well.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/input/touchscreen/goodix.c | 7 ++++++-
|
|
||||||
drivers/input/touchscreen/goodix.h | 1 +
|
|
||||||
2 files changed, 7 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
|
|
||||||
index 5f78dc1..91836019 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.c
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.c
|
|
||||||
@@ -400,9 +400,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts)
|
|
||||||
|
|
||||||
static int goodix_request_irq(struct goodix_ts_data *ts)
|
|
||||||
{
|
|
||||||
+ unsigned long irq_flags = ts->irq_flags;
|
|
||||||
+ if (ts->use_dt_irqflags)
|
|
||||||
+ irq_flags = IRQF_ONESHOT;
|
|
||||||
+
|
|
||||||
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
|
|
||||||
NULL, goodix_ts_irq_handler,
|
|
||||||
- ts->irq_flags, ts->client->name, ts);
|
|
||||||
+ irq_flags, ts->client->name, ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
|
|
||||||
@@ -1149,6 +1153,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
|
||||||
if (!ts)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
+ ts->use_dt_irqflags = of_property_read_bool(np, "use-dt-irq-flags");
|
|
||||||
ts->client = client;
|
|
||||||
i2c_set_clientdata(client, ts);
|
|
||||||
init_completion(&ts->firmware_loading_complete);
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
|
|
||||||
index 3bb51ea..0e992a8 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.h
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.h
|
|
||||||
@@ -80,6 +80,7 @@ struct goodix_ts_data {
|
|
||||||
const char *firmware_name;
|
|
||||||
struct touchscreen_properties prop;
|
|
||||||
unsigned int max_touch_num;
|
|
||||||
+ bool use_dt_irqflags;
|
|
||||||
unsigned int int_trigger_type;
|
|
||||||
struct regulator *avdd28;
|
|
||||||
struct regulator *vddio;
|
|
@ -1,23 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Thu, 11 Nov 2021 14:28:41 +0100
|
|
||||||
Subject: [PATCH 18/36] input: touchscreen: goodix: Add support for GT1158
|
|
||||||
|
|
||||||
This controller is used by Pinephone Pro.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
drivers/input/touchscreen/goodix.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
|
|
||||||
index 91836019..e2167d8 100644
|
|
||||||
--- a/drivers/input/touchscreen/goodix.c
|
|
||||||
+++ b/drivers/input/touchscreen/goodix.c
|
|
||||||
@@ -94,6 +94,7 @@ static const struct goodix_chip_data gt9x_chip_data = {
|
|
||||||
|
|
||||||
static const struct goodix_chip_id goodix_chip_ids[] = {
|
|
||||||
{ .id = "1151", .data = >1x_chip_data },
|
|
||||||
+ { .id = "1158", .data = >1x_chip_data },
|
|
||||||
{ .id = "5663", .data = >1x_chip_data },
|
|
||||||
{ .id = "5688", .data = >1x_chip_data },
|
|
||||||
{ .id = "917S", .data = >1x_chip_data },
|
|
File diff suppressed because it is too large
Load Diff
@ -1,101 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Wed, 22 Sep 2021 19:30:39 +0200
|
|
||||||
Subject: [PATCH 02/18] arm64: dts: rk3399-pinephone-pro: Fixup DT validation
|
|
||||||
issues
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
rk3399-pinephone-pro.dts:751.4-14: Warning (reg_format): /mipi@ff960000/panel/port:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
|
|
||||||
rk3399-pinephone-pro.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
|
|
||||||
rk3399-pinephone-pro.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
|
|
||||||
rk3399-pinephone-pro.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
|
|
||||||
rk3399-pinephone-pro.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
|
|
||||||
rk3399-pinephone-pro.dts:747.8-756.5: Warning (avoid_default_addr_size): /mipi@ff960000/panel/port: Relying on default #address-cells value
|
|
||||||
rk3399-pinephone-pro.dts:747.8-756.5: Warning (avoid_default_addr_size): /mipi@ff960000/panel/port: Relying on default #size-cells value
|
|
||||||
rk3399-pinephone-pro.dts:747.8-756.5: Warning (graph_port): /mipi@ff960000/panel/port: graph node unit address error, expected "0"
|
|
||||||
rk3399-pinephone-pro.dts:748.4-25: Warning (graph_port): /mipi@ff960000/panel/port:#address-cells: graph node '#address-cells' is -1, must be 1
|
|
||||||
rk3399-pinephone-pro.dts:749.4-22: Warning (graph_port): /mipi@ff960000/panel/port:#size-cells: graph node '#size-cells' is -1, must be 0
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 17 +++++++----------
|
|
||||||
1 file changed, 7 insertions(+), 10 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index b53df0d..de8a1f3 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -626,7 +626,6 @@ fusb0: typec-portc@22 {
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&fusb0_int>;
|
|
||||||
vbus-supply = <&vcc5v0_typec>;
|
|
||||||
- status = "okay";
|
|
||||||
|
|
||||||
connector {
|
|
||||||
compatible = "usb-c-connector";
|
|
||||||
@@ -691,23 +690,25 @@ accelerometer@68 {
|
|
||||||
"0", "0", "1";
|
|
||||||
};
|
|
||||||
|
|
||||||
- lis3mdl: magnetometer@1e {
|
|
||||||
+ lis3mdl: magnetometer@1c {
|
|
||||||
compatible = "st,lis3mdl-magn";
|
|
||||||
reg = <0x1c>;
|
|
||||||
interrupt-parent = <&gpio1>;
|
|
||||||
interrupts = <RK_PA1 IRQ_TYPE_LEVEL_LOW>;
|
|
||||||
vdd-supply = <&vcc3v3_sys>;
|
|
||||||
vddio-supply = <&vcc_1v8>;
|
|
||||||
+ status = "disabled";
|
|
||||||
};
|
|
||||||
|
|
||||||
// not populated currently
|
|
||||||
- ak09911: compass@0c {
|
|
||||||
+ ak09911: compass@c {
|
|
||||||
compatible = "asahi-kasei,ak09911";
|
|
||||||
reg = <0x0c>;
|
|
||||||
interrupt-parent = <&gpio1>;
|
|
||||||
interrupts = <RK_PA1 IRQ_TYPE_LEVEL_LOW>;
|
|
||||||
vdd-supply = <&vcc_3v0>;
|
|
||||||
vid-supply = <&vcc_1v8>;
|
|
||||||
+ status = "disabled";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -726,6 +727,8 @@ &mipi_dsi {
|
|
||||||
|
|
||||||
ports {
|
|
||||||
mipi_out: port@1 {
|
|
||||||
+ #address-cells = <0>;
|
|
||||||
+ #size-cells = <0>;
|
|
||||||
reg = <1>;
|
|
||||||
|
|
||||||
mipi_out_panel: endpoint {
|
|
||||||
@@ -734,7 +737,7 @@ mipi_out_panel: endpoint {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
- panel {
|
|
||||||
+ panel@0 {
|
|
||||||
compatible = "hannstar,hsd060bhw4";
|
|
||||||
reg = <0>;
|
|
||||||
backlight = <&backlight>;
|
|
||||||
@@ -745,11 +748,6 @@ panel {
|
|
||||||
pinctrl-0 = <&display_rst_l>;
|
|
||||||
|
|
||||||
port {
|
|
||||||
- #address-cells = <1>;
|
|
||||||
- #size-cells = <0>;
|
|
||||||
-
|
|
||||||
- reg = <0>;
|
|
||||||
-
|
|
||||||
mipi_in_panel: endpoint {
|
|
||||||
remote-endpoint = <&mipi_out_panel>;
|
|
||||||
};
|
|
||||||
@@ -757,7 +755,6 @@ mipi_in_panel: endpoint {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
-
|
|
||||||
&pmu_io_domains {
|
|
||||||
pmu1830-supply = <&vcc_3v0>;
|
|
||||||
status = "okay";
|
|
@ -1,34 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 11 Oct 2021 17:32:31 +0200
|
|
||||||
Subject: [PATCH 03/18] arm64: dts: rk3399-pinephone-pro: Make charging and
|
|
||||||
peripheral mode work
|
|
||||||
|
|
||||||
Signed-of-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 +++---
|
|
||||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index de8a1f3..eb2d15e 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -511,8 +511,8 @@ otg_switch: OTG_SWITCH {
|
|
||||||
regulator-name = "otg_switch";
|
|
||||||
// TODO: This requires a proper rk818-charger implementation
|
|
||||||
// without this always-on the type-c is not powered on
|
|
||||||
- regulator-always-on;
|
|
||||||
- regulator-boot-on;
|
|
||||||
+ //regulator-always-on;
|
|
||||||
+ //regulator-boot-on;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1013,7 +1013,7 @@ &usbdrd3_0 {
|
|
||||||
};
|
|
||||||
|
|
||||||
&usbdrd_dwc3_0 {
|
|
||||||
- dr_mode = "host";
|
|
||||||
+ dr_mode = "peripheral";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 18 Oct 2021 03:55:15 +0200
|
|
||||||
Subject: [PATCH 04/18] arm64: dts: rk3399-pinephone-pro: Fix goodix
|
|
||||||
toucscreen interrupts
|
|
||||||
|
|
||||||
The interrupt type read from the screen does not work well. It generates
|
|
||||||
constant stream of interrupts.
|
|
||||||
|
|
||||||
Change to rising edge interrupt, and enforce it in the driver via
|
|
||||||
'use-dt-irq-flags'.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 3 ++-
|
|
||||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index eb2d15e..83eb683 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -594,7 +594,8 @@ touchscreen@14 {
|
|
||||||
compatible = "goodix,gt917s";
|
|
||||||
reg = <0x14>;
|
|
||||||
interrupt-parent = <&gpio3>;
|
|
||||||
- interrupts = <RK_PB5 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
+ interrupts = <RK_PB5 IRQ_TYPE_EDGE_RISING>;
|
|
||||||
+ use-dt-irq-flags;
|
|
||||||
irq-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>;
|
|
||||||
reset-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
|
|
||||||
AVDD28-supply = <&vcc3v0_touch>;
|
|
@ -1,26 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 18 Oct 2021 03:57:56 +0200
|
|
||||||
Subject: [PATCH 05/18] arm64: dts: rk3399-pinephone-pro: Correct the pmu1830
|
|
||||||
io-domain supply
|
|
||||||
|
|
||||||
It's connected to vcc_1v8 according to datasheet. Credits to carlos
|
|
||||||
for noticing!
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 83eb683..59733033 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -757,7 +757,7 @@ mipi_in_panel: endpoint {
|
|
||||||
};
|
|
||||||
|
|
||||||
&pmu_io_domains {
|
|
||||||
- pmu1830-supply = <&vcc_3v0>;
|
|
||||||
+ pmu1830-supply = <&vcc_1v8>;
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 18 Oct 2021 03:58:56 +0200
|
|
||||||
Subject: [PATCH 06/18] arm64: dts: rk3399-pinephone-pro: Power off goodix
|
|
||||||
touchscreen in sleep
|
|
||||||
|
|
||||||
Otherwise it consumes 200mW of power when touched during system sleep.
|
|
||||||
It can't wake up the phone anyway.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 59733033..96b5170 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -602,6 +602,7 @@ touchscreen@14 {
|
|
||||||
VDDIO-supply = <&vcc3v0_touch>;
|
|
||||||
touchscreen-size-x = <720>;
|
|
||||||
touchscreen-size-y = <1440>;
|
|
||||||
+ poweroff-in-suspend;
|
|
||||||
};
|
|
||||||
|
|
||||||
light-sensor@48 {
|
|
@ -1,198 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Thu, 21 Oct 2021 20:25:35 +0200
|
|
||||||
Subject: [PATCH 07/18] arm64: dts: rk3399-pinephone-pro: Add support for both
|
|
||||||
cameras
|
|
||||||
|
|
||||||
IMX258 + OV5640.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 146 ++++++++++++++++++++-
|
|
||||||
1 file changed, 142 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 96b5170..3e9aa7b 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -456,8 +456,6 @@ regulator-state-mem {
|
|
||||||
|
|
||||||
vcc1v8_dvp: LDO_REG7 {
|
|
||||||
regulator-name = "vcc1v8_dvp";
|
|
||||||
- regulator-always-on;
|
|
||||||
- regulator-boot-on;
|
|
||||||
regulator-min-microvolt = <1800000>;
|
|
||||||
regulator-max-microvolt = <1800000>;
|
|
||||||
regulator-state-mem {
|
|
||||||
@@ -579,10 +577,92 @@ regulator-state-mem {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Cameras:
|
|
||||||
+ *
|
|
||||||
+ * cif clk out = gpio2 B3 / CIF_CLKOUTA_u
|
|
||||||
+ *
|
|
||||||
+ * both on i2c1 GPIO4_A1 (SDA) / GPIO4_A2 (SCL)
|
|
||||||
+ *
|
|
||||||
+ * both share power:
|
|
||||||
+ * VCC1V8_DVP - LDO7 - supplied by VCC7 (VCC3V3_SYS)
|
|
||||||
+ * DVDD_DVP 1.5V - autoenabled by VCC2V8_DVP depends on VCC1V8_S3 (U118 supplies 1.2V, though, not 1.5V)
|
|
||||||
+ * VCC2V8_DVP af - autoenabled by VCC1V8_DVP depends on VCC3V3_SYS
|
|
||||||
+ * AVDD2V8_DVP - autoenabled by VCC1V8_DVP depends on VCC3V3_SYS
|
|
||||||
+ *
|
|
||||||
+ * mipi0 = imx258
|
|
||||||
+ * reset = gpio1 A0
|
|
||||||
+ * powerdown = GPIO2_B4
|
|
||||||
+ *
|
|
||||||
+ * mipi1 = OV5640
|
|
||||||
+ * powerdown = GPIO2_D4
|
|
||||||
+ *
|
|
||||||
+ * bt656-supply = <&vcc1v8_dvp>;
|
|
||||||
+ */
|
|
||||||
&i2c1 {
|
|
||||||
+ status = "okay";
|
|
||||||
+
|
|
||||||
+ clock-frequency = <400000>;
|
|
||||||
i2c-scl-rising-time-ns = <300>;
|
|
||||||
i2c-scl-falling-time-ns = <15>;
|
|
||||||
- status = "okay";
|
|
||||||
+
|
|
||||||
+ pinctrl-0 = <&i2c1_xfer &cif_clkouta>;
|
|
||||||
+
|
|
||||||
+ assigned-clocks = <&cru SCLK_CIF_OUT &cru SCLK_CIF_OUT_SRC>;
|
|
||||||
+ assigned-clock-parents = <&cru SCLK_CIF_OUT_SRC &cru PLL_GPLL>;
|
|
||||||
+ assigned-clock-rates = <19200000 0>;
|
|
||||||
+
|
|
||||||
+ /* Rear-facing camera */
|
|
||||||
+ wcam: camera@1a {
|
|
||||||
+ compatible = "sony,imx258";
|
|
||||||
+ reg = <0x1a>;
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&wcam_rst &wcam_pdn>;
|
|
||||||
+
|
|
||||||
+ clocks = <&cru SCLK_CIF_OUT>;
|
|
||||||
+ clock-names = "xvclk";
|
|
||||||
+
|
|
||||||
+ vif-supply = <&vcc1v8_dvp>;
|
|
||||||
+ /*XXX: also depends on vcca1v8_codec for I2C bus power */
|
|
||||||
+
|
|
||||||
+ reset-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_LOW>;
|
|
||||||
+ powerdown-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ rotation = <180>;
|
|
||||||
+
|
|
||||||
+ port {
|
|
||||||
+ wcam_out: endpoint {
|
|
||||||
+ remote-endpoint = <&mipi_in_wcam>;
|
|
||||||
+ data-lanes = <1 2 3 4>;
|
|
||||||
+ link-frequencies = /bits/ 64 <320000000>;
|
|
||||||
+ //link-frequencies = /bits/ 64 <633600000>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ /* Front-facing camera */
|
|
||||||
+ ucam: camera@3c {
|
|
||||||
+ compatible = "ovti,ov5640";
|
|
||||||
+ reg = <0x3c>;
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&ucam_pdn>;
|
|
||||||
+
|
|
||||||
+ clocks = <&cru SCLK_CIF_OUT>;
|
|
||||||
+ clock-names = "xclk";
|
|
||||||
+
|
|
||||||
+ DOVDD-supply = <&vcc1v8_dvp>;
|
|
||||||
+ /*XXX: also depends on vcca1v8_codec for I2C bus power */
|
|
||||||
+
|
|
||||||
+ powerdown-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ rotation = <180>;
|
|
||||||
+
|
|
||||||
+ port {
|
|
||||||
+ ucam_out: endpoint {
|
|
||||||
+ remote-endpoint = <&mipi_in_ucam>;
|
|
||||||
+ data-lanes = <1 2>;
|
|
||||||
+ clock-lanes = <0>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
&i2c3 {
|
|
||||||
@@ -723,6 +803,50 @@ &io_domains {
|
|
||||||
gpio1830-supply = <&vcc_3v0>;
|
|
||||||
};
|
|
||||||
|
|
||||||
+&isp0 {
|
|
||||||
+ status = "okay";
|
|
||||||
+
|
|
||||||
+ ports {
|
|
||||||
+ port@0 {
|
|
||||||
+ mipi_in_wcam: endpoint@0 {
|
|
||||||
+ reg = <0>;
|
|
||||||
+ remote-endpoint = <&wcam_out>;
|
|
||||||
+ data-lanes = <1 2 3 4>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&mipi_dphy_rx0 {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&isp1 {
|
|
||||||
+ status = "okay";
|
|
||||||
+
|
|
||||||
+ ports {
|
|
||||||
+ port@0 {
|
|
||||||
+ mipi_in_ucam: endpoint@0 {
|
|
||||||
+ reg = <0>;
|
|
||||||
+ remote-endpoint = <&ucam_out>;
|
|
||||||
+ data-lanes = <1 2>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&isp0_mmu {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&isp1_mmu {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&mipi_dsi1 {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
&mipi_dsi {
|
|
||||||
status = "okay";
|
|
||||||
clock-master;
|
|
||||||
@@ -783,6 +907,20 @@ pwrbtn_pin: pwrbtn-pin {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ camera {
|
|
||||||
+ wcam_rst: wcam-rst {
|
|
||||||
+ rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ wcam_pdn: wcam-pdn {
|
|
||||||
+ rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ ucam_pdn: ucam-pdn {
|
|
||||||
+ rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
fusb302x {
|
|
||||||
fusb0_int: fusb0-int {
|
|
||||||
rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
|
|
||||||
@@ -1033,4 +1171,4 @@ &vopl {
|
|
||||||
|
|
||||||
&vopl_mmu {
|
|
||||||
status = "okay";
|
|
||||||
-};
|
|
||||||
\ No newline at end of file
|
|
||||||
+};
|
|
@ -1,71 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Wed, 20 Oct 2021 22:41:43 +0200
|
|
||||||
Subject: [PATCH 08/18] arm64: dts: rk3399-pinephone-pro: Fix SD card power
|
|
||||||
supply definition
|
|
||||||
|
|
||||||
GPIO0_A1 is used for modem's RI. SD card power supply is not changeable.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 27 ++++------------------
|
|
||||||
1 file changed, 5 insertions(+), 22 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 3e9aa7b..e6aac03 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -215,23 +215,6 @@ vcc1v8_codec: vcc1v8-codec-regulator {
|
|
||||||
vin-supply = <&vcc3v3_sys>;
|
|
||||||
};
|
|
||||||
|
|
||||||
- /* micro SD card power */
|
|
||||||
- vcc3v0_sd: vcc3v0-sd {
|
|
||||||
- compatible = "regulator-fixed";
|
|
||||||
- enable-active-high;
|
|
||||||
- gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
|
|
||||||
- pinctrl-names = "default";
|
|
||||||
- pinctrl-0 = <&sdmmc0_pwr_h>;
|
|
||||||
- regulator-name = "vcc3v0_sd";
|
|
||||||
- regulator-min-microvolt = <3000000>;
|
|
||||||
- regulator-max-microvolt = <3000000>;
|
|
||||||
- vin-supply = <&vcc3v3_sys>;
|
|
||||||
-
|
|
||||||
- regulator-state-mem {
|
|
||||||
- regulator-off-in-suspend;
|
|
||||||
- };
|
|
||||||
- };
|
|
||||||
-
|
|
||||||
/* MIPI DSI panel 1.8v supply */
|
|
||||||
vcc1v8_lcd: vcc1v8-lcd {
|
|
||||||
compatible = "regulator-fixed";
|
|
||||||
@@ -474,8 +457,8 @@ regulator-state-mem {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
- vcc_sd: LDO_REG9 {
|
|
||||||
- regulator-name = "vcc_sd";
|
|
||||||
+ vccio_sd: LDO_REG9 {
|
|
||||||
+ regulator-name = "vccio_sd";
|
|
||||||
regulator-min-microvolt = <1800000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
regulator-state-mem {
|
|
||||||
@@ -799,7 +782,7 @@ &io_domains {
|
|
||||||
|
|
||||||
bt656-supply = <&vcc1v8_dvp>;
|
|
||||||
audio-supply = <&vcca1v8_codec>;
|
|
||||||
- sdmmc-supply = <&vcc_sd>;
|
|
||||||
+ sdmmc-supply = <&vccio_sd>;
|
|
||||||
gpio1830-supply = <&vcc_3v0>;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1034,8 +1017,8 @@ &sdmmc {
|
|
||||||
max-frequency = <150000000>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
|
|
||||||
- vmmc-supply = <&vcc3v0_sd>;
|
|
||||||
- vqmmc-supply = <&vcc_sd>;
|
|
||||||
+ vmmc-supply = <&vcc3v3_sys>;
|
|
||||||
+ vqmmc-supply = <&vccio_sd>;
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 25 Oct 2021 17:49:41 +0200
|
|
||||||
Subject: [PATCH 09/18] arm64: dts: rk3399-pinephone-pro: Correct the battery
|
|
||||||
specification
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset="utf-8"
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
XLS with ZCV measurements from the manufacturer say that at 25°C,
|
|
||||||
ZCV is ~200 mOhm. At 50°C it's at ~100 mOhm. Set some value in between.
|
|
||||||
|
|
||||||
Lower the charging current to something less aggressive.
|
|
||||||
|
|
||||||
Fix the current sensing resitor value (it's 10 mOhm in the schematic).
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 +++---
|
|
||||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index e6aac03..ffdaaa6 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -504,16 +504,16 @@ battery {
|
|
||||||
4110 4161 4217 4308>;
|
|
||||||
design_capacity = <2916>;
|
|
||||||
design_qmax = <2708>;
|
|
||||||
- bat_res = <65>;
|
|
||||||
+ bat_res = <150>;
|
|
||||||
max_input_current = <3000>;
|
|
||||||
- max_chrg_current = <3000>;
|
|
||||||
+ max_chrg_current = <2000>;
|
|
||||||
max_chrg_voltage = <4350>;
|
|
||||||
sleep_enter_current = <300>;
|
|
||||||
sleep_exit_current = <300>;
|
|
||||||
power_off_thresd = <3400>;
|
|
||||||
zero_algorithm_vol = <3950>;
|
|
||||||
fb_temperature = <105>;
|
|
||||||
- sample_res = <20>;
|
|
||||||
+ sample_res = <10>;
|
|
||||||
max_soc_offset = <60>;
|
|
||||||
energy_mode = <0>;
|
|
||||||
monitor_sec = <5>;
|
|
@ -1,32 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 26 Oct 2021 01:29:50 +0200
|
|
||||||
Subject: [PATCH 10/18] arm64: dts: rk3399-pinephone-pro: Cleanup some USB
|
|
||||||
nodes whitespace
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index ffdaaa6..d9159d4 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -1067,7 +1067,7 @@ u2phy0_otg: otg-port {
|
|
||||||
|
|
||||||
u2phy0_host: host-port {
|
|
||||||
status = "okay";
|
|
||||||
- phy-supply = <&vcc5v0_sys>;
|
|
||||||
+ phy-supply = <&vcc5v0_sys>;
|
|
||||||
};
|
|
||||||
|
|
||||||
port {
|
|
||||||
@@ -1086,7 +1086,7 @@ u2phy1_otg: otg-port {
|
|
||||||
|
|
||||||
u2phy1_host: host-port {
|
|
||||||
status = "okay";
|
|
||||||
- phy-supply = <&vcc5v0_sys>;
|
|
||||||
+ phy-supply = <&vcc5v0_sys>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 26 Oct 2021 01:30:14 +0200
|
|
||||||
Subject: [PATCH 11/18] arm64: dts: rk3399-pinephone-pro: Fix PDOs to be more
|
|
||||||
reasonable
|
|
||||||
|
|
||||||
Let's not overtax the battery and provide only 4.5W to external devices.
|
|
||||||
Even that may be too much, given what PPP can consume by itself.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 8 +++-----
|
|
||||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index d9159d4..9493672 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -696,12 +696,10 @@ connector {
|
|
||||||
compatible = "usb-c-connector";
|
|
||||||
data-role = "dual";
|
|
||||||
label = "USB-C";
|
|
||||||
- op-sink-microwatt = <1000000>;
|
|
||||||
+ op-sink-microwatt = <2500000>;
|
|
||||||
power-role = "dual";
|
|
||||||
- sink-pdos =
|
|
||||||
- <PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM)>;
|
|
||||||
- source-pdos =
|
|
||||||
- <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM)>;
|
|
||||||
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
|
||||||
+ source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM)>;
|
|
||||||
try-power-role = "sink";
|
|
||||||
|
|
||||||
extcon-cables = <1 2 5 6 9 10 12 44>;
|
|
@ -1,24 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 2 Nov 2021 13:28:24 +0100
|
|
||||||
Subject: [PATCH 12/18] arm64: dts: rk3399-pinephone-pro: Add chassis-type =
|
|
||||||
"handset" to DT
|
|
||||||
|
|
||||||
This way, desktop environment can pick up device type from DT.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 9493672..3f944af 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -17,6 +17,7 @@
|
|
||||||
/ {
|
|
||||||
model = "Pine64 PinePhonePro";
|
|
||||||
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
|
|
||||||
+ chassis-type = "handset";
|
|
||||||
|
|
||||||
chosen {
|
|
||||||
bootargs = "earlycon=uart8250,mmio32,0xff1a0000";
|
|
@ -1,29 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 2 Nov 2021 13:29:29 +0100
|
|
||||||
Subject: [PATCH 13/18] arm64: dts: rk3399-pinephone-pro: Add mmc aliases to
|
|
||||||
get stable numbering
|
|
||||||
|
|
||||||
It's better to have stable meanings for /dev/mmcblk* device files.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 ++++++
|
|
||||||
1 file changed, 6 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 3f944af..58710a6 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -19,6 +19,12 @@ / {
|
|
||||||
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
|
|
||||||
chassis-type = "handset";
|
|
||||||
|
|
||||||
+ aliases {
|
|
||||||
+ mmc0 = &sdio0;
|
|
||||||
+ mmc1 = &sdmmc;
|
|
||||||
+ mmc2 = &sdhci;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
chosen {
|
|
||||||
bootargs = "earlycon=uart8250,mmio32,0xff1a0000";
|
|
||||||
stdout-path = "serial2:1500000n8";
|
|
@ -1,23 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:30:46 +0100
|
|
||||||
Subject: [PATCH 14/18] arm64: dts: rk3399-pinephone-pro: Use a new
|
|
||||||
rk818-battery compatible
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 58710a6..1b4eb26 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -505,7 +505,7 @@ otg_switch: OTG_SWITCH {
|
|
||||||
};
|
|
||||||
|
|
||||||
battery {
|
|
||||||
- compatible = "rk818-battery";
|
|
||||||
+ compatible = "rockchip,rk818-battery";
|
|
||||||
ocv_table = <3400 3675 3689 3716 3740 3756 3768 3780
|
|
||||||
3793 3807 3827 3853 3896 3937 3974 4007 4066
|
|
||||||
4110 4161 4217 4308>;
|
|
@ -1,294 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Sun, 7 Nov 2021 19:39:20 +0100
|
|
||||||
Subject: [PATCH 15/18] arm64: dts: rk3399-pinephone-pro: Full support for
|
|
||||||
Type-C port
|
|
||||||
|
|
||||||
Connect various devices to a extcon bridge. Fix some incorrectly
|
|
||||||
specified regulators. With this patch, this is now supported:
|
|
||||||
|
|
||||||
- PD charger / current limiting
|
|
||||||
- Alt-DisplayPort mode
|
|
||||||
- OTG - host/peripheral USB
|
|
||||||
- B1.2 detection
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 142 +++++++++++++++------
|
|
||||||
1 file changed, 103 insertions(+), 39 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 1b4eb26..f6eac416 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -12,8 +12,6 @@
|
|
||||||
#include "rk3399.dtsi"
|
|
||||||
#include "rk3399-opp.dtsi"
|
|
||||||
|
|
||||||
-#define WITHOUT_CDN_DP // TODO: everything works, but it is simpler to test mipi
|
|
||||||
-
|
|
||||||
/ {
|
|
||||||
model = "Pine64 PinePhonePro";
|
|
||||||
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
|
|
||||||
@@ -50,6 +48,43 @@ button-down {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ bat: battery {
|
|
||||||
+ compatible = "simple-battery";
|
|
||||||
+ voltage-min-design-microvolt = <3400000>;
|
|
||||||
+ voltage-max-design-microvolt = <4350000>;
|
|
||||||
+ energy-full-design-microwatt-hours = <11400000>;
|
|
||||||
+ charge-full-design-microamp-hours = <3000000>;
|
|
||||||
+ precharge-current-microamp = <120000>;
|
|
||||||
+ charge-term-current-microamp = <150000>;
|
|
||||||
+ constant-charge-current-max-microamp = <1500000>;
|
|
||||||
+ constant-charge-voltage-max-microvolt = <4350000>;
|
|
||||||
+ factory-internal-resistance-micro-ohms = <150000>;
|
|
||||||
+ resistance-temp-table = <20 150>;
|
|
||||||
+ ocv-capacity-celsius = <20>;
|
|
||||||
+ ocv-capacity-table-0 =
|
|
||||||
+ <4308000 100>,
|
|
||||||
+ <4217000 95>,
|
|
||||||
+ <4161000 90>,
|
|
||||||
+ <4110000 85>,
|
|
||||||
+ <4066000 80>,
|
|
||||||
+ <4007000 75>,
|
|
||||||
+ <3974000 70>,
|
|
||||||
+ <3937000 65>,
|
|
||||||
+ <3896000 60>,
|
|
||||||
+ <3853000 55>,
|
|
||||||
+ <3827000 50>,
|
|
||||||
+ <3807000 45>,
|
|
||||||
+ <3793000 40>,
|
|
||||||
+ <3780000 35>,
|
|
||||||
+ <3768000 30>,
|
|
||||||
+ <3756000 25>,
|
|
||||||
+ <3740000 20>,
|
|
||||||
+ <3716000 15>,
|
|
||||||
+ <3689000 10>,
|
|
||||||
+ <3675000 5>,
|
|
||||||
+ <3400000 0>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
cluster1_opp_ppp: opp-table1b {
|
|
||||||
compatible = "operating-points-v2";
|
|
||||||
opp-shared;
|
|
||||||
@@ -168,25 +203,35 @@ vcc5v0_sys: vcc5v0-host-regulator {
|
|
||||||
regulator-max-microvolt = <5000000>;
|
|
||||||
regulator-always-on;
|
|
||||||
regulator-boot-on;
|
|
||||||
- vin-supply = <&vcc_sysin>;
|
|
||||||
+ vin-supply = <&boost_otg>;
|
|
||||||
|
|
||||||
regulator-state-mem {
|
|
||||||
regulator-on-in-suspend;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * This is not a regulator, but GPIO0_A6 is used to disable
|
|
||||||
+ * VCC_SYS -> VBAT+ switch that helps boost that power path's
|
|
||||||
+ * current carrying capacity.
|
|
||||||
+ *
|
|
||||||
+ * GPIO0_A6 high: path is disabled no matter what
|
|
||||||
+ * GPIO0_A6 low: path is enabled if there's 5V voltage on
|
|
||||||
+ * VBUS_TYPEC
|
|
||||||
+ *
|
|
||||||
+ * GPIO0_A6 must be high when the phone is providing VBUS_TYPEC
|
|
||||||
+ * power.
|
|
||||||
+ */
|
|
||||||
vcc5v0_typec: vcc5v0-typec-regulator {
|
|
||||||
compatible = "regulator-fixed";
|
|
||||||
- //enable-active-high;
|
|
||||||
+ enable-active-high;
|
|
||||||
gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&vcc5v0_typec_en>;
|
|
||||||
regulator-min-microvolt = <5000000>;
|
|
||||||
regulator-max-microvolt = <5000000>;
|
|
||||||
regulator-name = "vcc5v0_typec";
|
|
||||||
- vin-supply = <&vcc5v0_sys>;
|
|
||||||
- regulator-always-on;
|
|
||||||
- regulator-boot-on;
|
|
||||||
+ vin-supply = <&boost_otg>;
|
|
||||||
|
|
||||||
regulator-state-mem {
|
|
||||||
regulator-on-in-suspend;
|
|
||||||
@@ -257,6 +302,14 @@ vcca1v8_s3: vcc1v8-s3 {
|
|
||||||
regulator-always-on;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ typec_extcon_bridge: typec-extcon {
|
|
||||||
+ compatible = "linux,typec-extcon-bridge";
|
|
||||||
+ usb-role-switch;
|
|
||||||
+ orientation-switch;
|
|
||||||
+ mode-switch;
|
|
||||||
+ svid = /bits/ 16 <0xff01>;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
&cpu_l0 {
|
|
||||||
@@ -285,12 +338,11 @@ &cpu_b1 {
|
|
||||||
operating-points-v2 = <&cluster1_opp_ppp>;
|
|
||||||
};
|
|
||||||
|
|
||||||
-#ifndef WITHOUT_CDN_DP
|
|
||||||
&cdn_dp {
|
|
||||||
status = "okay";
|
|
||||||
- extcon = <&fusb0>;
|
|
||||||
+ extcon = <&typec_extcon_bridge>;
|
|
||||||
+ phys = <&tcphy0_dp>;
|
|
||||||
};
|
|
||||||
-#endif
|
|
||||||
|
|
||||||
&emmc_phy {
|
|
||||||
status = "okay";
|
|
||||||
@@ -318,7 +370,6 @@ rk818: pmic@1c {
|
|
||||||
pinctrl-0 = <&pmic_int_l>;
|
|
||||||
rockchip,system-power-controller;
|
|
||||||
wakeup-source;
|
|
||||||
- extcon = <&fusb0>;
|
|
||||||
|
|
||||||
vcc1-supply = <&vcc_sysin>;
|
|
||||||
vcc2-supply = <&vcc_sysin>;
|
|
||||||
@@ -328,6 +379,7 @@ rk818: pmic@1c {
|
|
||||||
vcc7-supply = <&vcc3v3_sys>;
|
|
||||||
vcc8-supply = <&vcc_sysin>;
|
|
||||||
vcc9-supply = <&vcc3v3_sys>;
|
|
||||||
+ usb-supply = <&vcc5v0_typec>;
|
|
||||||
|
|
||||||
regulators {
|
|
||||||
vdd_cpu_l: DCDC_REG1 {
|
|
||||||
@@ -497,13 +549,13 @@ regulator-state-mem {
|
|
||||||
|
|
||||||
otg_switch: OTG_SWITCH {
|
|
||||||
regulator-name = "otg_switch";
|
|
||||||
- // TODO: This requires a proper rk818-charger implementation
|
|
||||||
- // without this always-on the type-c is not powered on
|
|
||||||
- //regulator-always-on;
|
|
||||||
- //regulator-boot-on;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * XXX: Backported BSP stuff, drop this. Use standard
|
|
||||||
+ * "monitored-battery" property.
|
|
||||||
+ */
|
|
||||||
battery {
|
|
||||||
compatible = "rockchip,rk818-battery";
|
|
||||||
ocv_table = <3400 3675 3689 3716 3740 3756 3768 3780
|
|
||||||
@@ -528,6 +580,12 @@ battery {
|
|
||||||
power_dc2otg = <0>;
|
|
||||||
otg5v_suspend_enable = <1>;
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ charger {
|
|
||||||
+ compatible = "rockchip,rk818-charger";
|
|
||||||
+ power-supplies = <&fusb0>;
|
|
||||||
+ monitored-battery = <&bat>;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
vdd_cpu_b: regulator@40 {
|
|
||||||
@@ -697,7 +755,9 @@ fusb0: typec-portc@22 {
|
|
||||||
interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&fusb0_int>;
|
|
||||||
- vbus-supply = <&vcc5v0_typec>;
|
|
||||||
+ extcon = <&typec_extcon_bridge>;
|
|
||||||
+ usb-role-switch = <&typec_extcon_bridge>;
|
|
||||||
+ vbus-supply = <&otg_switch>;
|
|
||||||
|
|
||||||
connector {
|
|
||||||
compatible = "usb-c-connector";
|
|
||||||
@@ -705,12 +765,18 @@ connector {
|
|
||||||
label = "USB-C";
|
|
||||||
op-sink-microwatt = <2500000>;
|
|
||||||
power-role = "dual";
|
|
||||||
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
|
||||||
- source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM)>;
|
|
||||||
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
|
|
||||||
+ source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
|
|
||||||
try-power-role = "sink";
|
|
||||||
+ mode-switch = <&typec_extcon_bridge>;
|
|
||||||
+ orientation-switch = <&typec_extcon_bridge>;
|
|
||||||
|
|
||||||
- extcon-cables = <1 2 5 6 9 10 12 44>;
|
|
||||||
- typec-altmodes = <0xff01 1 0x001c0c00 1>;
|
|
||||||
+ altmodes {
|
|
||||||
+ dp {
|
|
||||||
+ svid = <0xff01>;
|
|
||||||
+ vdo = <0x0c0046>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
|
|
||||||
ports {
|
|
||||||
#address-cells = <1>;
|
|
||||||
@@ -1035,7 +1101,7 @@ &sdhci {
|
|
||||||
};
|
|
||||||
|
|
||||||
&tcphy0 {
|
|
||||||
- extcon = <&fusb0>;
|
|
||||||
+ extcon = <&typec_extcon_bridge>;
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1065,15 +1131,7 @@ &tsadc {
|
|
||||||
|
|
||||||
&u2phy0 {
|
|
||||||
status = "okay";
|
|
||||||
-
|
|
||||||
- u2phy0_otg: otg-port {
|
|
||||||
- status = "okay";
|
|
||||||
- };
|
|
||||||
-
|
|
||||||
- u2phy0_host: host-port {
|
|
||||||
- status = "okay";
|
|
||||||
- phy-supply = <&vcc5v0_sys>;
|
|
||||||
- };
|
|
||||||
+ extcon = <&typec_extcon_bridge>;
|
|
||||||
|
|
||||||
port {
|
|
||||||
u2phy0_typec_hs: endpoint {
|
|
||||||
@@ -1082,17 +1140,22 @@ u2phy0_typec_hs: endpoint {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
-&u2phy1 {
|
|
||||||
+&u2phy0_otg {
|
|
||||||
status = "okay";
|
|
||||||
+};
|
|
||||||
|
|
||||||
- u2phy1_otg: otg-port {
|
|
||||||
- status = "okay";
|
|
||||||
- };
|
|
||||||
+&u2phy0_host {
|
|
||||||
+ status = "okay";
|
|
||||||
+ phy-supply = <&vcc5v0_sys>;
|
|
||||||
+};
|
|
||||||
|
|
||||||
- u2phy1_host: host-port {
|
|
||||||
- status = "okay";
|
|
||||||
- phy-supply = <&vcc5v0_sys>;
|
|
||||||
- };
|
|
||||||
+&u2phy1 {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+&u2phy1_host {
|
|
||||||
+ status = "okay";
|
|
||||||
+ phy-supply = <&vcc5v0_sys>;
|
|
||||||
};
|
|
||||||
|
|
||||||
&uart0 {
|
|
||||||
@@ -1141,7 +1204,8 @@ &usbdrd3_0 {
|
|
||||||
};
|
|
||||||
|
|
||||||
&usbdrd_dwc3_0 {
|
|
||||||
- dr_mode = "peripheral";
|
|
||||||
+ dr_mode = "otg";
|
|
||||||
+ extcon = <&typec_extcon_bridge>;
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Mon, 15 Nov 2021 23:52:40 +0100
|
|
||||||
Subject: [PATCH 16/18] arm64: dts: rk3399-pinephone-pro: Use DCLK_VOP*_FRAC
|
|
||||||
to achieve precise rates
|
|
||||||
|
|
||||||
By setting parents of DCLK_VOP1_DIV to frac/cpll we can achieve
|
|
||||||
various clock rates needed by display engine precisely.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 ++++++
|
|
||||||
1 file changed, 6 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index f6eac416..4603788 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -1211,6 +1211,9 @@ &usbdrd_dwc3_0 {
|
|
||||||
|
|
||||||
&vopb {
|
|
||||||
status = "okay";
|
|
||||||
+ assigned-clocks = <&cru DCLK_VOP0_DIV>, <&cru DCLK_VOP0>, <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;
|
|
||||||
+ assigned-clock-rates = <0>, <0>, <400000000>, <100000000>;
|
|
||||||
+ assigned-clock-parents = <&cru PLL_CPLL>, <&cru DCLK_VOP0_FRAC>;
|
|
||||||
};
|
|
||||||
|
|
||||||
&vopb_mmu {
|
|
||||||
@@ -1219,6 +1222,9 @@ &vopb_mmu {
|
|
||||||
|
|
||||||
&vopl {
|
|
||||||
status = "okay";
|
|
||||||
+ assigned-clocks = <&cru DCLK_VOP1_DIV>, <&cru DCLK_VOP1>, <&cru ACLK_VOP1>, <&cru HCLK_VOP1>;
|
|
||||||
+ assigned-clock-rates = <0>, <0>, <400000000>, <100000000>;
|
|
||||||
+ assigned-clock-parents = <&cru PLL_CPLL>, <&cru DCLK_VOP1_FRAC>;
|
|
||||||
};
|
|
||||||
|
|
||||||
&vopl_mmu {
|
|
@ -1,78 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Tue, 23 Nov 2021 23:26:26 +0100
|
|
||||||
Subject: [PATCH 17/18] arm64: dts: rk3399-pinephone-pro: Add support for
|
|
||||||
powering up the modem
|
|
||||||
|
|
||||||
Pinephone Pro has the same modem that's already supported by modem-power.
|
|
||||||
Add support for it do DT.
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 40 ++++++++++++++++++++++
|
|
||||||
1 file changed, 40 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 4603788..65cb701 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -253,6 +253,32 @@ regulator-state-mem {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ vcc_4g_5v: vcc-4g-5v {
|
|
||||||
+ compatible = "regulator-fixed";
|
|
||||||
+ enable-active-high;
|
|
||||||
+ gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&vcc_4g_5v_en>;
|
|
||||||
+ regulator-name = "vcc_4g_5v";
|
|
||||||
+ regulator-min-microvolt = <5000000>;
|
|
||||||
+ regulator-max-microvolt = <5000000>;
|
|
||||||
+ vin-supply = <&vcc5v0_sys>;
|
|
||||||
+ regulator-always-on;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ vcc_4g: vcc-4g {
|
|
||||||
+ compatible = "regulator-fixed";
|
|
||||||
+ enable-active-high;
|
|
||||||
+ gpio = <&gpio4 RK_PC7 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&vcc_4g_en>;
|
|
||||||
+ regulator-name = "vcc_4g";
|
|
||||||
+ regulator-min-microvolt = <3800000>;
|
|
||||||
+ regulator-max-microvolt = <3800000>;
|
|
||||||
+ vin-supply = <&vcc_sysin>;
|
|
||||||
+ regulator-always-on;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
vcc1v8_codec: vcc1v8-codec-regulator {
|
|
||||||
compatible = "regulator-fixed";
|
|
||||||
enable-active-high;
|
|
||||||
@@ -935,6 +961,10 @@ mipi_in_panel: endpoint {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+&uart3 {
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
&pmu_io_domains {
|
|
||||||
pmu1830-supply = <&vcc_1v8>;
|
|
||||||
status = "okay";
|
|
||||||
@@ -995,6 +1025,16 @@ blue_led_pin: blue-led-pin {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ modem {
|
|
||||||
+ vcc_4g_5v_en: vcc-4g-5v-en-pin {
|
|
||||||
+ rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ vcc_4g_en: vcc-4g-en-pin {
|
|
||||||
+ rockchip,pins = <4 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
pmic {
|
|
||||||
pmic_int_l: pmic-int-l {
|
|
||||||
rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
|
|
@ -1,139 +0,0 @@
|
|||||||
From: Ondrej Jirman <megous@megous.com>
|
|
||||||
Date: Wed, 24 Nov 2021 01:58:45 +0100
|
|
||||||
Subject: [PATCH 18/18] arm64: dts: rk3399-pinephone-pro: Add audio support
|
|
||||||
|
|
||||||
The codec is complicated, good luck! :D
|
|
||||||
|
|
||||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 96 ++++++++++++++++++++++
|
|
||||||
1 file changed, 96 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 65cb701..4afed92 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -168,6 +168,69 @@ power {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ // in1 - digital mic daughhterboard
|
|
||||||
+ // in2 - headset mic
|
|
||||||
+ // in3 - modem output (muxed with mono)
|
|
||||||
+ // spol - earphone
|
|
||||||
+ // hpo - heaphones
|
|
||||||
+ // lout - modem input
|
|
||||||
+ // spaker - amp enabled by SPK_CTL_H
|
|
||||||
+ //
|
|
||||||
+ // mclk - GPIO4_A0/I2S_CLK
|
|
||||||
+ //
|
|
||||||
+ // some gpio-jack-detection driver?
|
|
||||||
+ //pinctrl-0 = <&hp_det>; // GPIO4_D4
|
|
||||||
+
|
|
||||||
+ rt5640-sound {
|
|
||||||
+ compatible = "simple-audio-card";
|
|
||||||
+ simple-audio-card,name = "rockchip,rt5640-codec";
|
|
||||||
+ simple-audio-card,aux-devs = <&speaker_amp>;
|
|
||||||
+ simple-audio-card,format = "i2s";
|
|
||||||
+ simple-audio-card,mclk-fs = <256>;
|
|
||||||
+
|
|
||||||
+ simple-audio-card,widgets =
|
|
||||||
+ "Microphone", "Headset Microphone",
|
|
||||||
+ "Microphone", "Internal Microphone",
|
|
||||||
+ "Headphone", "Headphone Jack",
|
|
||||||
+ "Speaker", "Internal Earpiece",
|
|
||||||
+ "Speaker", "Internal Speaker",
|
|
||||||
+ "Line", "Line In Modem",
|
|
||||||
+ "Line", "Line Out Modem";
|
|
||||||
+
|
|
||||||
+ simple-audio-card,routing =
|
|
||||||
+ "Headphone Jack", "HPOL",
|
|
||||||
+ "Headphone Jack", "HPOR",
|
|
||||||
+ "Internal Earpiece", "SPOLP",
|
|
||||||
+ "Internal Earpiece", "SPOLN",
|
|
||||||
+ "Internal Speaker", "Speaker Amp OUTL",
|
|
||||||
+ "Internal Speaker", "Speaker Amp OUTR",
|
|
||||||
+ "Speaker Amp INL", "HPOL",
|
|
||||||
+ "Speaker Amp INR", "HPOR",
|
|
||||||
+ "DMIC1", "Internal Microphone",
|
|
||||||
+ "Headset Microphone", "MICBIAS1",
|
|
||||||
+ "IN2P", "Headset Microphone",
|
|
||||||
+ "Line Out Modem", "LOUTL",
|
|
||||||
+ "Line Out Modem", "LOUTR",
|
|
||||||
+ "IN3P", "Line In Modem",
|
|
||||||
+ "IN3N", "Line In Modem";
|
|
||||||
+
|
|
||||||
+ simple-audio-card,cpu {
|
|
||||||
+ sound-dai = <&i2s0>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ simple-audio-card,codec {
|
|
||||||
+ sound-dai = <&rt5640>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ speaker_amp: audio-amplifier {
|
|
||||||
+ compatible = "simple-audio-amplifier";
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&spk_en>;
|
|
||||||
+ enable-gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ sound-name-prefix = "Speaker Amp";
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
sdio_pwrseq: sdio-pwrseq {
|
|
||||||
compatible = "mmc-pwrseq-simple";
|
|
||||||
clocks = <&rk818 1>;
|
|
||||||
@@ -737,6 +800,24 @@ ucam_out: endpoint {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ // XXX: modem codec supplies:
|
|
||||||
+ // - vcc1v8_codec
|
|
||||||
+ // - vcca3v0_codec
|
|
||||||
+
|
|
||||||
+ // supplies: (always on currently)
|
|
||||||
+ // - vcca3v0_codec
|
|
||||||
+ // - vcca1v8_codec
|
|
||||||
+ // - vcc5v0_sys - spk_vcc
|
|
||||||
+ rt5640: rt5640@1c {
|
|
||||||
+ compatible = "realtek,rt5640";
|
|
||||||
+ reg = <0x1c>;
|
|
||||||
+ clocks = <&cru SCLK_I2S_8CH_OUT>;
|
|
||||||
+ clock-names = "mclk";
|
|
||||||
+ realtek,dmic1-data-pin = <1>;
|
|
||||||
+ realtek,in3-differential;
|
|
||||||
+ #sound-dai-cells = <0>;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
&i2c3 {
|
|
||||||
@@ -874,6 +955,13 @@ ak09911: compass@c {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+&i2s0 {
|
|
||||||
+ rockchip,playback-channels = <2>;
|
|
||||||
+ rockchip,capture-channels = <2>;
|
|
||||||
+ pinctrl-0 = <&i2s0_2ch_bus>;
|
|
||||||
+ status = "okay";
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
&io_domains {
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
@@ -1086,6 +1174,14 @@ sound {
|
|
||||||
vcc1v8_codec_en: vcc1v8-codec-en {
|
|
||||||
rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>;
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ hp_det: hp-det {
|
|
||||||
+ rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ spk_en: spk-en {
|
|
||||||
+ rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
|||||||
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
Date: Wed, 1 Dec 2021 20:48:51 +0100
|
|
||||||
Subject: arm64: dts: rk3399-pinephone-pro: Add flash and fix leds
|
|
||||||
|
|
||||||
The PinePhone Pro has a similar device to the SGM3140 used in the OG
|
|
||||||
PinePhone. This commit adds the corresponding device-tree node so the
|
|
||||||
flash/torch can work on this device.
|
|
||||||
|
|
||||||
Moreover, existing LEDs use different names and functions than what
|
|
||||||
we're used to, change them all to the same names we use on the OG
|
|
||||||
PinePhone.
|
|
||||||
|
|
||||||
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 47 +++++++++++++---------
|
|
||||||
1 file changed, 28 insertions(+), 19 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index 4afed92..e305955 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -127,30 +127,22 @@ leds {
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&red_led_pin &green_led_pin &blue_led_pin>;
|
|
||||||
|
|
||||||
- led-standby {
|
|
||||||
+ led-red {
|
|
||||||
color = <LED_COLOR_ID_RED>;
|
|
||||||
- default-state = "off";
|
|
||||||
- function = LED_FUNCTION_STANDBY;
|
|
||||||
+ function = LED_FUNCTION_INDICATOR;
|
|
||||||
gpios = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
|
|
||||||
- label = "red:standby";
|
|
||||||
- panic-indicator;
|
|
||||||
- retain-state-suspended;
|
|
||||||
};
|
|
||||||
|
|
||||||
- led-pwr {
|
|
||||||
+ led-green {
|
|
||||||
color = <LED_COLOR_ID_GREEN>;
|
|
||||||
- default-state = "on";
|
|
||||||
- function = LED_FUNCTION_POWER;
|
|
||||||
+ function = LED_FUNCTION_INDICATOR;
|
|
||||||
gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
|
|
||||||
- label = "green:disk-activity";
|
|
||||||
};
|
|
||||||
|
|
||||||
- blue-charging {
|
|
||||||
+ led-blue {
|
|
||||||
color = <LED_COLOR_ID_BLUE>;
|
|
||||||
- default-state = "off";
|
|
||||||
- function = LED_FUNCTION_CHARGING;
|
|
||||||
- gpios = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>;
|
|
||||||
- label = "blue:charging";
|
|
||||||
+ function = LED_FUNCTION_INDICATOR;
|
|
||||||
+ gpios = <&gpio4 RK_PD6 GPIO_ACTIVE_HIGH>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -399,6 +391,21 @@ typec_extcon_bridge: typec-extcon {
|
|
||||||
mode-switch;
|
|
||||||
svid = /bits/ 16 <0xff01>;
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ sgm3140: led-controller {
|
|
||||||
+ compatible = "sgmicro,sgm3140";
|
|
||||||
+ vin-supply = <&vcc3v3_sys>;
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&flash_pins>;
|
|
||||||
+ enable-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
|
|
||||||
+ flash-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
|
|
||||||
+
|
|
||||||
+ sgm3140_flash: led {
|
|
||||||
+ function = LED_FUNCTION_FLASH;
|
|
||||||
+ color = <LED_COLOR_ID_WHITE>;
|
|
||||||
+ flash-max-timeout-us = <250000>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
&cpu_l0 {
|
|
||||||
@@ -1111,6 +1118,12 @@ green_led_pin: green-led-pin {
|
|
||||||
blue_led_pin: blue-led-pin {
|
|
||||||
rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
};
|
|
||||||
+
|
|
||||||
+ flash_pins: flash-pins {
|
|
||||||
+ rockchip,pins =
|
|
||||||
+ <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>,
|
|
||||||
+ <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
modem {
|
|
||||||
@@ -1189,10 +1202,6 @@ &pwm0 {
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
||||||
-&pwm1 {
|
|
||||||
- status = "okay";
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
&pwm2 {
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
Date: Wed, 8 Dec 2021 23:43:08 +0100
|
|
||||||
Subject: arm64: dts: rk3399-pinephone-pro: add modem RI pin
|
|
||||||
|
|
||||||
Taht way the modem can wake the phone on incoming calls/messages.
|
|
||||||
|
|
||||||
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
---
|
|
||||||
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 19 +++++++++++++++++++
|
|
||||||
1 file changed, 19 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index e305955..ef5a58c 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -160,6 +160,21 @@ power {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ gpio-key-ri {
|
|
||||||
+ compatible = "gpio-keys";
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&ri_pin>;
|
|
||||||
+
|
|
||||||
+ ring_indicator: ring-indicator {
|
|
||||||
+ label = "ring-indicator";
|
|
||||||
+ linux,can-disable;
|
|
||||||
+ linux,code = <KEY_WAKEUP>;
|
|
||||||
+ gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>;
|
|
||||||
+ wakeup-event-action = <EV_ACT_ASSERTED>;
|
|
||||||
+ wakeup-source;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
// in1 - digital mic daughhterboard
|
|
||||||
// in2 - headset mic
|
|
||||||
// in3 - modem output (muxed with mono)
|
|
||||||
@@ -1127,6 +1142,10 @@ flash_pins: flash-pins {
|
|
||||||
};
|
|
||||||
|
|
||||||
modem {
|
|
||||||
+ ri_pin: ri-pin {
|
|
||||||
+ rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
vcc_4g_5v_en: vcc-4g-5v-en-pin {
|
|
||||||
rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
|
|
||||||
};
|
|
@ -1,90 +0,0 @@
|
|||||||
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
Date: Thu, 9 Dec 2021 16:52:29 +0100
|
|
||||||
Subject: arm64: dts: rk3399-pinephone-pro: improve sound device definition
|
|
||||||
|
|
||||||
This commit renames the sound card and the "Headphone" widget so they
|
|
||||||
match the names used by the ALSA UCM profiles.
|
|
||||||
|
|
||||||
It also adds a jack detection GPIO to the sound card definition, and
|
|
||||||
creates a new set of ADC keys for handling headset buttons.
|
|
||||||
|
|
||||||
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
||||||
---
|
|
||||||
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 41 ++++++++++++++++++----
|
|
||||||
1 file changed, 34 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
index ef5a58c..e46f36f 100644
|
|
||||||
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
|
|
||||||
@@ -48,6 +48,32 @@ button-down {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
+ headset-keys {
|
|
||||||
+ compatible = "adc-keys";
|
|
||||||
+ io-channels = <&saradc 2>;
|
|
||||||
+ io-channel-names = "buttons";
|
|
||||||
+ keyup-threshold-microvolt = <900000>;
|
|
||||||
+ poll-interval = <100>;
|
|
||||||
+
|
|
||||||
+ headset-play {
|
|
||||||
+ label = "Play";
|
|
||||||
+ linux,code = <KEY_PLAYPAUSE>;
|
|
||||||
+ press-threshold-microvolt = <650000>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ headset-up {
|
|
||||||
+ label = "Volume Up";
|
|
||||||
+ linux,code = <KEY_VOLUMEUP>;
|
|
||||||
+ press-threshold-microvolt = <750000>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ headset-down {
|
|
||||||
+ label = "Volume Down";
|
|
||||||
+ linux,code = <KEY_VOLUMEDOWN>;
|
|
||||||
+ press-threshold-microvolt = <850000>;
|
|
||||||
+ };
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
bat: battery {
|
|
||||||
compatible = "simple-battery";
|
|
||||||
voltage-min-design-microvolt = <3400000>;
|
|
||||||
@@ -184,29 +210,30 @@ ring_indicator: ring-indicator {
|
|
||||||
// spaker - amp enabled by SPK_CTL_H
|
|
||||||
//
|
|
||||||
// mclk - GPIO4_A0/I2S_CLK
|
|
||||||
- //
|
|
||||||
- // some gpio-jack-detection driver?
|
|
||||||
- //pinctrl-0 = <&hp_det>; // GPIO4_D4
|
|
||||||
|
|
||||||
rt5640-sound {
|
|
||||||
compatible = "simple-audio-card";
|
|
||||||
- simple-audio-card,name = "rockchip,rt5640-codec";
|
|
||||||
+ pinctrl-names = "default";
|
|
||||||
+ pinctrl-0 = <&hp_det>;
|
|
||||||
+ simple-audio-card,name = "PinePhonePro";
|
|
||||||
simple-audio-card,aux-devs = <&speaker_amp>;
|
|
||||||
simple-audio-card,format = "i2s";
|
|
||||||
simple-audio-card,mclk-fs = <256>;
|
|
||||||
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>;
|
|
||||||
+ simple-audio-card,pin-switches = "Internal Speaker";
|
|
||||||
|
|
||||||
simple-audio-card,widgets =
|
|
||||||
"Microphone", "Headset Microphone",
|
|
||||||
"Microphone", "Internal Microphone",
|
|
||||||
- "Headphone", "Headphone Jack",
|
|
||||||
+ "Headphone", "Headphones",
|
|
||||||
"Speaker", "Internal Earpiece",
|
|
||||||
"Speaker", "Internal Speaker",
|
|
||||||
"Line", "Line In Modem",
|
|
||||||
"Line", "Line Out Modem";
|
|
||||||
|
|
||||||
simple-audio-card,routing =
|
|
||||||
- "Headphone Jack", "HPOL",
|
|
||||||
- "Headphone Jack", "HPOR",
|
|
||||||
+ "Headphones", "HPOL",
|
|
||||||
+ "Headphones", "HPOR",
|
|
||||||
"Internal Earpiece", "SPOLP",
|
|
||||||
"Internal Earpiece", "SPOLN",
|
|
||||||
"Internal Speaker", "Speaker Amp OUTL",
|
|
@ -1,172 +0,0 @@
|
|||||||
From 2423aac2d6f5db55da99e11fd799ee66fe6f54c6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Samuel Holland <samuel@sholland.org>
|
|
||||||
Date: Mon, 9 Aug 2021 19:30:18 -0500
|
|
||||||
Subject: [PATCH] Input: kb151 - Add support for the FN layer
|
|
||||||
|
|
||||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
|
||||||
---
|
|
||||||
.../dts/allwinner/sun50i-a64-pinephone.dtsi | 34 +++++++++++++++++--
|
|
||||||
drivers/input/keyboard/kb151.c | 33 ++++++++++--------
|
|
||||||
2 files changed, 51 insertions(+), 16 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
index 0bdc6eceec6099..68f5730cf164c7 100644
|
|
||||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
@@ -557,7 +557,7 @@
|
|
||||||
reg = <0x15>;
|
|
||||||
interrupt-parent = <&r_pio>;
|
|
||||||
interrupts = <0 12 IRQ_TYPE_EDGE_FALLING>; /* PL12 */
|
|
||||||
- keypad,num-rows = <6>;
|
|
||||||
+ keypad,num-rows = <12>;
|
|
||||||
keypad,num-columns = <12>;
|
|
||||||
linux,keymap = <MATRIX_KEY(0, 0, KEY_ESC)
|
|
||||||
MATRIX_KEY(0, 1, KEY_1)
|
|
||||||
@@ -612,7 +612,37 @@
|
|
||||||
MATRIX_KEY(4, 9, KEY_LEFTBRACE)
|
|
||||||
MATRIX_KEY(5, 2, KEY_FN)
|
|
||||||
MATRIX_KEY(5, 3, KEY_LEFTALT)
|
|
||||||
- MATRIX_KEY(5, 5, KEY_RIGHTALT)>;
|
|
||||||
+ MATRIX_KEY(5, 5, KEY_RIGHTALT)
|
|
||||||
+
|
|
||||||
+ /* FN layer */
|
|
||||||
+ MATRIX_KEY(6, 1, KEY_BACKSLASH)
|
|
||||||
+ MATRIX_KEY(6, 2, KEY_BACKSLASH)
|
|
||||||
+ MATRIX_KEY(6, 3, KEY_DOLLAR)
|
|
||||||
+ MATRIX_KEY(6, 4, KEY_EURO)
|
|
||||||
+ MATRIX_KEY(6, 5, KEY_GRAVE)
|
|
||||||
+ MATRIX_KEY(6, 6, KEY_GRAVE)
|
|
||||||
+ MATRIX_KEY(6, 7, KEY_MINUS)
|
|
||||||
+ MATRIX_KEY(6, 8, KEY_EQUAL)
|
|
||||||
+ MATRIX_KEY(6, 9, KEY_MINUS)
|
|
||||||
+ MATRIX_KEY(6, 10, KEY_EQUAL)
|
|
||||||
+ MATRIX_KEY(6, 11, KEY_DELETE)
|
|
||||||
+
|
|
||||||
+ MATRIX_KEY(8, 0, KEY_SYSRQ)
|
|
||||||
+ MATRIX_KEY(8, 10, KEY_INSERT)
|
|
||||||
+
|
|
||||||
+ MATRIX_KEY(9, 0, KEY_LEFTSHIFT)
|
|
||||||
+ MATRIX_KEY(9, 8, KEY_HOME)
|
|
||||||
+ MATRIX_KEY(9, 9, KEY_UP)
|
|
||||||
+ MATRIX_KEY(9, 10, KEY_END)
|
|
||||||
+
|
|
||||||
+ MATRIX_KEY(10, 1, KEY_LEFTCTRL)
|
|
||||||
+ MATRIX_KEY(10, 6, KEY_LEFT)
|
|
||||||
+ MATRIX_KEY(10, 8, KEY_RIGHT)
|
|
||||||
+ MATRIX_KEY(10, 9, KEY_DOWN)
|
|
||||||
+
|
|
||||||
+ MATRIX_KEY(11, 2, KEY_FN)
|
|
||||||
+ MATRIX_KEY(11, 3, KEY_LEFTALT)
|
|
||||||
+ MATRIX_KEY(11, 5, KEY_RIGHTALT)>;
|
|
||||||
wakeup-source;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c
|
|
||||||
index 595275d4f9d96f..bb6250efe93419 100644
|
|
||||||
--- a/drivers/input/keyboard/kb151.c
|
|
||||||
+++ b/drivers/input/keyboard/kb151.c
|
|
||||||
@@ -29,6 +29,7 @@ struct kb151 {
|
|
||||||
u8 row_shift;
|
|
||||||
u8 rows;
|
|
||||||
u8 cols;
|
|
||||||
+ u8 fn_state;
|
|
||||||
u8 buf_swap;
|
|
||||||
u8 buf[];
|
|
||||||
};
|
|
||||||
@@ -55,7 +56,7 @@ static void kb151_update(struct i2c_client *client)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
- dev_info(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
||||||
+ dev_dbg(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
||||||
new_buf[0], new_buf[1], new_buf[2], new_buf[3], new_buf[4], new_buf[5],
|
|
||||||
new_buf[6], new_buf[7], new_buf[8], new_buf[9], new_buf[10], new_buf[11],
|
|
||||||
new_buf[12]);
|
|
||||||
@@ -65,8 +66,6 @@ static void kb151_update(struct i2c_client *client)
|
|
||||||
crc, new_buf[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
- dev_info(dev, "Good scan data (%02x == %02x)\n",
|
|
||||||
- crc, new_buf[0]);
|
|
||||||
|
|
||||||
for (col = 0; col < kb151->cols; ++col) {
|
|
||||||
u8 old = *(++old_buf);
|
|
||||||
@@ -74,14 +73,20 @@ static void kb151_update(struct i2c_client *client)
|
|
||||||
u8 changed = old ^ new;
|
|
||||||
|
|
||||||
for (row = 0; row < kb151->rows; ++row) {
|
|
||||||
- int code = MATRIX_SCAN_CODE(row, col, kb151->row_shift);
|
|
||||||
u8 pressed = new & BIT(row);
|
|
||||||
+ u8 map_row = row + (kb151->fn_state ? kb151->rows : 0);
|
|
||||||
+ int code = MATRIX_SCAN_CODE(map_row, col, kb151->row_shift);
|
|
||||||
|
|
||||||
if (!(changed & BIT(row)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "row %u col %u %sed\n",
|
|
||||||
- row, col, pressed ? "press" : "releas");
|
|
||||||
+ map_row, col, pressed ? "press" : "releas");
|
|
||||||
+ if (keymap[code] == KEY_FN) {
|
|
||||||
+ dev_dbg(&client->dev, "FN is now %s\n",
|
|
||||||
+ pressed ? "pressed" : "released");
|
|
||||||
+ kb151->fn_state = pressed;
|
|
||||||
+ } else
|
|
||||||
input_report_key(kb151->input, keymap[code], pressed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -151,7 +156,7 @@ static int kb151_probe(struct i2c_client *client)
|
|
||||||
struct device *dev = &client->dev;
|
|
||||||
u8 info[KB151_MATRIX_SIZE + 1];
|
|
||||||
unsigned int kb_rows, kb_cols;
|
|
||||||
- unsigned int rows, cols;
|
|
||||||
+ unsigned int map_rows, map_cols;
|
|
||||||
struct kb151 *kb151;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
@@ -168,20 +173,20 @@ static int kb151_probe(struct i2c_client *client)
|
|
||||||
info[KB151_FW_REVISION] & 0xf,
|
|
||||||
info[KB151_FW_FEATURES]);
|
|
||||||
|
|
||||||
- ret = matrix_keypad_parse_properties(dev, &rows, &cols);
|
|
||||||
+ ret = matrix_keypad_parse_properties(dev, &map_rows, &map_cols);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
kb_rows = info[KB151_MATRIX_SIZE] & 0xf;
|
|
||||||
kb_cols = info[KB151_MATRIX_SIZE] >> 4;
|
|
||||||
- if (rows > kb_rows || cols != kb_cols) {
|
|
||||||
+ if (map_rows != 2 * kb_rows || map_cols != kb_cols) {
|
|
||||||
dev_err(dev, "Keyboard matrix is %ux%u, but key map is %ux%u\n",
|
|
||||||
- kb_rows, kb_cols, rows, cols);
|
|
||||||
+ kb_rows, kb_cols, map_rows, map_cols);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate two buffers, and include space for the CRC. */
|
|
||||||
- kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (cols + 1)), GFP_KERNEL);
|
|
||||||
+ kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (kb_cols + 1)), GFP_KERNEL);
|
|
||||||
if (!kb151)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
@@ -189,9 +194,9 @@ static int kb151_probe(struct i2c_client *client)
|
|
||||||
|
|
||||||
crc8_populate_msb(kb151->crc_table, KB151_CRC8_POLYNOMIAL);
|
|
||||||
|
|
||||||
- kb151->row_shift = get_count_order(cols);
|
|
||||||
- kb151->rows = rows;
|
|
||||||
- kb151->cols = cols;
|
|
||||||
+ kb151->row_shift = get_count_order(kb_cols);
|
|
||||||
+ kb151->rows = kb_rows;
|
|
||||||
+ kb151->cols = kb_cols;
|
|
||||||
|
|
||||||
kb151->input = devm_input_allocate_device(dev);
|
|
||||||
if (!kb151->input)
|
|
||||||
@@ -207,7 +212,7 @@ static int kb151_probe(struct i2c_client *client)
|
|
||||||
|
|
||||||
__set_bit(EV_REP, kb151->input->evbit);
|
|
||||||
|
|
||||||
- ret = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
|
|
||||||
+ ret = matrix_keypad_build_keymap(NULL, NULL, map_rows, map_cols,
|
|
||||||
NULL, kb151->input);
|
|
||||||
if (ret)
|
|
||||||
return dev_err_probe(dev, ret, "Failed to build keymap\n");
|
|
@ -1,12 +0,0 @@
|
|||||||
[Trigger]
|
|
||||||
Type = File
|
|
||||||
Operation = Install
|
|
||||||
Operation = Upgrade
|
|
||||||
Operation = Remove
|
|
||||||
Target = usr/lib/modules/%KERNVER%/*
|
|
||||||
Target = usr/lib/modules/%EXTRAMODULES%/*
|
|
||||||
|
|
||||||
[Action]
|
|
||||||
Description = Updating %PKGBASE% module dependencies...
|
|
||||||
When = PostTransaction
|
|
||||||
Exec = /usr/bin/depmod %KERNVER%
|
|
@ -1,377 +0,0 @@
|
|||||||
From d1d849cae12db71aa81ceedaedc1b17a34790367 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Samuel Holland <samuel@sholland.org>
|
|
||||||
Date: Sat, 19 Jun 2021 18:36:05 -0500
|
|
||||||
Subject: [PATCH] Input: kb151 - Add a driver for the KB151 keyboard
|
|
||||||
|
|
||||||
This keyboard is found in the official Pine64 PinePhone keyboard case.
|
|
||||||
It is connected over I2C and runs a libre firmware.
|
|
||||||
|
|
||||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
|
||||||
---
|
|
||||||
.../dts/allwinner/sun50i-a64-pinephone.dtsi | 64 +++++
|
|
||||||
drivers/input/keyboard/Kconfig | 10 +
|
|
||||||
drivers/input/keyboard/Makefile | 1 +
|
|
||||||
drivers/input/keyboard/kb151.c | 246 ++++++++++++++++++
|
|
||||||
4 files changed, 321 insertions(+)
|
|
||||||
create mode 100644 drivers/input/keyboard/kb151.c
|
|
||||||
|
|
||||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
index 4ede9fe66020c9..0bdc6eceec6099 100644
|
|
||||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
@@ -551,6 +551,70 @@
|
|
||||||
/* Connected to pogo pins (external spring based pinheader for user addons) */
|
|
||||||
&i2c2 {
|
|
||||||
status = "okay";
|
|
||||||
+
|
|
||||||
+ keyboard@15 {
|
|
||||||
+ compatible = "pine64,kb151";
|
|
||||||
+ reg = <0x15>;
|
|
||||||
+ interrupt-parent = <&r_pio>;
|
|
||||||
+ interrupts = <0 12 IRQ_TYPE_EDGE_FALLING>; /* PL12 */
|
|
||||||
+ keypad,num-rows = <6>;
|
|
||||||
+ keypad,num-columns = <12>;
|
|
||||||
+ linux,keymap = <MATRIX_KEY(0, 0, KEY_ESC)
|
|
||||||
+ MATRIX_KEY(0, 1, KEY_1)
|
|
||||||
+ MATRIX_KEY(0, 2, KEY_2)
|
|
||||||
+ MATRIX_KEY(0, 3, KEY_3)
|
|
||||||
+ MATRIX_KEY(0, 4, KEY_4)
|
|
||||||
+ MATRIX_KEY(0, 5, KEY_5)
|
|
||||||
+ MATRIX_KEY(0, 6, KEY_6)
|
|
||||||
+ MATRIX_KEY(0, 7, KEY_7)
|
|
||||||
+ MATRIX_KEY(0, 8, KEY_8)
|
|
||||||
+ MATRIX_KEY(0, 9, KEY_9)
|
|
||||||
+ MATRIX_KEY(0, 10, KEY_0)
|
|
||||||
+ MATRIX_KEY(0, 11, KEY_BACKSPACE)
|
|
||||||
+ MATRIX_KEY(1, 0, KEY_TAB)
|
|
||||||
+ MATRIX_KEY(1, 1, KEY_Q)
|
|
||||||
+ MATRIX_KEY(1, 2, KEY_W)
|
|
||||||
+ MATRIX_KEY(1, 3, KEY_E)
|
|
||||||
+ MATRIX_KEY(1, 4, KEY_R)
|
|
||||||
+ MATRIX_KEY(1, 5, KEY_T)
|
|
||||||
+ MATRIX_KEY(1, 6, KEY_Y)
|
|
||||||
+ MATRIX_KEY(1, 7, KEY_U)
|
|
||||||
+ MATRIX_KEY(1, 8, KEY_I)
|
|
||||||
+ MATRIX_KEY(1, 9, KEY_O)
|
|
||||||
+ MATRIX_KEY(1, 10, KEY_P)
|
|
||||||
+ MATRIX_KEY(1, 11, KEY_ENTER)
|
|
||||||
+ MATRIX_KEY(2, 0, KEY_LEFTMETA)
|
|
||||||
+ MATRIX_KEY(2, 1, KEY_A)
|
|
||||||
+ MATRIX_KEY(2, 2, KEY_S)
|
|
||||||
+ MATRIX_KEY(2, 3, KEY_D)
|
|
||||||
+ MATRIX_KEY(2, 4, KEY_F)
|
|
||||||
+ MATRIX_KEY(2, 5, KEY_G)
|
|
||||||
+ MATRIX_KEY(2, 6, KEY_H)
|
|
||||||
+ MATRIX_KEY(2, 7, KEY_J)
|
|
||||||
+ MATRIX_KEY(2, 8, KEY_K)
|
|
||||||
+ MATRIX_KEY(2, 9, KEY_L)
|
|
||||||
+ MATRIX_KEY(2, 10, KEY_SEMICOLON)
|
|
||||||
+ MATRIX_KEY(3, 0, KEY_LEFTSHIFT)
|
|
||||||
+ MATRIX_KEY(3, 1, KEY_Z)
|
|
||||||
+ MATRIX_KEY(3, 2, KEY_X)
|
|
||||||
+ MATRIX_KEY(3, 3, KEY_C)
|
|
||||||
+ MATRIX_KEY(3, 4, KEY_V)
|
|
||||||
+ MATRIX_KEY(3, 5, KEY_B)
|
|
||||||
+ MATRIX_KEY(3, 6, KEY_N)
|
|
||||||
+ MATRIX_KEY(3, 7, KEY_M)
|
|
||||||
+ MATRIX_KEY(3, 8, KEY_COMMA)
|
|
||||||
+ MATRIX_KEY(3, 9, KEY_DOT)
|
|
||||||
+ MATRIX_KEY(3, 10, KEY_SLASH)
|
|
||||||
+ MATRIX_KEY(4, 1, KEY_LEFTCTRL)
|
|
||||||
+ MATRIX_KEY(4, 4, KEY_SPACE)
|
|
||||||
+ MATRIX_KEY(4, 6, KEY_APOSTROPHE)
|
|
||||||
+ MATRIX_KEY(4, 8, KEY_RIGHTBRACE)
|
|
||||||
+ MATRIX_KEY(4, 9, KEY_LEFTBRACE)
|
|
||||||
+ MATRIX_KEY(5, 2, KEY_FN)
|
|
||||||
+ MATRIX_KEY(5, 3, KEY_LEFTALT)
|
|
||||||
+ MATRIX_KEY(5, 5, KEY_RIGHTALT)>;
|
|
||||||
+ wakeup-source;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
&i2s2 {
|
|
||||||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
|
|
||||||
index 40a070a2e7f5b7..0259e9133f4692 100644
|
|
||||||
--- a/drivers/input/keyboard/Kconfig
|
|
||||||
+++ b/drivers/input/keyboard/Kconfig
|
|
||||||
@@ -353,6 +353,16 @@ config KEYBOARD_HP7XX
|
|
||||||
To compile this driver as a module, choose M here: the
|
|
||||||
module will be called jornada720_kbd.
|
|
||||||
|
|
||||||
+config KEYBOARD_KB151
|
|
||||||
+ tristate "Pine64 KB151 Keyboard"
|
|
||||||
+ depends on I2C
|
|
||||||
+ select CRC8
|
|
||||||
+ select INPUT_MATRIXKMAP
|
|
||||||
+ help
|
|
||||||
+ Say Y here to enable support for the KB151 keyboard used in the
|
|
||||||
+ Pine64 PinePhone keyboard case. This driver supports the FLOSS
|
|
||||||
+ firmware available at https://megous.com/git/pinephone-keyboard/
|
|
||||||
+
|
|
||||||
config KEYBOARD_LM8323
|
|
||||||
tristate "LM8323 keypad chip"
|
|
||||||
depends on I2C
|
|
||||||
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
|
|
||||||
index 1d689fdd5c00f9..87fda7b961913a 100644
|
|
||||||
--- a/drivers/input/keyboard/Makefile
|
|
||||||
+++ b/drivers/input/keyboard/Makefile
|
|
||||||
@@ -33,6 +33,7 @@ obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
|
|
||||||
+obj-$(CONFIG_KEYBOARD_KB151) += kb151.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
|
|
||||||
obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o
|
|
||||||
diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000000..595275d4f9d96f
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/input/keyboard/kb151.c
|
|
||||||
@@ -0,0 +1,246 @@
|
|
||||||
+// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
+//
|
|
||||||
+// Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
|
|
||||||
+
|
|
||||||
+#include <linux/crc8.h>
|
|
||||||
+#include <linux/i2c.h>
|
|
||||||
+#include <linux/input/matrix_keypad.h>
|
|
||||||
+#include <linux/interrupt.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/pm_wakeirq.h>
|
|
||||||
+
|
|
||||||
+#define KB151_CRC8_POLYNOMIAL 0x07
|
|
||||||
+
|
|
||||||
+#define KB151_DEVICE_ID_HI 0x00
|
|
||||||
+#define KB151_DEVICE_ID_HI_VALUE 0x4b
|
|
||||||
+#define KB151_DEVICE_ID_LO 0x01
|
|
||||||
+#define KB151_DEVICE_ID_LO_VALUE 0x42
|
|
||||||
+#define KB151_FW_REVISION 0x02
|
|
||||||
+#define KB151_FW_FEATURES 0x03
|
|
||||||
+#define KB151_MATRIX_SIZE 0x06
|
|
||||||
+#define KB151_SCAN_CRC 0x07
|
|
||||||
+#define KB151_SCAN_DATA 0x08
|
|
||||||
+#define KB151_SYS_CONFIG 0x20
|
|
||||||
+#define KB151_SYS_CONFIG_DISABLE_SCAN BIT(0)
|
|
||||||
+
|
|
||||||
+struct kb151 {
|
|
||||||
+ struct input_dev *input;
|
|
||||||
+ u8 crc_table[CRC8_TABLE_SIZE];
|
|
||||||
+ u8 row_shift;
|
|
||||||
+ u8 rows;
|
|
||||||
+ u8 cols;
|
|
||||||
+ u8 buf_swap;
|
|
||||||
+ u8 buf[];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void kb151_update(struct i2c_client *client)
|
|
||||||
+{
|
|
||||||
+ struct kb151 *kb151 = i2c_get_clientdata(client);
|
|
||||||
+ unsigned short *keymap = kb151->input->keycode;
|
|
||||||
+ struct device *dev = &client->dev;
|
|
||||||
+ size_t buf_len = kb151->cols + 1;
|
|
||||||
+ u8 *old_buf = kb151->buf;
|
|
||||||
+ u8 *new_buf = kb151->buf;
|
|
||||||
+ int col, crc, ret, row;
|
|
||||||
+
|
|
||||||
+ if (kb151->buf_swap)
|
|
||||||
+ old_buf += buf_len;
|
|
||||||
+ else
|
|
||||||
+ new_buf += buf_len;
|
|
||||||
+
|
|
||||||
+ ret = i2c_smbus_read_i2c_block_data(client, KB151_SCAN_CRC,
|
|
||||||
+ buf_len, new_buf);
|
|
||||||
+ if (ret != buf_len) {
|
|
||||||
+ dev_err(dev, "Failed to read scan data: %d\n", ret);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ dev_info(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
||||||
+ new_buf[0], new_buf[1], new_buf[2], new_buf[3], new_buf[4], new_buf[5],
|
|
||||||
+ new_buf[6], new_buf[7], new_buf[8], new_buf[9], new_buf[10], new_buf[11],
|
|
||||||
+ new_buf[12]);
|
|
||||||
+ crc = crc8(kb151->crc_table, new_buf + 1, kb151->cols, CRC8_INIT_VALUE);
|
|
||||||
+ if (crc != new_buf[0]) {
|
|
||||||
+ dev_err(dev, "Bad scan data (%02x != %02x)\n",
|
|
||||||
+ crc, new_buf[0]);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ dev_info(dev, "Good scan data (%02x == %02x)\n",
|
|
||||||
+ crc, new_buf[0]);
|
|
||||||
+
|
|
||||||
+ for (col = 0; col < kb151->cols; ++col) {
|
|
||||||
+ u8 old = *(++old_buf);
|
|
||||||
+ u8 new = *(++new_buf);
|
|
||||||
+ u8 changed = old ^ new;
|
|
||||||
+
|
|
||||||
+ for (row = 0; row < kb151->rows; ++row) {
|
|
||||||
+ int code = MATRIX_SCAN_CODE(row, col, kb151->row_shift);
|
|
||||||
+ u8 pressed = new & BIT(row);
|
|
||||||
+
|
|
||||||
+ if (!(changed & BIT(row)))
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ dev_dbg(&client->dev, "row %u col %u %sed\n",
|
|
||||||
+ row, col, pressed ? "press" : "releas");
|
|
||||||
+ input_report_key(kb151->input, keymap[code], pressed);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ input_sync(kb151->input);
|
|
||||||
+
|
|
||||||
+ kb151->buf_swap = !kb151->buf_swap;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int kb151_open(struct input_dev *input)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = input_get_drvdata(input);
|
|
||||||
+ struct device *dev = &client->dev;
|
|
||||||
+ int ret, val;
|
|
||||||
+
|
|
||||||
+ ret = i2c_smbus_read_byte_data(client, KB151_SYS_CONFIG);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(dev, "Failed to read config: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ val = ret & ~KB151_SYS_CONFIG_DISABLE_SCAN;
|
|
||||||
+ ret = i2c_smbus_write_byte_data(client, KB151_SYS_CONFIG, val);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(dev, "Failed to write config: %d\n", ret);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ kb151_update(client);
|
|
||||||
+
|
|
||||||
+ enable_irq(client->irq);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void kb151_close(struct input_dev *input)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = input_get_drvdata(input);
|
|
||||||
+ struct device *dev = &client->dev;
|
|
||||||
+ int ret, val;
|
|
||||||
+
|
|
||||||
+ disable_irq(client->irq);
|
|
||||||
+
|
|
||||||
+ ret = i2c_smbus_read_byte_data(client, KB151_SYS_CONFIG);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ dev_err(dev, "Failed to read config: %d\n", ret);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ val = ret | KB151_SYS_CONFIG_DISABLE_SCAN;
|
|
||||||
+ ret = i2c_smbus_write_byte_data(client, KB151_SYS_CONFIG, val);
|
|
||||||
+ if (ret) {
|
|
||||||
+ dev_err(dev, "Failed to write config: %d\n", ret);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t kb151_irq_thread(int irq, void *data)
|
|
||||||
+{
|
|
||||||
+ struct i2c_client *client = data;
|
|
||||||
+
|
|
||||||
+ kb151_update(client);
|
|
||||||
+
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int kb151_probe(struct i2c_client *client)
|
|
||||||
+{
|
|
||||||
+ struct device *dev = &client->dev;
|
|
||||||
+ u8 info[KB151_MATRIX_SIZE + 1];
|
|
||||||
+ unsigned int kb_rows, kb_cols;
|
|
||||||
+ unsigned int rows, cols;
|
|
||||||
+ struct kb151 *kb151;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = i2c_smbus_read_i2c_block_data(client, 0, sizeof(info), info);
|
|
||||||
+ if (ret != sizeof(info))
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ if (info[KB151_DEVICE_ID_HI] != KB151_DEVICE_ID_HI_VALUE ||
|
|
||||||
+ info[KB151_DEVICE_ID_LO] != KB151_DEVICE_ID_LO_VALUE)
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ dev_info(dev, "Found KB151 with firmware %d.%d (features=%#x)\n",
|
|
||||||
+ info[KB151_FW_REVISION] >> 4,
|
|
||||||
+ info[KB151_FW_REVISION] & 0xf,
|
|
||||||
+ info[KB151_FW_FEATURES]);
|
|
||||||
+
|
|
||||||
+ ret = matrix_keypad_parse_properties(dev, &rows, &cols);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ kb_rows = info[KB151_MATRIX_SIZE] & 0xf;
|
|
||||||
+ kb_cols = info[KB151_MATRIX_SIZE] >> 4;
|
|
||||||
+ if (rows > kb_rows || cols != kb_cols) {
|
|
||||||
+ dev_err(dev, "Keyboard matrix is %ux%u, but key map is %ux%u\n",
|
|
||||||
+ kb_rows, kb_cols, rows, cols);
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Allocate two buffers, and include space for the CRC. */
|
|
||||||
+ kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (cols + 1)), GFP_KERNEL);
|
|
||||||
+ if (!kb151)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ i2c_set_clientdata(client, kb151);
|
|
||||||
+
|
|
||||||
+ crc8_populate_msb(kb151->crc_table, KB151_CRC8_POLYNOMIAL);
|
|
||||||
+
|
|
||||||
+ kb151->row_shift = get_count_order(cols);
|
|
||||||
+ kb151->rows = rows;
|
|
||||||
+ kb151->cols = cols;
|
|
||||||
+
|
|
||||||
+ kb151->input = devm_input_allocate_device(dev);
|
|
||||||
+ if (!kb151->input)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ input_set_drvdata(kb151->input, client);
|
|
||||||
+
|
|
||||||
+ kb151->input->name = client->name;
|
|
||||||
+ kb151->input->phys = "kb151/input0";
|
|
||||||
+ kb151->input->id.bustype = BUS_I2C;
|
|
||||||
+ kb151->input->open = kb151_open;
|
|
||||||
+ kb151->input->close = kb151_close;
|
|
||||||
+
|
|
||||||
+ __set_bit(EV_REP, kb151->input->evbit);
|
|
||||||
+
|
|
||||||
+ ret = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
|
|
||||||
+ NULL, kb151->input);
|
|
||||||
+ if (ret)
|
|
||||||
+ return dev_err_probe(dev, ret, "Failed to build keymap\n");
|
|
||||||
+
|
|
||||||
+ ret = devm_request_threaded_irq(dev, client->irq,
|
|
||||||
+ NULL, kb151_irq_thread,
|
|
||||||
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
|
|
||||||
+ client->name, client);
|
|
||||||
+ if (ret)
|
|
||||||
+ return dev_err_probe(dev, ret, "Failed to request IRQ\n");
|
|
||||||
+
|
|
||||||
+ ret = input_register_device(kb151->input);
|
|
||||||
+ if (ret)
|
|
||||||
+ return dev_err_probe(dev, ret, "Failed to register input\n");
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct of_device_id kb151_of_match[] = {
|
|
||||||
+ { .compatible = "pine64,kb151" },
|
|
||||||
+ { }
|
|
||||||
+};
|
|
||||||
+MODULE_DEVICE_TABLE(of, kb151_of_match);
|
|
||||||
+
|
|
||||||
+static struct i2c_driver kb151_driver = {
|
|
||||||
+ .probe_new = kb151_probe,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "kb151",
|
|
||||||
+ .of_match_table = kb151_of_match,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+module_i2c_driver(kb151_driver);
|
|
||||||
+
|
|
||||||
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
|
|
||||||
+MODULE_DESCRIPTION("Pine64 KB151 keyboard driver");
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
49
sys-kernel/pinephone-sources/pinephone-sources-5.16.0.ebuild
Normal file
49
sys-kernel/pinephone-sources/pinephone-sources-5.16.0.ebuild
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Copyright 1999-2021 Gentoo Authors
|
||||||
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
|
||||||
|
EAPI="8"
|
||||||
|
K_NOUSENAME="yes"
|
||||||
|
K_NOSETEXTRAVERSION="yes"
|
||||||
|
K_SECURITY_UNSUPPORTED="1"
|
||||||
|
ETYPE="sources"
|
||||||
|
inherit kernel-2
|
||||||
|
detect_version
|
||||||
|
|
||||||
|
KEYWORDS="~arm64"
|
||||||
|
|
||||||
|
DEPEND="${RDEPEND}
|
||||||
|
>=sys-devel/patch-2.7.5"
|
||||||
|
|
||||||
|
DESCRIPTION="Full sources for the Linux kernel, with megi's patch for pinephone"
|
||||||
|
|
||||||
|
MEGI_PATCH_URI="https://xff.cz/kernels/${PV:0:4}/patches/all.patch"
|
||||||
|
SRC_URI="${KERNEL_URI} ${MEGI_PATCH_URI} -> all-${PV}.patch"
|
||||||
|
|
||||||
|
PATCHES=(
|
||||||
|
${DISTDIR}/all-${PV}.patch
|
||||||
|
)
|
||||||
|
|
||||||
|
src_prepare() {
|
||||||
|
default
|
||||||
|
eapply_user
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg_postinst() {
|
||||||
|
kernel-2_pkg_postinst
|
||||||
|
einfo "For more info on this patchset, and how to report problems, see:"
|
||||||
|
einfo "${HOMEPAGE}"
|
||||||
|
einfo "To build the kernel use the following command:"
|
||||||
|
einfo "make Image Image.gz modules"
|
||||||
|
einfo "make DTC_FLAGS="-@" dtbs"
|
||||||
|
einfo "make install; make modules_intall; make dtbs_install"
|
||||||
|
einfo "If you use kernel config coming with this ebuild, don't forget to also copy dracut-pp.conf to /etc/dracut.conf.d/"
|
||||||
|
einfo "to make sure proper kernel modules are loaded into initramfs"
|
||||||
|
einfo "if you want to cross compile pinephone kernel on amd64 host, follow the https://wiki.gentoo.org/wiki/Cross_build_environment"
|
||||||
|
einfo "to setup cross toolchain environment, then create a xmake wrapper like the following, and replace make with xmake in above commands"
|
||||||
|
einfo "#!/bin/sh"
|
||||||
|
einfo "exec make ARCH='arm64' CROSS_COMPILE='aarch64-unknown-linux-gnu-' INSTALL_MOD_PATH='${SYSROOT}' '$@'"
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg_postrm() {
|
||||||
|
kernel-2_pkg_postrm
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user