[RESEND PATCH] drm/rockchip: dsi: move all lane config except LCDC mux to bind()

2021-04-18 Thread Thomas Hebb
When we first enable the DSI encoder, we currently program some per-chip
configuration that we look up in rk3399_chip_data based on the device
tree compatible we match. This data configures various parameters of the
MIPI lanes, including on RK3399 whether DSI1 is slaved to DSI0 in a
dual-mode configuration. It also selects which LCDC (i.e. VOP) to scan
out from.

This causes a problem in RK3399 dual-mode configurations, though: panel
prepare() callbacks run before the encoder gets enabled and expect to be
able to write commands to the DSI bus, but the bus isn't fully
functional until the lane and master/slave configuration have been
programmed. As a result, dual-mode panels (and possibly others too) fail
to turn on when the rockchipdrm driver is initially loaded.

Because the LCDC mux is the only thing we don't know until enable time
(and is the only thing that can ever change), we can actually move most
of the initialization to bind() and get it out of the way early. That's
what this change does. (Rockchip's 4.4 BSP kernel does it in mode_set(),
which also avoids the issue, but bind() seems like the more correct
place to me.)

Tested on a Google Scarlet board (Acer Chromebook Tab 10), which has a
Kingdisplay KD097D04 dual-mode panel. Prior to this change, the panel's
backlight would turn on but no image would appear when initially loading
rockchipdrm. If I kept rockchipdrm loaded and reloaded the panel driver,
it would come on. With this change, the panel successfully turns on
during initial rockchipdrm load as expected.

Fixes: 2d4f7bdafd70 ("drm/rockchip: dsi: migrate to use dw-mipi-dsi bridge 
driver")
Signed-off-by: Thomas Hebb 
---

 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 36 ++-
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 8cc81d5b82f0..520a0a0cd2b5 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -691,13 +691,8 @@ static const struct dw_mipi_dsi_phy_ops 
dw_mipi_dsi_rockchip_phy_ops = {
.get_timing = dw_mipi_dsi_phy_get_timing,
 };
 
-static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
-   int mux)
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
 {
-   if (dsi->cdata->lcdsel_grf_reg)
-   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
-   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
-
if (dsi->cdata->lanecfg1_grf_reg)
regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
  dsi->cdata->lanecfg1);
@@ -711,6 +706,13 @@ static void dw_mipi_dsi_rockchip_config(struct 
dw_mipi_dsi_rockchip *dsi,
  dsi->cdata->enable);
 }
 
+static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
+   int mux)
+{
+   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+}
+
 static int
 dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 struct drm_crtc_state *crtc_state,
@@ -766,9 +768,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder 
*encoder)
return;
}
 
-   dw_mipi_dsi_rockchip_config(dsi, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
if (dsi->slave)
-   dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);
 
clk_disable_unprepare(dsi->grf_clk);
 }
@@ -922,6 +924,24 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
return ret;
}
 
+   /*
+* With the GRF clock running, write lane and dual-mode configurations
+* that won't change immediately. If we waited until enable() to do
+* this, things like panel preparation would not be able to send
+* commands over DSI.
+*/
+   ret = clk_prepare_enable(dsi->grf_clk);
+   if (ret) {
+   DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+   return ret;
+   }
+
+   dw_mipi_dsi_rockchip_config(dsi);
+   if (dsi->slave)
+   dw_mipi_dsi_rockchip_config(dsi->slave);
+
+   clk_disable_unprepare(dsi->grf_clk);
+
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
-- 
2.30.0



[RESEND PATCH] drm/rockchip: dsi: remove extra component_del() call

2021-04-18 Thread Thomas Hebb
commit cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support") added
this devcnt field and call to component_del(). However, these both
appear to be erroneous changes left over from an earlier version of the
patch. In the version merged, nothing ever modifies devcnt, meaning
component_del() runs unconditionally and in addition to the
component_del() calls in dw_mipi_dsi_rockchip_host_detach(). The second
call fails to delete anything and produces a warning in dmesg.

If we look at the previous version of the patch[1], however, we see that
it had logic to calculate devcnt and call component_add() in certain
situations. This was removed in v6, and the fact that the deletion code
was not appears to have been an oversight.

[1] 
https://patchwork.kernel.org/project/dri-devel/patch/20180821140515.22246-8-he...@sntech.de/

Fixes: cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support")
Cc: sta...@vger.kernel.org
Signed-off-by: Thomas Hebb 
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 24a71091759c..8cc81d5b82f0 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -243,7 +243,6 @@ struct dw_mipi_dsi_rockchip {
struct dw_mipi_dsi *dmd;
const struct rockchip_dw_dsi_chip_data *cdata;
struct dw_mipi_dsi_plat_data pdata;
-   int devcnt;
 };
 
 struct dphy_pll_parameter_map {
@@ -1121,9 +1120,6 @@ static int dw_mipi_dsi_rockchip_remove(struct 
platform_device *pdev)
 {
struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
 
-   if (dsi->devcnt == 0)
-   component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
-
dw_mipi_dsi_remove(dsi->dmd);
 
return 0;
-- 
2.30.0



[PATCH] z3fold: prevent reclaim/free race for headless pages

2021-03-11 Thread Thomas Hebb
commit ca0246bb97c2 ("z3fold: fix possible reclaim races") introduced
the PAGE_CLAIMED flag "to avoid racing on a z3fold 'headless' page
release." By atomically testing and setting the bit in each of
z3fold_free() and z3fold_reclaim_page(), a double-free was avoided.

However, commit dcf5aedb24f8 ("z3fold: stricter locking and more careful
reclaim") appears to have unintentionally broken this behavior by moving
the PAGE_CLAIMED check in z3fold_reclaim_page() to after the page lock
gets taken, which only happens for non-headless pages. For headless
pages, the check is now skipped entirely and races can occur again.

I have observed such a race on my system:

page:ffbd76b7 refcount:0 mapcount:0 mapping: 
index:0x0 pfn:0x165316
flags: 0x200()
raw: 0200 ea0004535f48 8881d553a170 
raw:  0011  
page dumped because: VM_BUG_ON_PAGE(page_ref_count(page) == 0)
[ cut here ]
kernel BUG at include/linux/mm.h:707!
invalid opcode:  [#1] PREEMPT SMP KASAN PTI
CPU: 2 PID: 291928 Comm: kworker/2:0 Tainted: GB 
5.10.7-arch1-1-kasan #1
Hardware name: Gigabyte Technology Co., Ltd. H97N-WIFI/H97N-WIFI, BIOS F9b 
03/03/2016
Workqueue: zswap-shrink shrink_worker
RIP: 0010:__free_pages+0x10a/0x130
Code: c1 e7 06 48 01 ef 45 85 e4 74 d1 44 89 e6 31 d2 41 83 ec 01 e8 e7 b0 
ff ff eb da 48 c7 c6 e0 32 91 88 48 89 ef e8 a6 89 f8 ff <0f> 0b 4c 89 e7 e8 fc 
79 07 00 e9 33 ff ff ff 48 89 ef e8 ff 79 07
RSP: :88819a2ffb98 EFLAGS: 00010296
RAX:  RBX: ea000594c5a8 RCX: 
RDX: 1d4000b298b7 RSI:  RDI: ea000594c5b8
RBP: ea000594c580 R08: 003e R09: 8881d5520bbb
R10: ed103aaa4177 R11: 0001 R12: ea000594c5b4
R13:  R14: 888165316000 R15: ea000594c588
FS:  () GS:8881d550() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 7f7c8c3654d8 CR3: 000103f42004 CR4: 001706e0
Call Trace:
 z3fold_zpool_shrink+0x9b6/0x1240
 ? sugov_update_single+0x357/0x990
 ? sched_clock+0x5/0x10
 ? sched_clock_cpu+0x18/0x180
 ? z3fold_zpool_map+0x490/0x490
 ? _raw_spin_lock_irq+0x88/0xe0
 shrink_worker+0x35/0x90
 process_one_work+0x70c/0x1210
 ? pwq_dec_nr_in_flight+0x15b/0x2a0
 worker_thread+0x539/0x1200
 ? __kthread_parkme+0x73/0x120
 ? rescuer_thread+0x1000/0x1000
 kthread+0x330/0x400
 ? __kthread_bind_mask+0x90/0x90
 ret_from_fork+0x22/0x30
Modules linked in: rfcomm ebtable_filter ebtables ip6table_filter 
ip6_tables iptable_filter ccm algif_aead des_generic libdes ecb algif_skcipher 
cmac bnep md4 algif_hash af_alg vfat fat intel_rapl_msr intel_rapl_common 
x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iwlmvm 
hid_logitech_hidpp kvm at24 mac80211 snd_hda_codec_realtek iTCO_wdt 
snd_hda_codec_generic intel_pmc_bxt snd_hda_codec_hdmi ledtrig_audio 
iTCO_vendor_support mei_wdt mei_hdcp snd_hda_intel snd_intel_dspcfg libarc4 
soundwire_intel irqbypass iwlwifi soundwire_generic_allocation rapl 
soundwire_cadence intel_cstate snd_hda_codec intel_uncore btusb joydev mousedev 
snd_usb_audio pcspkr btrtl uvcvideo nouveau btbcm i2c_i801 btintel snd_hda_core 
videobuf2_vmalloc i2c_smbus snd_usbmidi_lib videobuf2_memops bluetooth 
snd_hwdep soundwire_bus snd_soc_rt5640 videobuf2_v4l2 cfg80211 snd_soc_rl6231 
videobuf2_common snd_rawmidi lpc_ich alx videodev mdio snd_seq_device 
snd_soc_core mc ecdh_generic mxm_wmi mei_me
 hid_logitech_dj wmi snd_compress e1000e ac97_bus mei ttm rfkill 
snd_pcm_dmaengine ecc snd_pcm snd_timer snd soundcore mac_hid acpi_pad 
pkcs8_key_parser it87 hwmon_vid crypto_user fuse ip_tables x_tables ext4 
crc32c_generic crc16 mbcache jbd2 dm_crypt cbc encrypted_keys trusted tpm 
rng_core usbhid dm_mod crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel aesni_intel crypto_simd cryptd glue_helper xhci_pci 
xhci_pci_renesas i915 video intel_gtt i2c_algo_bit drm_kms_helper syscopyarea 
sysfillrect sysimgblt fb_sys_fops cec drm agpgart
---[ end trace 126d646fc3dc0ad8 ]---

To fix the issue, re-add the earlier test and set in the case where we
have a headless page.

Fixes: dcf5aedb24f8 ("z3fold: stricter locking and more careful reclaim")
Cc: sta...@vger.kernel.org
Signed-off-by: Thomas Hebb 
---

 mm/z3fold.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/mm/z3fold.c b/mm/z3fold.c
index 0152ad9931a8..8ae944eeb8e2 100644
--- a/mm/z3fold.c
+++ b/mm/z3fold.c
@@ -1350,8 +1350,22 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, 
unsigned int retries)
page = list_entry(pos, struct p

[RFC PATCH] z3fold: prevent reclaim/free race for headless pages

2021-02-16 Thread Thomas Hebb
commit ca0246bb97c2 ("z3fold: fix possible reclaim races") introduced
the PAGE_CLAIMED flag "to avoid racing on a z3fold 'headless' page
release." By atomically testing and setting the bit in each of
z3fold_free() and z3fold_reclaim_page(), a double-free was avoided.

However, commit 746d179b0e66 ("z3fold: stricter locking and more careful
reclaim") appears to have unintentionally broken this behavior by moving
the PAGE_CLAIMED check in z3fold_reclaim_page() to after the page lock
gets taken, which only happens for non-headless pages. For headless
pages, the check is now skipped entirely and races can occur again.

I have observed such a race on my system:

page:ffbd76b7 refcount:0 mapcount:0 mapping: 
index:0x0 pfn:0x165316
flags: 0x200()
raw: 0200 ea0004535f48 8881d553a170 
raw:  0011  
page dumped because: VM_BUG_ON_PAGE(page_ref_count(page) == 0)
[ cut here ]
kernel BUG at include/linux/mm.h:707!
invalid opcode:  [#1] PREEMPT SMP KASAN PTI
CPU: 2 PID: 291928 Comm: kworker/2:0 Tainted: GB 
5.10.7-arch1-1-kasan #1
Hardware name: Gigabyte Technology Co., Ltd. H97N-WIFI/H97N-WIFI, BIOS F9b 
03/03/2016
Workqueue: zswap-shrink shrink_worker
RIP: 0010:__free_pages+0x10a/0x130
Code: c1 e7 06 48 01 ef 45 85 e4 74 d1 44 89 e6 31 d2 41 83 ec 01 e8 e7 b0 
ff ff eb da 48 c7 c6 e0 32 91 88 48 89 ef e8 a6 89 f8 ff <0f> 0b 4c 89 e7 e8 fc 
79 07 00 e9 33 ff ff ff 48 89 ef e8 ff 79 07
RSP: :88819a2ffb98 EFLAGS: 00010296
RAX:  RBX: ea000594c5a8 RCX: 
RDX: 1d4000b298b7 RSI:  RDI: ea000594c5b8
RBP: ea000594c580 R08: 003e R09: 8881d5520bbb
R10: ed103aaa4177 R11: 0001 R12: ea000594c5b4
R13:  R14: 888165316000 R15: ea000594c588
FS:  () GS:8881d550() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 7f7c8c3654d8 CR3: 000103f42004 CR4: 001706e0
Call Trace:
 z3fold_zpool_shrink+0x9b6/0x1240
 ? sugov_update_single+0x357/0x990
 ? sched_clock+0x5/0x10
 ? sched_clock_cpu+0x18/0x180
 ? z3fold_zpool_map+0x490/0x490
 ? _raw_spin_lock_irq+0x88/0xe0
 shrink_worker+0x35/0x90
 process_one_work+0x70c/0x1210
 ? pwq_dec_nr_in_flight+0x15b/0x2a0
 worker_thread+0x539/0x1200
 ? __kthread_parkme+0x73/0x120
 ? rescuer_thread+0x1000/0x1000
 kthread+0x330/0x400
 ? __kthread_bind_mask+0x90/0x90
 ret_from_fork+0x22/0x30
Modules linked in: rfcomm ebtable_filter ebtables ip6table_filter 
ip6_tables iptable_filter ccm algif_aead des_generic libdes ecb algif_skcipher 
cmac bnep md4 algif_hash af_alg vfat fat intel_rapl_msr intel_rapl_common 
x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iwlmvm 
hid_logitech_hidpp kvm at24 mac80211 snd_hda_codec_realtek iTCO_wdt 
snd_hda_codec_generic intel_pmc_bxt snd_hda_codec_hdmi ledtrig_audio 
iTCO_vendor_support mei_wdt mei_hdcp snd_hda_intel snd_intel_dspcfg libarc4 
soundwire_intel irqbypass iwlwifi soundwire_generic_allocation rapl 
soundwire_cadence intel_cstate snd_hda_codec intel_uncore btusb joydev mousedev 
snd_usb_audio pcspkr btrtl uvcvideo nouveau btbcm i2c_i801 btintel snd_hda_core 
videobuf2_vmalloc i2c_smbus snd_usbmidi_lib videobuf2_memops bluetooth 
snd_hwdep soundwire_bus snd_soc_rt5640 videobuf2_v4l2 cfg80211 snd_soc_rl6231 
videobuf2_common snd_rawmidi lpc_ich alx videodev mdio snd_seq_device 
snd_soc_core mc ecdh_generic mxm_wmi mei_me
 hid_logitech_dj wmi snd_compress e1000e ac97_bus mei ttm rfkill 
snd_pcm_dmaengine ecc snd_pcm snd_timer snd soundcore mac_hid acpi_pad 
pkcs8_key_parser it87 hwmon_vid crypto_user fuse ip_tables x_tables ext4 
crc32c_generic crc16 mbcache jbd2 dm_crypt cbc encrypted_keys trusted tpm 
rng_core usbhid dm_mod crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel aesni_intel crypto_simd cryptd glue_helper xhci_pci 
xhci_pci_renesas i915 video intel_gtt i2c_algo_bit drm_kms_helper syscopyarea 
sysfillrect sysimgblt fb_sys_fops cec drm agpgart
---[ end trace 126d646fc3dc0ad8 ]---

To fix the issue, re-add the earlier test and set in the case where we
have a headless page.

Fixes: 746d179b0e66 ("z3fold: stricter locking and more careful reclaim")
Signed-off-by: Thomas Hebb 
---
I have NOT tested this patch yet beyond compiling it. If the approach
seems good, I'll test it on my system for a period of several days and
see if I can reproduce the crash before sending a v1.

 mm/z3fold.c | 16 +++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/mm/z3fold.c b/mm/z3fold.c
index 0152ad9931a8..8ae944eeb8e2 100644
--- a/mm

[PATCH] hwmon: (dell-smm) Add XPS 15 L502X to fan control blacklist

2021-01-23 Thread Thomas Hebb
It has been reported[0] that the Dell XPS 15 L502X exhibits similar
freezing behavior to the other systems[1] on this blacklist. The issue
was exposed by a prior change of mine to automatically load
dell_smm_hwmon on a wider set of XPS models. To fix the regression, add
this model to the blacklist.

[0] https://bugzilla.kernel.org/show_bug.cgi?id=211081
[1] https://bugzilla.kernel.org/show_bug.cgi?id=195751

Fixes: b8a13e5e8f37 ("hwmon: (dell-smm) Use one DMI match for all XPS models")
Cc: sta...@vger.kernel.org
Reported-by: Bob Hepple 
Tested-by: Bob Hepple 
Signed-off-by: Thomas Hebb 
---

 drivers/hwmon/dell-smm-hwmon.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index ec448f5f2dc3..73b9db9e3aab 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -1159,6 +1159,13 @@ static struct dmi_system_id 
i8k_blacklist_fan_support_dmi_table[] __initdata = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"),
},
},
+   {
+   .ident = "Dell XPS 15 L502X",
+   .matches = {
+   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+   DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Dell System XPS 
L502X"),
+   },
+   },
{ }
 };
 
-- 
2.30.0



[RESEND PATCH] drm/rockchip: dsi: move all lane config except LCDC mux to bind()

2020-12-13 Thread Thomas Hebb
When we first enable the DSI encoder, we currently program some per-chip
configuration that we look up in rk3399_chip_data based on the device
tree compatible we match. This data configures various parameters of the
MIPI lanes, including on RK3399 whether DSI1 is slaved to DSI0 in a
dual-mode configuration. It also selects which LCDC (i.e. VOP) to scan
out from.

This causes a problem in RK3399 dual-mode configurations, though: panel
prepare() callbacks run before the encoder gets enabled and expect to be
able to write commands to the DSI bus, but the bus isn't fully
functional until the lane and master/slave configuration have been
programmed. As a result, dual-mode panels (and possibly others too) fail
to turn on when the rockchipdrm driver is initially loaded.

Because the LCDC mux is the only thing we don't know until enable time
(and is the only thing that can ever change), we can actually move most
of the initialization to bind() and get it out of the way early. That's
what this change does. (Rockchip's 4.4 BSP kernel does it in mode_set(),
which also avoids the issue, but bind() seems like the more correct
place to me.)

Tested on a Google Scarlet board (Acer Chromebook Tab 10), which has a
Kingdisplay KD097D04 dual-mode panel. Prior to this change, the panel's
backlight would turn on but no image would appear when initially loading
rockchipdrm. If I kept rockchipdrm loaded and reloaded the panel driver,
it would come on. With this change, the panel successfully turns on
during initial rockchipdrm load as expected.

Fixes: 2d4f7bdafd70 ("drm/rockchip: dsi: migrate to use dw-mipi-dsi bridge 
driver")
Signed-off-by: Thomas Hebb 
---
Resending since I wasn't subscribed to dri-devel

 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 36 ++-
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index ce044db8c97e..d0c9610ad220 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -691,13 +691,8 @@ static const struct dw_mipi_dsi_phy_ops 
dw_mipi_dsi_rockchip_phy_ops = {
.get_timing = dw_mipi_dsi_phy_get_timing,
 };
 
-static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
-   int mux)
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
 {
-   if (dsi->cdata->lcdsel_grf_reg)
-   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
-   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
-
if (dsi->cdata->lanecfg1_grf_reg)
regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
  dsi->cdata->lanecfg1);
@@ -711,6 +706,13 @@ static void dw_mipi_dsi_rockchip_config(struct 
dw_mipi_dsi_rockchip *dsi,
  dsi->cdata->enable);
 }
 
+static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
+   int mux)
+{
+   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+}
+
 static int
 dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 struct drm_crtc_state *crtc_state,
@@ -766,9 +768,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder 
*encoder)
return;
}
 
-   dw_mipi_dsi_rockchip_config(dsi, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
if (dsi->slave)
-   dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);
 
clk_disable_unprepare(dsi->grf_clk);
 }
@@ -922,6 +924,24 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
return ret;
}
 
+   /*
+* With the GRF clock running, write lane and dual-mode configurations
+* that won't change immediately. If we waited until enable() to do
+* this, things like panel preparation would not be able to send
+* commands over DSI.
+*/
+   ret = clk_prepare_enable(dsi->grf_clk);
+   if (ret) {
+   DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+   return ret;
+   }
+
+   dw_mipi_dsi_rockchip_config(dsi);
+   if (dsi->slave)
+   dw_mipi_dsi_rockchip_config(dsi->slave);
+
+   clk_disable_unprepare(dsi->grf_clk);
+
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
-- 
2.29.2



[RESEND PATCH] drm/rockchip: dsi: remove extra component_del() call

2020-12-13 Thread Thomas Hebb
commit cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support") added
this devcnt field and call to component_del(). However, these both
appear to be erroneous changes left over from an earlier version of the
patch. In the version merged, nothing ever modifies devcnt, meaning
component_del() runs unconditionally and in addition to the
component_del() calls in dw_mipi_dsi_rockchip_host_detach(). The second
call fails to delete anything and produces a warning in dmesg.

If we look at the previous version of the patch[1], however, we see that
it had logic to calculate devcnt and call component_add() in certain
situations. This was removed in v6, and the fact that the deletion code
was not appears to have been an oversight.

[1] 
https://patchwork.kernel.org/project/dri-devel/patch/20180821140515.22246-8-he...@sntech.de/

Fixes: cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support")
Cc: sta...@vger.kernel.org
Signed-off-by: Thomas Hebb 
---
Resending since I wasn't subscribed to dri-devel

 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 542dcf7eddd6..ce044db8c97e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -243,7 +243,6 @@ struct dw_mipi_dsi_rockchip {
struct dw_mipi_dsi *dmd;
const struct rockchip_dw_dsi_chip_data *cdata;
struct dw_mipi_dsi_plat_data pdata;
-   int devcnt;
 };
 
 struct dphy_pll_parameter_map {
@@ -1121,9 +1120,6 @@ static int dw_mipi_dsi_rockchip_remove(struct 
platform_device *pdev)
 {
struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
 
-   if (dsi->devcnt == 0)
-   component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
-
dw_mipi_dsi_remove(dsi->dmd);
 
return 0;
-- 
2.29.2



[PATCH] drm/rockchip: dsi: move all lane config except LCDC mux to bind()

2020-12-13 Thread Thomas Hebb
When we first enable the DSI encoder, we currently program some per-chip
configuration that we look up in rk3399_chip_data based on the device
tree compatible we match. This data configures various parameters of the
MIPI lanes, including on RK3399 whether DSI1 is slaved to DSI0 in a
dual-mode configuration. It also selects which LCDC (i.e. VOP) to scan
out from.

This causes a problem in RK3399 dual-mode configurations, though: panel
prepare() callbacks run before the encoder gets enabled and expect to be
able to write commands to the DSI bus, but the bus isn't fully
functional until the lane and master/slave configuration have been
programmed. As a result, dual-mode panels (and possibly others too) fail
to turn on when the rockchipdrm driver is initially loaded.

Because the LCDC mux is the only thing we don't know until enable time
(and is the only thing that can ever change), we can actually move most
of the initialization to bind() and get it out of the way early. That's
what this change does. (Rockchip's 4.4 BSP kernel does it in mode_set(),
which also avoids the issue, but bind() seems like the more correct
place to me.)

Tested on a Google Scarlet board (Acer Chromebook Tab 10), which has a
Kingdisplay KD097D04 dual-mode panel. Prior to this change, the panel's
backlight would turn on but no image would appear when initially loading
rockchipdrm. If I kept rockchipdrm loaded and reloaded the panel driver,
it would come on. With this change, the panel successfully turns on
during initial rockchipdrm load as expected.

Fixes: 2d4f7bdafd70 ("drm/rockchip: dsi: migrate to use dw-mipi-dsi bridge 
driver")
Signed-off-by: Thomas Hebb 
---

 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 36 ++-
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index ce044db8c97e..d0c9610ad220 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -691,13 +691,8 @@ static const struct dw_mipi_dsi_phy_ops 
dw_mipi_dsi_rockchip_phy_ops = {
.get_timing = dw_mipi_dsi_phy_get_timing,
 };
 
-static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
-   int mux)
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
 {
-   if (dsi->cdata->lcdsel_grf_reg)
-   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
-   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
-
if (dsi->cdata->lanecfg1_grf_reg)
regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
  dsi->cdata->lanecfg1);
@@ -711,6 +706,13 @@ static void dw_mipi_dsi_rockchip_config(struct 
dw_mipi_dsi_rockchip *dsi,
  dsi->cdata->enable);
 }
 
+static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
+   int mux)
+{
+   regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+   mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+}
+
 static int
 dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 struct drm_crtc_state *crtc_state,
@@ -766,9 +768,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder 
*encoder)
return;
}
 
-   dw_mipi_dsi_rockchip_config(dsi, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
if (dsi->slave)
-   dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+   dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);
 
clk_disable_unprepare(dsi->grf_clk);
 }
@@ -922,6 +924,24 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
return ret;
}
 
+   /*
+* With the GRF clock running, write lane and dual-mode configurations
+* that won't change immediately. If we waited until enable() to do
+* this, things like panel preparation would not be able to send
+* commands over DSI.
+*/
+   ret = clk_prepare_enable(dsi->grf_clk);
+   if (ret) {
+   DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+   return ret;
+   }
+
+   dw_mipi_dsi_rockchip_config(dsi);
+   if (dsi->slave)
+   dw_mipi_dsi_rockchip_config(dsi->slave);
+
+   clk_disable_unprepare(dsi->grf_clk);
+
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
-- 
2.29.2



[PATCH] ASoC: dapm: remove widget from dirty list on free

2020-12-12 Thread Thomas Hebb
A widget's "dirty" list_head, much like its "list" list_head, eventually
chains back to a list_head on the snd_soc_card itself. This means that
the list can stick around even after the widget (or all widgets) have
been freed. Currently, however, widgets that are in the dirty list when
freed remain there, corrupting the entire list and leading to memory
errors and undefined behavior when the list is next accessed or
modified.

I encountered this issue when a component failed to probe relatively
late in snd_soc_bind_card(), causing it to bail out and call
soc_cleanup_card_resources(), which eventually called
snd_soc_dapm_free() with widgets that were still dirty from when they'd
been added.

Fixes: db432b414e20 ("ASoC: Do DAPM power checks only for widgets changed since 
last run")
Cc: sta...@vger.kernel.org
Signed-off-by: Thomas Hebb 
---

 sound/soc/soc-dapm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7f87b449f950..148c095df27b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2486,6 +2486,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget 
*w)
enum snd_soc_dapm_direction dir;
 
list_del(&w->list);
+   list_del(&w->dirty);
/*
 * remove source and sink paths associated to this widget.
 * While removing the path, remove reference to it from both
-- 
2.29.2



[PATCH] drm/rockchip: dsi: remove extra component_del() call

2020-12-12 Thread Thomas Hebb
commit cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support") added
this devcnt field and call to component_del(). However, these both
appear to be erroneous changes left over from an earlier version of the
patch. In the version merged, nothing ever modifies devcnt, meaning
component_del() runs unconditionally and in addition to the
component_del() calls in dw_mipi_dsi_rockchip_host_detach(). The second
call fails to delete anything and produces a warning in dmesg.

If we look at the previous version of the patch[1], however, we see that
it had logic to calculate devcnt and call component_add() in certain
situations. This was removed in v6, and the fact that the deletion code
was not appears to have been an oversight.

[1] 
https://patchwork.kernel.org/project/dri-devel/patch/20180821140515.22246-8-he...@sntech.de/

Fixes: cf6d100dd238 ("drm/rockchip: dsi: add dual mipi support")
Cc: sta...@vger.kernel.org
Signed-off-by: Thomas Hebb 
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 542dcf7eddd6..ce044db8c97e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -243,7 +243,6 @@ struct dw_mipi_dsi_rockchip {
struct dw_mipi_dsi *dmd;
const struct rockchip_dw_dsi_chip_data *cdata;
struct dw_mipi_dsi_plat_data pdata;
-   int devcnt;
 };
 
 struct dphy_pll_parameter_map {
@@ -1121,9 +1120,6 @@ static int dw_mipi_dsi_rockchip_remove(struct 
platform_device *pdev)
 {
struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
 
-   if (dsi->devcnt == 0)
-   component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
-
dw_mipi_dsi_remove(dsi->dmd);
 
return 0;
-- 
2.29.2



[PATCH 3/3] libsubcmd: Get rid of useless conditional assignments

2020-07-26 Thread Thomas Hebb
Conditional assignment does not work properly for variables that Make
implicitly sets, among which are CC and AR. To quote
tools/scripts/Makefile.include, which handles this properly:

  # Makefiles suck: This macro sets a default value of $(2) for the
  # variable named by $(1), unless the variable has been set by
  # environment or command line. This is necessary for CC and AR
  # because make sets default values, so the simpler ?= approach
  # won't work as expected.

In other words, the conditional assignments will not run even if the
variables are not overridden in the environment; Make will set CC and AR
to default values when it starts[1], meaning they're not empty by the
time the conditional assignments are evaluated.

Since the assignments never run, we can just get rid of them. CC and AR
are already set properly by Makefile.include using the macro mentioned
in the quote above. In addition, we can get rid of the LD assignment,
because it's also set by Makefile.include.

[1] https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html

Signed-off-by: Thomas Hebb 
---

 tools/lib/subcmd/Makefile | 4 
 1 file changed, 4 deletions(-)

diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile
index 1c777a72bb39..5f2058a6a1ce 100644
--- a/tools/lib/subcmd/Makefile
+++ b/tools/lib/subcmd/Makefile
@@ -9,10 +9,6 @@ srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
 endif
 
-CC ?= $(CROSS_COMPILE)gcc
-LD ?= $(CROSS_COMPILE)ld
-AR ?= $(CROSS_COMPILE)ar
-
 RM = rm -f
 
 MAKEFLAGS += --no-print-directory
-- 
2.27.0



[PATCH 1/3] tools build feature: Use CC and CXX from parent

2020-07-26 Thread Thomas Hebb
commit c8c188679ccf ("tools build: Use the same CC for feature detection
and actual build") changed these assignments from unconditional (:=) to
conditional (?=) so that they wouldn't clobber values from the
environment. However, conditional assignment does not work properly for
variables that Make implicitly sets, among which are CC and CXX. To
quote tools/scripts/Makefile.include, which handles this properly:

  # Makefiles suck: This macro sets a default value of $(2) for the
  # variable named by $(1), unless the variable has been set by
  # environment or command line. This is necessary for CC and AR
  # because make sets default values, so the simpler ?= approach
  # won't work as expected.

In other words, the conditional assignments will not run even if the
variables are not overridden in the environment; Make will set CC to
"cc" and CXX to "g++" when it starts[1], meaning the variables are not
empty by the time the conditional assignments are evaluated. This breaks
cross-compilation when CROSS_COMPILE is set but CC isn't, since "cc"
gets used for feature detection instead of the cross compiler (and
likewise for CXX).

To fix the issue, just pass down the values of CC and CXX computed by
the parent Makefile, which gets included by the Makefile that actually
builds whatever we're detecting features for and so is guaranteed to
have good values. This is a better solution anyway, since it means we
aren't trying to replicate the logic of the parent build system and so
don't risk it getting out of sync.

Leave PKG_CONFIG alone, since 1) there's no common logic to compute it
in Makefile.include, and 2) it's not an implicit variable, so
conditional assignment works properly.

[1] https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html

Fixes: c8c188679ccf ("tools build: Use the same CC for feature detection and 
actual build")
Signed-off-by: Thomas Hebb 
---

 tools/build/Makefile.feature | 2 +-
 tools/build/feature/Makefile | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index cb152370fdef..774f0b0ca28a 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -8,7 +8,7 @@ endif
 
 feature_check = $(eval $(feature_check_code))
 define feature_check_code
-  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) 
CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" 
CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) 
$(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin 
>/dev/null 2>/dev/null && echo 1 || echo 0)
+  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CC=$(CC) 
CXX=$(CXX) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" 
CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) 
$(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin 
>/dev/null 2>/dev/null && echo 1 || echo 0)
 endef
 
 feature_set = $(eval $(feature_set_code))
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index b1f0321180f5..93b590d81209 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -74,8 +74,6 @@ FILES=  \
 
 FILES := $(addprefix $(OUTPUT),$(FILES))
 
-CC ?= $(CROSS_COMPILE)gcc
-CXX ?= $(CROSS_COMPILE)g++
 PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
 LLVM_CONFIG ?= llvm-config
 CLANG ?= clang
-- 
2.27.0



[PATCH 2/3] tools lib api: Get rid of useless conditional assignments

2020-07-26 Thread Thomas Hebb
Conditional assignment does not work properly for variables that Make
implicitly sets, among which are CC and AR. To quote
tools/scripts/Makefile.include, which handles this properly:

  # Makefiles suck: This macro sets a default value of $(2) for the
  # variable named by $(1), unless the variable has been set by
  # environment or command line. This is necessary for CC and AR
  # because make sets default values, so the simpler ?= approach
  # won't work as expected.

In other words, the conditional assignments will not run even if the
variables are not overridden in the environment; Make will set CC and AR
to default values when it starts[1], meaning they're not empty by the
time the conditional assignments are evaluated.

Since the assignments never run, we can just get rid of them. CC and AR
are already set properly by Makefile.include using the macro mentioned
in the quote above. In addition, we can get rid of the LD assignment,
because it's also set by Makefile.include.

[1] https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html

Signed-off-by: Thomas Hebb 
---

 tools/lib/api/Makefile | 4 
 1 file changed, 4 deletions(-)

diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile
index a13e9c7f1fc5..5f2e3f8acbd0 100644
--- a/tools/lib/api/Makefile
+++ b/tools/lib/api/Makefile
@@ -9,10 +9,6 @@ srctree := $(patsubst %/,%,$(dir $(srctree)))
 #$(info Determined 'srctree' to be $(srctree))
 endif
 
-CC ?= $(CROSS_COMPILE)gcc
-AR ?= $(CROSS_COMPILE)ar
-LD ?= $(CROSS_COMPILE)ld
-
 MAKEFLAGS += --no-print-directory
 
 LIBFILE = $(OUTPUT)libapi.a
-- 
2.27.0



[PATCH v2] pwm: berlin: Don't use broken prescaler values

2018-06-06 Thread Thomas Hebb
The Berlin PWM driver is currently broken on at least BG2CD. The
symptoms manifest as a very non-linear and erratic mapping from the duty
cycle configured in software to the duty cycle produced by hardware.

The cause of the bug is software's configuration of the prescaler, and
in particular its usage of the six prescaler values between the minimum
value of 1 and the maximum value of 4096. As it turns out, these six
values do not actually slow down the PWM clock; rather, they emulate
slowing down the clock by internally multiplying the value of TCNT.

This would be a fine trick, if not for the fact that the internal,
scaled TCNT value has no extra bits beyond the 16 already exposed to
software in the register. What this means is that, for a prescaler of 4,
the software must ensure that the top two bits of TCNT are not set,
because hardware will chop them off; for a prescaler of 8, the top three
bits must not be set, and so forth. Software does not currently ensure
this, resulting in a TCNT several orders of magnitude lower than
intended any time one of those six prescalers are selected.

Because hardware chops off the high bits in its internal shift, the
middle six prescalers don't actually allow *anything* that the first
doesn't. In fact, they are strictly worse than the first, since the
internal shift of TCNT prevents software from setting the low bits,
decreasing the resolution, without providing any extra high bits.

By skipping the useless prescalers entirely, this patch both fixes the
driver's behavior and increases its performance (since, when the 4096
prescaler is selected, it now does only a single shift rather than the
seven successive divisions it did before).

Tested on BG2CD.

Signed-off-by: Thomas Hebb 
---
 drivers/pwm/pwm-berlin.c | 45 ++--
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index 771859aca4be..7c8d6a168ceb 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -21,8 +21,18 @@
 #define BERLIN_PWM_EN  0x0
 #define  BERLIN_PWM_ENABLE BIT(0)
 #define BERLIN_PWM_CONTROL 0x4
-#define  BERLIN_PWM_PRESCALE_MASK  0x7
-#define  BERLIN_PWM_PRESCALE_MAX   4096
+/*
+ * The prescaler claims to support 8 different moduli, configured using the
+ * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64,
+ * 256, 1024, and 4096.)  However, the moduli from 4 to 1024 appear to be
+ * implemented by internally shifting TCNT left without adding additional
+ * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff;
+ * for 8, 0x1fff; and so on. This means that those moduli are entirely
+ * useless, as we could just do the shift ourselves. The 4096 modulus is
+ * implemented with a real prescaler, so we do use that, but we treat it
+ * as a flag instead of pretending the modulus is actually configurable.
+ */
+#define  BERLIN_PWM_PRESCALE_4096  0x7
 #define  BERLIN_PWM_INVERT_POLARITYBIT(3)
 #define BERLIN_PWM_DUTY0x8
 #define BERLIN_PWM_TCNT0xc
@@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip 
*to_berlin_pwm_chip(struct pwm_chip *chip)
return container_of(chip, struct berlin_pwm_chip, chip);
 }
 
-static const u32 prescaler_table[] = {
-   1, 4, 8, 16, 64, 256, 1024, 4096
-};
-
 static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
   unsigned int channel, unsigned long offset)
 {
@@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct 
pwm_device *pwm_dev,
 int duty_ns, int period_ns)
 {
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
-   unsigned int prescale;
+   bool prescale_4096 = false;
u32 value, duty, period;
-   u64 cycles, tmp;
+   u64 cycles;
 
cycles = clk_get_rate(pwm->clk);
cycles *= period_ns;
do_div(cycles, NSEC_PER_SEC);
 
-   for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
-   tmp = cycles;
-   do_div(tmp, prescaler_table[prescale]);
+   if (cycles > BERLIN_PWM_MAX_TCNT) {
+   prescale_4096 = true;
+   cycles >>= 12; // Prescaled by 4096
 
-   if (tmp <= BERLIN_PWM_MAX_TCNT)
-   break;
+   if (cycles > BERLIN_PWM_MAX_TCNT)
+   return -ERANGE;
}
 
-   if (tmp > BERLIN_PWM_MAX_TCNT)
-   return -ERANGE;
-
-   period = tmp;
-   cycles = tmp * duty_ns;
+   period = cycles;
+   cycles *= duty_ns;
do_div(cycles, period_ns);
duty = cycles;
 
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
-   value &= ~BERLIN_PWM_PRESCALE_MASK;
-   value |= prescale;
+   if (prescale_4096

[PATCH RESEND] pwm: berlin: Don't use broken prescaler values

2018-06-04 Thread Thomas Hebb
Six of the eight prescaler values available for Berlin PWM are not true
prescalers but rather internal shifts that throw away the high bits of
TCNT. Currently, we attempt to use those high bits, leading to erratic
behavior. Restrict the prescaler configurations we select to only the
two that respect the full range of TCNT.

Tested on BG2CD.

Signed-off-by: Thomas Hebb 
---
 drivers/pwm/pwm-berlin.c | 45 ++--
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index 771859aca4be..7c8d6a168ceb 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -21,8 +21,18 @@
 #define BERLIN_PWM_EN  0x0
 #define  BERLIN_PWM_ENABLE BIT(0)
 #define BERLIN_PWM_CONTROL 0x4
-#define  BERLIN_PWM_PRESCALE_MASK  0x7
-#define  BERLIN_PWM_PRESCALE_MAX   4096
+/*
+ * The prescaler claims to support 8 different moduli, configured using the
+ * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64,
+ * 256, 1024, and 4096.)  However, the moduli from 4 to 1024 appear to be
+ * implemented by internally shifting TCNT left without adding additional
+ * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff;
+ * for 8, 0x1fff; and so on. This means that those moduli are entirely
+ * useless, as we could just do the shift ourselves. The 4096 modulus is
+ * implemented with a real prescaler, so we do use that, but we treat it
+ * as a flag instead of pretending the modulus is actually configurable.
+ */
+#define  BERLIN_PWM_PRESCALE_4096  0x7
 #define  BERLIN_PWM_INVERT_POLARITYBIT(3)
 #define BERLIN_PWM_DUTY0x8
 #define BERLIN_PWM_TCNT0xc
@@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip 
*to_berlin_pwm_chip(struct pwm_chip *chip)
return container_of(chip, struct berlin_pwm_chip, chip);
 }
 
-static const u32 prescaler_table[] = {
-   1, 4, 8, 16, 64, 256, 1024, 4096
-};
-
 static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
   unsigned int channel, unsigned long offset)
 {
@@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct 
pwm_device *pwm_dev,
 int duty_ns, int period_ns)
 {
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
-   unsigned int prescale;
+   bool prescale_4096 = false;
u32 value, duty, period;
-   u64 cycles, tmp;
+   u64 cycles;
 
cycles = clk_get_rate(pwm->clk);
cycles *= period_ns;
do_div(cycles, NSEC_PER_SEC);
 
-   for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
-   tmp = cycles;
-   do_div(tmp, prescaler_table[prescale]);
+   if (cycles > BERLIN_PWM_MAX_TCNT) {
+   prescale_4096 = true;
+   cycles >>= 12; // Prescaled by 4096
 
-   if (tmp <= BERLIN_PWM_MAX_TCNT)
-   break;
+   if (cycles > BERLIN_PWM_MAX_TCNT)
+   return -ERANGE;
}
 
-   if (tmp > BERLIN_PWM_MAX_TCNT)
-   return -ERANGE;
-
-   period = tmp;
-   cycles = tmp * duty_ns;
+   period = cycles;
+   cycles *= duty_ns;
do_div(cycles, period_ns);
duty = cycles;
 
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
-   value &= ~BERLIN_PWM_PRESCALE_MASK;
-   value |= prescale;
+   if (prescale_4096)
+   value |= BERLIN_PWM_PRESCALE_4096;
+   else
+   value &= ~BERLIN_PWM_PRESCALE_4096;
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
 
berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
-- 
2.17.0



[PATCH] ARM: dts: berlin: switch to earlycon

2018-05-29 Thread Thomas Hebb
The Synopsys DesignWare 8250 UART in Berlin SoCs is now supported by
8250_early, so we can use earlycon for early console output instead
of earlyprintk, which requires an SoC-specific kernel.

Signed-off-by: Thomas Hebb 
---
 arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts| 2 +-
 arch/arm/boot/dts/berlin2cd-google-chromecast.dts | 2 +-
 arch/arm/boot/dts/berlin2q-marvell-dmp.dts| 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts 
b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
index 1c475796d17f..f98798bb684f 100644
--- a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
+++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
@@ -45,7 +45,7 @@
compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin";
 
chosen {
-   bootargs = "earlyprintk";
+   bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
 
diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts 
b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index ca24def0ce13..20f31cdeaf38 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -46,7 +46,7 @@
compatible = "google,chromecast", "marvell,berlin2cd", "marvell,berlin";
 
chosen {
-   bootargs = "earlyprintk";
+   bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
 
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts 
b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index 57aa5f8a7c77..9834e84a0797 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -49,7 +49,7 @@
};
 
chosen {
-   bootargs = "earlyprintk";
+   bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
 
-- 
2.17.0



[PATCH 2/2] ARM: dts: chromecast: use PWM for LEDs

2018-05-14 Thread Thomas Hebb
Control the Chromecast's two LEDs using PWM instead of GPIO pins. This
allows for variable brightness.

Signed-off-by: Thomas Hebb 
---
 .../boot/dts/berlin2cd-google-chromecast.dts  | 20 ++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts 
b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 54221f55bfa2..fb71e5436420 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -66,18 +66,21 @@
};
 
leds {
-   compatible = "gpio-leds";
+   compatible = "pwm-leds";
+   pinctrl-0 = <&ledpwm_pmux>;
+   pinctrl-names = "default";
 
white {
label = "white";
-   gpios = <&portc 1 GPIO_ACTIVE_HIGH>;
-   default-state = "keep";
+   pwms = <&pwm 0 60 0>;
+   max-brightness = <255>;
+   linux,default-trigger = "default-on";
};
 
red {
label = "red";
-   gpios = <&portc 2 GPIO_ACTIVE_HIGH>;
-   default-state = "keep";
+   pwms = <&pwm 1 60 0>;
+   max-brightness = <255>;
};
};
 };
@@ -96,3 +99,10 @@
 &usb_phy1 { status = "okay"; };
 
 &usb1 { status = "okay"; };
+
+&soc_pinctrl {
+   ledpwm_pmux: ledpwm-pmux {
+   groups = "G0";
+   function = "pwm";
+   };
+};
-- 
2.17.0



[PATCH 1/2] pwm: berlin: Don't use broken prescaler values

2018-05-14 Thread Thomas Hebb
Six of the eight prescaler values available for Berlin PWM are not true
prescalers but rather internal shifts that throw away the high bits of
TCNT. Currently, we attempt to use those high bits, leading to erratic
behavior. Restrict the prescaler configurations we select to only the
two that respect the full range of TCNT.

Tested on BG2CD.

Signed-off-by: Thomas Hebb 
---
 drivers/pwm/pwm-berlin.c | 45 ++--
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index 771859aca4be..7c8d6a168ceb 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -21,8 +21,18 @@
 #define BERLIN_PWM_EN  0x0
 #define  BERLIN_PWM_ENABLE BIT(0)
 #define BERLIN_PWM_CONTROL 0x4
-#define  BERLIN_PWM_PRESCALE_MASK  0x7
-#define  BERLIN_PWM_PRESCALE_MAX   4096
+/*
+ * The prescaler claims to support 8 different moduli, configured using the
+ * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64,
+ * 256, 1024, and 4096.)  However, the moduli from 4 to 1024 appear to be
+ * implemented by internally shifting TCNT left without adding additional
+ * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff;
+ * for 8, 0x1fff; and so on. This means that those moduli are entirely
+ * useless, as we could just do the shift ourselves. The 4096 modulus is
+ * implemented with a real prescaler, so we do use that, but we treat it
+ * as a flag instead of pretending the modulus is actually configurable.
+ */
+#define  BERLIN_PWM_PRESCALE_4096  0x7
 #define  BERLIN_PWM_INVERT_POLARITYBIT(3)
 #define BERLIN_PWM_DUTY0x8
 #define BERLIN_PWM_TCNT0xc
@@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip 
*to_berlin_pwm_chip(struct pwm_chip *chip)
return container_of(chip, struct berlin_pwm_chip, chip);
 }
 
-static const u32 prescaler_table[] = {
-   1, 4, 8, 16, 64, 256, 1024, 4096
-};
-
 static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
   unsigned int channel, unsigned long offset)
 {
@@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct 
pwm_device *pwm_dev,
 int duty_ns, int period_ns)
 {
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
-   unsigned int prescale;
+   bool prescale_4096 = false;
u32 value, duty, period;
-   u64 cycles, tmp;
+   u64 cycles;
 
cycles = clk_get_rate(pwm->clk);
cycles *= period_ns;
do_div(cycles, NSEC_PER_SEC);
 
-   for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
-   tmp = cycles;
-   do_div(tmp, prescaler_table[prescale]);
+   if (cycles > BERLIN_PWM_MAX_TCNT) {
+   prescale_4096 = true;
+   cycles >>= 12; // Prescaled by 4096
 
-   if (tmp <= BERLIN_PWM_MAX_TCNT)
-   break;
+   if (cycles > BERLIN_PWM_MAX_TCNT)
+   return -ERANGE;
}
 
-   if (tmp > BERLIN_PWM_MAX_TCNT)
-   return -ERANGE;
-
-   period = tmp;
-   cycles = tmp * duty_ns;
+   period = cycles;
+   cycles *= duty_ns;
do_div(cycles, period_ns);
duty = cycles;
 
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
-   value &= ~BERLIN_PWM_PRESCALE_MASK;
-   value |= prescale;
+   if (prescale_4096)
+   value |= BERLIN_PWM_PRESCALE_4096;
+   else
+   value &= ~BERLIN_PWM_PRESCALE_4096;
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
 
berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
-- 
2.17.0



[PATCH] ARM: dts: chromecast: override bad bootloader memory info

2018-05-14 Thread Thomas Hebb
On the Chromecast, the bootloader provides us with an ATAG_MEM of
start=0x0100 and size=0x3eff8000. This is clearly incorrect, as the
range given encompasses nearly a GiB but the Chromecast only has 512MiB
of RAM! Additionally, this causes the kernel to be decompressed at
0x8000, below the claimed beginning of RAM, and so the boot fails.

Since the existing ATAG parsing code runs before the kernel is even
decompressed and irrevocably patches the device tree, don't even try
to bypass it. Instead, use the "linux,usable-memory" property instead
of the "reg" property to define the real range. The ATAG code only
overwrites reg, but linux,usable-memory is checked first in the OF
driver, so the fact that reg gets changed makes no difference.

Signed-off-by: Thomas Hebb 
---
 arch/arm/boot/dts/berlin2cd-google-chromecast.dts | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts 
b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 20f31cdeaf38..54221f55bfa2 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -52,7 +52,17 @@
 
memory@0 {
device_type = "memory";
-   reg = <0x 0x2000>; /* 512 MB */
+
+   /*
+* We're using "linux,usable-memory" instead of "reg" here
+* because the (signed and encrypted) bootloader that shipped
+* with this device provides an incorrect memory range in
+* ATAG_MEM. Linux helpfully overrides the "reg" property with
+* data from the ATAG, so we can't specify the proper range
+* normally. Fortunately, this alternate property is checked
+* first by the OF driver, so we can (ab)use it instead.
+*/
+   linux,usable-memory = <0x 0x2000>; /* 512 MB */
};
 
leds {
-- 
2.17.0



[PATCH] Documentation: arm: clean up Marvell Berlin family info

2018-05-14 Thread Thomas Hebb
Remove dead links, make spacing consistent, and note that the family was
acquired by Synaptics in 2017.

Signed-off-by: Thomas Hebb 
---
 Documentation/arm/Marvell/README | 15 +++
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
index b5bb7f518840..56ada27c53be 100644
--- a/Documentation/arm/Marvell/README
+++ b/Documentation/arm/Marvell/README
@@ -302,19 +302,15 @@ Berlin family (Multimedia Solutions)
88DE3010, Armada 1000 (no Linux support)
Core:   Marvell PJ1 (ARMv5TE), Dual-core
Product Brief:  
http://www.marvell.com.cn/digital-entertainment/assets/armada_1000_pb.pdf
-   88DE3005, Armada 1500-mini
88DE3005, Armada 1500 Mini
Design name:BG2CD
Core:   ARM Cortex-A9, PL310 L2CC
-   Homepage:   
http://www.marvell.com/multimedia-solutions/armada-1500-mini/
-88DE3006, Armada 1500 Mini Plus
-Design name:BG2CDP
-Core:   Dual Core ARM Cortex-A7
-Homepage:   
http://www.marvell.com/multimedia-solutions/armada-1500-mini-plus/
+   88DE3006, Armada 1500 Mini Plus
+   Design name:BG2CDP
+   Core:   Dual Core ARM Cortex-A7
88DE3100, Armada 1500
Design name:BG2
Core:   Marvell PJ4B-MP (ARMv7), Tauros3 L2CC
-   Product Brief:  
http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
88DE3114, Armada 1500 Pro
Design name:BG2Q
Core:   Quad Core ARM Cortex-A9, PL310 L2CC
@@ -324,13 +320,16 @@ Berlin family (Multimedia Solutions)
88DE3218, ARMADA 1500 Ultra
Core:   ARM Cortex-A53
 
-  Homepage: http://www.marvell.com/multimedia-solutions/
+  Homepage: https://www.synaptics.com/products/multimedia-solutions
   Directory: arch/arm/mach-berlin
 
   Comments:
+
* This line of SoCs is based on Marvell Sheeva or ARM Cortex CPUs
  with Synopsys DesignWare (IRQ, GPIO, Timers, ...) and PXA IP (SDHCI, USB, 
ETH, ...).
 
+   * The Berlin family was acquired by Synaptics from Marvell in 2017.
+
 CPU Cores
 -
 
-- 
2.17.0



[PATCH] ath10k: search all IEs for variant before falling back

2018-02-21 Thread Thomas Hebb
commit f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file
extension") added a feature to ath10k that allows Board Data File
(BDF) conflicts between multiple devices that use the same device IDs
but have different calibration requirements to be resolved by allowing
a "variant" string to be stored in SMBIOS [and later device tree, added
by commit d06f26c5c8a4 ("ath10k: search DT for qcom,ath10k-calibration-
variant")] that gets appended to the ID stored in board-2.bin.

This original patch had a regression, however. Namely that devices with
a variant present in SMBIOS that didn't need custom BDFs could no longer
find the default BDF, which has no variant appended. The patch was
reverted and re-applied with a fix for this issue in commit 1657b8f84ed9
("search SMBIOS for OEM board file extension").

But the fix to fall back to a default BDF introduced another issue: the
driver currently parses IEs in board-2.bin one by one, and for each one
it first checks to see if it matches the ID with the variant appended.
If it doesn't, it checks to see if it matches the "fallback" ID with no
variant. If a matching BDF is found at any point during this search, the
search is terminated and that BDF is used. The issue is that it's very
possible (and is currently the case for board-2.bin files present in the
ath10k-firmware repository) for the default BDF to occur in an earlier
IE than the variant-specific BDF. In this case, the current code will
happily choose the default BDF even though a better-matching BDF is
present later in the file.

This patch fixes the issue by first searching the entire file for the ID
with variant, and searching for the fallback ID only if that search
fails. It also includes some code cleanup in the area, as
ath10k_core_fetch_board_data_api_n() no longer does its own string
mangling to remove the variant from an ID, instead leaving that job to a
new flag passed to ath10k_core_create_board_name().

I've tested this patch on a QCA4019 and verified that the driver behaves
correctly for 1) both fallback and variant BDFs present, 2) only fallback
BDF present, and 3) no matching BDFs present.

Fixes: 1657b8f84ed9 ("ath10k: search SMBIOS for OEM board file extension")
Signed-off-by: Thomas Hebb 
---
 drivers/net/wireless/ath/ath10k/core.c | 134 ++---
 1 file changed, 72 insertions(+), 62 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index f3ec13b80b20..2233f7e8cc68 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1252,14 +1252,61 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k 
*ar,
return ret;
 }
 
+static int ath10k_core_search_bd(struct ath10k *ar,
+const char *boardname,
+const u8 *data,
+size_t len)
+{
+   size_t ie_len;
+   struct ath10k_fw_ie *hdr;
+   int ret = -ENOENT, ie_id;
+
+   while (len > sizeof(struct ath10k_fw_ie)) {
+   hdr = (struct ath10k_fw_ie *)data;
+   ie_id = le32_to_cpu(hdr->id);
+   ie_len = le32_to_cpu(hdr->len);
+
+   len -= sizeof(*hdr);
+   data = hdr->data;
+
+   if (len < ALIGN(ie_len, 4)) {
+   ath10k_err(ar, "invalid length for board ie_id %d 
ie_len %zu len %zu\n",
+  ie_id, ie_len, len);
+   return -EINVAL;
+   }
+
+   switch (ie_id) {
+   case ATH10K_BD_IE_BOARD:
+   ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
+   boardname);
+   if (ret == -ENOENT)
+   /* no match found, continue */
+   break;
+
+   /* either found or error, so stop searching */
+   goto out;
+   }
+
+   /* jump over the padding */
+   ie_len = ALIGN(ie_len, 4);
+
+   len -= ie_len;
+   data += ie_len;
+   }
+
+out:
+   /* return result of parse_bd_ie_board() or -ENOENT */
+   return ret;
+}
+
 static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
  const char *boardname,
+ const char *fallback_boardname,
  const char *filename)
 {
-   size_t len, magic_len, ie_len;
-   struct ath10k_fw_ie *hdr;
+   size_t len, magic_len;
const u8 *data;
-   int ret, ie_id;
+   int ret;
 
ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
ar->hw_params

[PATCH] pinctrl: berlin: fix BG2CD field widths

2015-09-26 Thread Thomas Hebb
The previous register layout was incorrect, many of the fields having
fewer bits than were needed to represent all their modes. The new layout
is taken from the bootloader source of a BG2CD device.

Signed-off-by: Thomas Hebb 
---
 drivers/pinctrl/berlin/berlin-bg2cd.c | 62
++-
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/drivers/pinctrl/berlin/berlin-bg2cd.c
b/drivers/pinctrl/berlin/berlin-bg2cd.c
index 0cb793a..af5e465 100644
--- a/drivers/pinctrl/berlin/berlin-bg2cd.c
+++ b/drivers/pinctrl/berlin/berlin-bg2cd.c
@@ -19,24 +19,24 @@

 static const struct berlin_desc_group berlin2cd_soc_pinctrl_groups[] = {
/* G */
-   BERLIN_PINCTRL_GROUP("G0", 0x00, 0x1, 0x00,
+   BERLIN_PINCTRL_GROUP("G0", 0x00, 0x3, 0x00,
BERLIN_PINCTRL_FUNCTION(0x0, "jtag"),
BERLIN_PINCTRL_FUNCTION(0x1, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x2, "led"),
BERLIN_PINCTRL_FUNCTION(0x3, "pwm")),
-   BERLIN_PINCTRL_GROUP("G1", 0x00, 0x2, 0x01,
+   BERLIN_PINCTRL_GROUP("G1", 0x00, 0x3, 0x03,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "sd0"),
BERLIN_PINCTRL_FUNCTION(0x6, "usb0_dbg"),
BERLIN_PINCTRL_FUNCTION(0x7, "usb1_dbg")),
-   BERLIN_PINCTRL_GROUP("G2", 0x00, 0x2, 0x02,
+   BERLIN_PINCTRL_GROUP("G2", 0x00, 0x3, 0x06,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "sd0"),
BERLIN_PINCTRL_FUNCTION(0x2, "fe"),
BERLIN_PINCTRL_FUNCTION(0x3, "pll"),
BERLIN_PINCTRL_FUNCTION(0x6, "usb0_dbg"),
BERLIN_PINCTRL_FUNCTION(0x7, "usb1_dbg")),
-   BERLIN_PINCTRL_GROUP("G3", 0x00, 0x2, 0x04,
+   BERLIN_PINCTRL_GROUP("G3", 0x00, 0x3, 0x09,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "sd0"),
BERLIN_PINCTRL_FUNCTION(0x2, "twsi2"),
@@ -44,7 +44,7 @@ static const struct berlin_desc_group
berlin2cd_soc_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x4, "fe"),
BERLIN_PINCTRL_FUNCTION(0x6, "usb0_dbg"),
BERLIN_PINCTRL_FUNCTION(0x7, "usb1_dbg")),
-   BERLIN_PINCTRL_GROUP("G4", 0x00, 0x2, 0x06,
+   BERLIN_PINCTRL_GROUP("G4", 0x00, 0x3, 0x0c,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "sd0"),
BERLIN_PINCTRL_FUNCTION(0x2, "twsi3"),
@@ -52,7 +52,7 @@ static const struct berlin_desc_group
berlin2cd_soc_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x4, "pwm"),
BERLIN_PINCTRL_FUNCTION(0x6, "usb0_dbg"),
BERLIN_PINCTRL_FUNCTION(0x7, "usb1_dbg")),
-   BERLIN_PINCTRL_GROUP("G5", 0x00, 0x3, 0x08,
+   BERLIN_PINCTRL_GROUP("G5", 0x00, 0x3, 0x0f,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "sd0"),
BERLIN_PINCTRL_FUNCTION(0x2, "twsi3"),
@@ -60,64 +60,66 @@ static const struct berlin_desc_group
berlin2cd_soc_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x4, "pwm"),
BERLIN_PINCTRL_FUNCTION(0x6, "usb0_dbg"),
BERLIN_PINCTRL_FUNCTION(0x7, "usb1_dbg")),
-   BERLIN_PINCTRL_GROUP("G6", 0x00, 0x2, 0x0b,
+   BERLIN_PINCTRL_GROUP("G6", 0x00, 0x3, 0x12,
BERLIN_PINCTRL_FUNCTION(0x0, "uart0"),  /* RX/TX */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
-   BERLIN_PINCTRL_GROUP("G7", 0x00, 0x3, 0x0d,
+   BERLIN_PINCTRL_GROUP("G7", 0x00, 0x3, 0x15,
BERLIN_PINCTRL_FUNCTION(0x0, "eddc"),
BERLIN_PINCTRL_FUNCTION(0x1, "twsi1"),
BERLIN_PINCTRL_FUNCTION(0x2, "gpio")),
-   BERLIN_PINCTRL_GROUP("G8", 0x00, 0x3, 0x10,
+   BERLIN_PINCTRL_GROUP("G8", 0x00, 0x3, 0x18,
BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
-   BERLIN_PINCTRL_GROUP("G9", 0x00, 0x3, 0x13,
+   BERLIN_PINCTRL_GROUP("G9", 0x00, 0x3, 0x1b,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS1n/SS2n */
-   BERLIN_PINCTRL_FUNCTION(0x2, "twsi0&quo

[PATCH 2/4 RESEND] ARM: dts: berlin: change BG2Q's USB PHY compatible

2015-09-26 Thread Thomas Hebb
Currently, BG2Q shares a compatible with BG2. This is incorrect, since
BG2 and BG2Q use different USB PLL dividers. In reality, BG2Q shares a
divider with BG2CD. Change BG2Q's USB PHY compatible string to reflect
that.

Signed-off-by: Thomas Hebb 
Cc: sta...@vger.kernel.org
---
This patch seems to have been missed from my original series (all the
rest made it into 4.2), and as a result the BG2Q currently uses the
wrong divider.

 arch/arm/boot/dts/berlin2q.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi
b/arch/arm/boot/dts/berlin2q.dtsi
index 63a4849..d4dbd28 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -152,7 +152,7 @@
};

usb_phy2: phy@a2f400 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xa2f400 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 14>;
@@ -170,7 +170,7 @@
};

usb_phy0: phy@b74000 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb74000 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 12>;
@@ -178,7 +178,7 @@
};

usb_phy1: phy@b78000 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb78000 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 13>;
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/4] phy: berlin-usb: fix divider for BG2CD

2015-07-03 Thread Thomas Hebb
On 07/03/2015 05:20 AM, Antoine Tenart wrote:
> Thomas,
> 
> On Thu, Jul 02, 2015 at 01:04:18AM -0400, Thomas Hebb wrote:
>> The marvell,berlin2cd-usb-phy compatible incorrectly sets the PLL
>> divider to BG2's value instead of BG2CD/BG2Q's. Change it to the right
>> value.
>>
>> Signed-off-by: Thomas Hebb 
>> Cc: sta...@vger.kernel.org
> 
> Only this one is sent to stable? The BG2 won't be fixed in stable?
> 
> Antoine

Since BG2 doesn't currently have its USB PHY enabled in device tree, I
didn't see any reason to mark that fix for stable; we'd have to wait
until next cycle for it to be of use anyway. This is the same division
that Sebastian suggested.

I admit it looks a bit odd to have both dividers be the same. If you
want me to mark the other patches for stable for clarity reasons, I'm
happy to do that.

-Tom

>> ---
>>  drivers/phy/phy-berlin-usb.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
>> index c6fc95b..ab54f28 100644
>> --- a/drivers/phy/phy-berlin-usb.c
>> +++ b/drivers/phy/phy-berlin-usb.c
>> @@ -106,8 +106,8 @@
>>  static const u32 phy_berlin_pll_dividers[] = {
>>  /* Berlin 2 */
>>  CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
>> -/* Berlin 2CD */
>> -CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
>> +/* Berlin 2CD/Q */
>> +CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
>>  };
>>  
>>  struct phy_berlin_usb_priv {
>> -- 
>> 2.4.4
>>
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/4] phy: berlin-usb: rename table copied from SATA PHY

2015-07-03 Thread Thomas Hebb
On 07/03/2015 05:18 AM, Antoine Tenart wrote:
> Thomas,
> 
> On Thu, Jul 02, 2015 at 01:04:30AM -0400, Thomas Hebb wrote:
>> We're not in a SATA PHY driver, so the of_match table shouldn't have
>> "sata" in its name.
> 
> There is already a patch fixing this (which was sent last week):
> 
> https://lkml.org/lkml/2015/6/24/103
> 
> You can drop this one from the series.
> 
> Antoine

Acknowledged. Sorry for the noise.

-Tom

>>
>> Signed-off-by: Thomas Hebb 
>> Suggested-by: Sebastian Hesselbarth 
>> ---
>>  drivers/phy/phy-berlin-usb.c | 8 
>>  1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
>> index 335e06d..7143cd3 100644
>> --- a/drivers/phy/phy-berlin-usb.c
>> +++ b/drivers/phy/phy-berlin-usb.c
>> @@ -152,7 +152,7 @@ static struct phy_ops phy_berlin_usb_ops = {
>>  .owner  = THIS_MODULE,
>>  };
>>  
>> -static const struct of_device_id phy_berlin_sata_of_match[] = {
>> +static const struct of_device_id phy_berlin_usb_of_match[] = {
>>  {
>>  .compatible = "marvell,berlin2-usb-phy",
>>  .data = &phy_berlin_pll_dividers[0],
>> @@ -163,12 +163,12 @@ static const struct of_device_id 
>> phy_berlin_sata_of_match[] = {
>>  },
>>  { },
>>  };
>> -MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
>> +MODULE_DEVICE_TABLE(of, phy_berlin_usb_of_match);
>>  
>>  static int phy_berlin_usb_probe(struct platform_device *pdev)
>>  {
>>  const struct of_device_id *match =
>> -of_match_device(phy_berlin_sata_of_match, &pdev->dev);
>> +of_match_device(phy_berlin_usb_of_match, &pdev->dev);
>>  struct phy_berlin_usb_priv *priv;
>>  struct resource *res;
>>  struct phy *phy;
>> @@ -208,7 +208,7 @@ static struct platform_driver phy_berlin_usb_driver = {
>>  .driver = {
>>  .name   = "phy-berlin-usb",
>>  .owner  = THIS_MODULE,
>> -.of_match_table = phy_berlin_sata_of_match,
>> +.of_match_table = phy_berlin_usb_of_match,
>>   },
>>  };
>>  module_platform_driver(phy_berlin_usb_driver);
>> -- 
>> 2.4.4
>>
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/4] phy: berlin-usb: fix divider for BG2

2015-07-01 Thread Thomas Hebb
The USB PLL divider set by the marvell,berlin2-usb-phy compatible is not
correct for BG2. We couldn't change it before because BG2Q incorrectly
used the same compatible string. Now that BG2Q's compatible is fixed,
change BG2's divider to the correct value.

Signed-off-by: Thomas Hebb 
---
 drivers/phy/phy-berlin-usb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
index ab54f28..335e06d 100644
--- a/drivers/phy/phy-berlin-usb.c
+++ b/drivers/phy/phy-berlin-usb.c
@@ -105,7 +105,7 @@
 
 static const u32 phy_berlin_pll_dividers[] = {
/* Berlin 2 */
-   CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
+   CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
/* Berlin 2CD/Q */
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
 };
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/4] phy: berlin-usb: rename table copied from SATA PHY

2015-07-01 Thread Thomas Hebb
We're not in a SATA PHY driver, so the of_match table shouldn't have
"sata" in its name.

Signed-off-by: Thomas Hebb 
Suggested-by: Sebastian Hesselbarth 
---
 drivers/phy/phy-berlin-usb.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
index 335e06d..7143cd3 100644
--- a/drivers/phy/phy-berlin-usb.c
+++ b/drivers/phy/phy-berlin-usb.c
@@ -152,7 +152,7 @@ static struct phy_ops phy_berlin_usb_ops = {
.owner  = THIS_MODULE,
 };
 
-static const struct of_device_id phy_berlin_sata_of_match[] = {
+static const struct of_device_id phy_berlin_usb_of_match[] = {
{
.compatible = "marvell,berlin2-usb-phy",
.data = &phy_berlin_pll_dividers[0],
@@ -163,12 +163,12 @@ static const struct of_device_id 
phy_berlin_sata_of_match[] = {
},
{ },
 };
-MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
+MODULE_DEVICE_TABLE(of, phy_berlin_usb_of_match);
 
 static int phy_berlin_usb_probe(struct platform_device *pdev)
 {
const struct of_device_id *match =
-   of_match_device(phy_berlin_sata_of_match, &pdev->dev);
+   of_match_device(phy_berlin_usb_of_match, &pdev->dev);
struct phy_berlin_usb_priv *priv;
struct resource *res;
struct phy *phy;
@@ -208,7 +208,7 @@ static struct platform_driver phy_berlin_usb_driver = {
.driver = {
.name   = "phy-berlin-usb",
.owner  = THIS_MODULE,
-   .of_match_table = phy_berlin_sata_of_match,
+   .of_match_table = phy_berlin_usb_of_match,
 },
 };
 module_platform_driver(phy_berlin_usb_driver);
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/4] ARM: dts: berlin: change BG2Q's USB PHY compatible

2015-07-01 Thread Thomas Hebb
Currently, BG2Q shares a compatible with BG2. This is incorrect, since
BG2 and BG2Q use different USB PLL dividers. In reality, BG2Q shares a
divider with BG2CD. Change BG2Q's USB PHY compatible string to reflect
that.

Signed-off-by: Thomas Hebb 
---
 arch/arm/boot/dts/berlin2q.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index 63a4849..d4dbd28 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -152,7 +152,7 @@
};
 
usb_phy2: phy@a2f400 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xa2f400 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 14>;
@@ -170,7 +170,7 @@
};
 
usb_phy0: phy@b74000 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb74000 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 12>;
@@ -178,7 +178,7 @@
};
 
usb_phy1: phy@b78000 {
-   compatible = "marvell,berlin2-usb-phy";
+   compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb78000 0x128>;
#phy-cells = <0>;
resets = <&chip_rst 0x104 13>;
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/4] phy: berlin-usb: fix divider for BG2CD

2015-07-01 Thread Thomas Hebb
The marvell,berlin2cd-usb-phy compatible incorrectly sets the PLL
divider to BG2's value instead of BG2CD/BG2Q's. Change it to the right
value.

Signed-off-by: Thomas Hebb 
Cc: sta...@vger.kernel.org
---
 drivers/phy/phy-berlin-usb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
index c6fc95b..ab54f28 100644
--- a/drivers/phy/phy-berlin-usb.c
+++ b/drivers/phy/phy-berlin-usb.c
@@ -106,8 +106,8 @@
 static const u32 phy_berlin_pll_dividers[] = {
/* Berlin 2 */
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
-   /* Berlin 2CD */
-   CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
+   /* Berlin 2CD/Q */
+   CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
 };
 
 struct phy_berlin_usb_priv {
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/4] phy: berlin-usb: PLL divider fixes

2015-07-01 Thread Thomas Hebb
The USB PLL dividers currently set by phy-berlin-usb are incorrect for
BG2 and BG2CD (i.e. all Berlin variants but BG2Q). This series fixes the
divider values for those two chips and additionally corrects the name of
the of_match table to no longer contain "sata" (which was presumably
mistakenly carried over from phy-berlin-sata).

I have verified that the new divider values work on BG2CD and Antoine
Tenart has verified that they work on BG2Q. The divider value for BG2
was taken from bootloader source but has not been tested.

Thomas Hebb (4):
  phy: berlin-usb: fix divider for BG2CD
  ARM: dts: berlin: change BG2Q's USB PHY compatible
  phy: berlin-usb: fix divider for BG2
  phy: berlin-usb: rename table copied from SATA PHY

 arch/arm/boot/dts/berlin2q.dtsi |  6 +++---
 drivers/phy/phy-berlin-usb.c| 12 ++--
 2 files changed, 9 insertions(+), 9 deletions(-)

-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/