diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index bebef04465..051688a41f 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From 3df8aa3aa981f3c463d793b69fa23c5aab53fec2 Mon Sep 17 00:00:00 2001 +From 5b3bce3c7cc7c2c353709f0197c86cc09978922b Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 001/140] smsx95xx: fix crimes against truesize +Subject: [PATCH 001/187] smsx95xx: fix crimes against truesize smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. @@ -48,10 +48,10 @@ index 831aa33d078ae7d2dd57fdded5de71d1eb915f99..b77935bded8c0ff7808b00f170ff10e5 usbnet_skb_return(dev, ax_skb); } -From aefca8fa1aefb12cc7ac1862b4c6e94c1ec9e74c Mon Sep 17 00:00:00 2001 +From f1b3225d7b4b1bf55b5daf2c95a19b7565b08b52 Mon Sep 17 00:00:00 2001 From: Sam Nazarko Date: Fri, 1 Apr 2016 17:27:21 +0100 -Subject: [PATCH 002/140] smsc95xx: Experimental: Enable turbo_mode and +Subject: [PATCH 002/187] smsc95xx: Experimental: Enable turbo_mode and packetsize=2560 by default See: http://forum.kodi.tv/showthread.php?tid=285288 @@ -94,10 +94,10 @@ index b77935bded8c0ff7808b00f170ff10e594300ad0..693f163684de921404738e33244881e0 netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -From a4774fe88b0a06562a7b6c5d3181f13e7444a3f0 Mon Sep 17 00:00:00 2001 +From 1d04650c28a39de8e0e3158e17cc84c5580fa1a6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 003/140] Allow mac address to be set in smsc95xx +Subject: [PATCH 003/187] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -193,10 +193,10 @@ index 693f163684de921404738e33244881e0aab92ec9..df60c989fc229bf0aab3c27e95ccd453 eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -From 0b4480a51b80954e34605c9bf42947d97e37d1c3 Mon Sep 17 00:00:00 2001 +From 7cb0c34c77963aac8b7c282986088eb479ea3362 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 13 Mar 2015 12:43:36 +0000 -Subject: [PATCH 004/140] Protect __release_resource against resources without +Subject: [PATCH 004/187] Protect __release_resource against resources without parents Without this patch, removing a device tree overlay can crash here. @@ -224,10 +224,10 @@ index 9b5f04404152c296af3a96132f27cfc80ffa9af9..f8a9af6e6b915812be2ba2c1c2b40106 for (;;) { tmp = *p; -From 029f649c29d81583b412cb6ff5792a3cf9102a95 Mon Sep 17 00:00:00 2001 +From 1c0b6f37973324f7ce3557f57d11133d2c9372cf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Dec 2014 16:07:15 -0800 -Subject: [PATCH 005/140] mm: Remove the PFN busy warning +Subject: [PATCH 005/187] mm: Remove the PFN busy warning See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is expected sometimes when using CMA. However, that commit still spams @@ -252,10 +252,10 @@ index f4a02e240fb68acbaa0d3a0c7ac5a498c051a272..0e1fba92702858ceaf2f92a1d5fa53d5 goto done; } -From 3fad09910dafeb93a351aefa90ca4fd490f68c84 Mon Sep 17 00:00:00 2001 +From a1116c4d3195b96d0f79fbeccc9d454bc3fa967a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 4 Dec 2015 17:41:50 +0000 -Subject: [PATCH 006/140] irq-bcm2836: Prevent spurious interrupts, and trap +Subject: [PATCH 006/187] irq-bcm2836: Prevent spurious interrupts, and trap them early The old arch-specific IRQ macros included a dsb to ensure the @@ -282,10 +282,10 @@ index d96b2c947e74e3edab3917551c64fbd1ced0f34c..93e3f7660c4230c9f1dd3b195958cb49 #endif } else if (stat) { -From 0c9c73fafac86e96a1d1fb59b13aac0ce6d70692 Mon Sep 17 00:00:00 2001 +From 3ea010e54a24c8e7a8aaad6811b7864d1352ed63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 12 Jun 2015 19:01:05 +0200 -Subject: [PATCH 007/140] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 007/187] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -414,10 +414,10 @@ index 44d7c38dde479d771f3552e914bf8c1c1f5019f7..42ff5e6a8e0d532f5b60a1e7af7cc4d9 } -From 3b662c4466e336bab7ebb438b65bd5487d30305d Mon Sep 17 00:00:00 2001 +From c91bab759ca14e6ed6ff31b71f104c7535fa69f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Oct 2015 16:26:55 +0200 -Subject: [PATCH 008/140] irqchip: irq-bcm2835: Add 2836 FIQ support +Subject: [PATCH 008/187] irqchip: irq-bcm2835: Add 2836 FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -516,10 +516,10 @@ index 42ff5e6a8e0d532f5b60a1e7af7cc4d941bd5008..eccf6ed025299cb480884f5bcbe77abf for (b = 0; b < NR_BANKS; b++) { for (i = 0; i < bank_irqs[b]; i++) { -From 21a313f8517a1be2b0962710ffe9ad94e7334ba1 Mon Sep 17 00:00:00 2001 +From 22f4e30205024f86c31328e8fc0e6a624417a9a4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 009/140] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 009/187] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -540,10 +540,10 @@ index 2e05046f866bd01bf87edcdeff0d5b76d4d0aea7..d780491b8013a4e97fa843958964454e }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 0059a02a50c6d01a399024cad56ec5254c645fd0 Mon Sep 17 00:00:00 2001 +From 1b90d0328bad60569b3876ef844d31aca382814c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 010/140] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 010/187] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -563,10 +563,10 @@ index e8819aa20415603c80547e382838a8fa3ce54792..cf9c7d2e3f95e1a19410247a89c2e49c for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From c9d0e1314de3cde0674ef5a2c8688b1dc10b2091 Mon Sep 17 00:00:00 2001 +From de236bea6bfc0787a78afda32e0dab3dd6cf716d Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 011/140] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 011/187] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -588,10 +588,10 @@ index fa77165fab2c1348163979da507df17e7168c49b..d11e2e4ea189466e686d762cb6c6fef9 .can_sleep = false, }; -From c7ab4eb8e79ceaa923a7c9f4e14dc085a1934a29 Mon Sep 17 00:00:00 2001 +From 190101af65ca984d506d90d97a109bab83f8cb0f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 012/140] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 012/187] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -737,10 +737,10 @@ index d11e2e4ea189466e686d762cb6c6fef9111ecf8e..107ad7d58de8f8a7f55e09c9cdcf7d66 }, }; -From a5a46d240c25576b901f0afa76575c1ab4a1469a Mon Sep 17 00:00:00 2001 +From 258765d54675e739f457d478218ea3a10bee5c84 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 013/140] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 013/187] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -767,10 +767,10 @@ index 107ad7d58de8f8a7f55e09c9cdcf7d66fa7ab66b..644bdecbcfcb79d3b84a33769265fca5 pc->irq_data[i].irqgroup = i; -From 403ea1795165839348e5953b80ec4da31b639f8e Mon Sep 17 00:00:00 2001 +From dd4ea5e4cac6ee63d4f97a9cddc1c5d52ec87c5b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 May 2016 12:32:47 +0100 -Subject: [PATCH 014/140] pinctrl-bcm2835: Return pins to inputs when freed +Subject: [PATCH 014/187] pinctrl-bcm2835: Return pins to inputs when freed When dynamically unloading overlays, it is important that freed pins are restored to being inputs to prevent functions from being enabled in @@ -811,10 +811,10 @@ index 644bdecbcfcb79d3b84a33769265fca5d3d0c9e5..81a66cba2ab0f7e3ae179de7edd10122 .get_function_name = bcm2835_pmx_get_function_name, .get_function_groups = bcm2835_pmx_get_function_groups, -From d4a8fe93bffd4cab698a2630ee7125da93d55d8a Mon Sep 17 00:00:00 2001 +From 6c2da0e15244836a68c33f3c661bed8c7395d102 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 015/140] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 015/187] spi-bcm2835: Support pin groups other than 7-11 The spi-bcm2835 driver automatically uses GPIO chip-selects due to some unreliability of the native ones. In doing so it chooses the @@ -895,10 +895,10 @@ index f35cc10772f6670397ea923ad30158270dd68578..5dfe20ffc2866fa6789825016c585175 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From fa79e1013557f418119bd9dd2c0cf4c51eb4c093 Mon Sep 17 00:00:00 2001 +From bfe6009cfa1d1d3bafd5178c7e57a7a5d1ce3ee6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 016/140] spi-bcm2835: Disable forced software CS +Subject: [PATCH 016/187] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -932,10 +932,10 @@ index 5dfe20ffc2866fa6789825016c585175a29705b6..8493474d286f7a1ac6454a22c61c8c2c return 0; } -From 85bb42acd1c5a045d372d187c26b77c6bf1b617a Mon Sep 17 00:00:00 2001 +From f8573fdb3818a34ffb20e355e886b1714bc26619 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Nov 2016 21:35:38 +0000 -Subject: [PATCH 017/140] spi-bcm2835: Remove unused code +Subject: [PATCH 017/187] spi-bcm2835: Remove unused code --- drivers/spi/spi-bcm2835.c | 61 ----------------------------------------------- @@ -1023,10 +1023,10 @@ index 8493474d286f7a1ac6454a22c61c8c2cef9121bf..33d75ad38a7f77d085321ace9101900a } -From c33ee72bce07fc83e4797ebea1bce97c0b301ba2 Mon Sep 17 00:00:00 2001 +From 6444138c2aae35d68ae725f3282c412806c039c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 3 Jun 2015 12:26:13 +0200 -Subject: [PATCH 018/140] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 018/187] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1079,10 +1079,10 @@ index 0c1edfc98696da0e0bb7f4a18cdfbcdd27a9795d..8f152266ba9b470df2eaaed9ebcf158e static const char * const bcm2835_compat[] = { -From b4e0c1c3facd38ef5e615248c42dba90d2622257 Mon Sep 17 00:00:00 2001 +From 46b3c73e94090e79f781794efa9eb5c3baca7182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 3 Oct 2015 22:22:55 +0200 -Subject: [PATCH 019/140] dmaengine: bcm2835: Load driver early and support +Subject: [PATCH 019/187] dmaengine: bcm2835: Load driver early and support legacy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -1185,10 +1185,10 @@ index e18dc596cf2447fa9ef7e41b62d9396e29043426..80d35f760b4a4a51e60c355a84d538ba MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); -From 05f9e93200ec5d5e27c8a93f69588180cddda924 Mon Sep 17 00:00:00 2001 +From 5370c41f35ce93bf75842234ebe2e095478d70fb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jan 2016 17:25:12 +0000 -Subject: [PATCH 020/140] firmware: Updated mailbox header +Subject: [PATCH 020/187] firmware: Updated mailbox header --- include/soc/bcm2835/raspberrypi-firmware.h | 11 +++++++++++ @@ -1251,10 +1251,10 @@ index 3fb357193f09914fe21f8555a4b8613f74f22bc3..227a107214a02deadcca3db202da265e RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From c9cb54929b3466ed0da304563e22739477055d3b Mon Sep 17 00:00:00 2001 +From 69546c227775515917c1b037b28ce39307e73482 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 May 2016 17:28:18 -0700 -Subject: [PATCH 021/140] clk: bcm2835: Mark GPIO clocks enabled at boot as +Subject: [PATCH 021/187] clk: bcm2835: Mark GPIO clocks enabled at boot as critical. These divide off of PLLD_PER and are used for the ethernet and wifi @@ -1292,10 +1292,10 @@ index 3bbd2a58db470a89b870a793e59ddf9fc4f48e57..7040c6426e35c11608121893b662c601 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 6c8399fb8dcc815aa9d6b4488a519785912ea983 Mon Sep 17 00:00:00 2001 +From 7682665c3927a4ad4f3826477d390a700aa9bbbe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jun 2016 16:48:41 +0100 -Subject: [PATCH 022/140] rtc: Add SPI alias for pcf2123 driver +Subject: [PATCH 022/187] rtc: Add SPI alias for pcf2123 driver Without this alias, Device Tree won't cause the driver to be loaded. @@ -1315,10 +1315,10 @@ index 8895f77726e8da5444afcd602dceff8f25a9b3fd..1833b8853ceb0e6147cceb93a00e558c MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); -From 259f169ef05f12bc7fed007befc11ed6c66dd9c8 Mon Sep 17 00:00:00 2001 +From 051fa2bc6b71ceb8fcf127bcdc0e9967c4bd3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 7 Oct 2016 16:50:59 +0200 -Subject: [PATCH 023/140] watchdog: bcm2835: Support setting reboot partition +Subject: [PATCH 023/187] watchdog: bcm2835: Support setting reboot partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1442,10 +1442,10 @@ index 4dddd8298a227d64862f2e92954a465f2e44b3f6..1f545e024422f59280932713e6a1b051 register_restart_handler(&wdt->restart_handler); if (pm_power_off == NULL) -From 79d93260c98e0164ca89c9f7c767528d7a3aaeae Mon Sep 17 00:00:00 2001 +From da7d9873080833fc0776c9dd62e2663654c6bd63 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 Apr 2016 19:40:12 +0100 -Subject: [PATCH 024/140] reboot: Use power off rather than busy spinning when +Subject: [PATCH 024/187] reboot: Use power off rather than busy spinning when halt is requested --- @@ -1468,10 +1468,10 @@ index 3fa867a2aae672755c6ce6448f4148c989dbf964..80dca8dcd6709034b643c6a3f35729e0 /* -From 9799ea4ba8ae1e6c586a3dd728ad75f68830e93f Mon Sep 17 00:00:00 2001 +From a5e16e1716206bbe5006cbc44bafbfd938745b94 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 9 Nov 2016 13:02:52 +0000 -Subject: [PATCH 025/140] bcm: Make RASPBERRYPI_POWER depend on PM +Subject: [PATCH 025/187] bcm: Make RASPBERRYPI_POWER depend on PM --- drivers/soc/bcm/Kconfig | 1 + @@ -1490,10 +1490,10 @@ index a39b0d58ddd0fdf0ac1cc7295f8aafb12546e226..e037a6dd79d1881a09e3ca9115782709 help This enables support for the RPi power domains which can be enabled -From 261269cc41f6b77f7264f0e44f9b9da5cc36de00 Mon Sep 17 00:00:00 2001 +From 540071d235f5bef9c51be32bedd1c50b310bcf5a Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Fri, 2 Sep 2016 16:45:27 +0100 -Subject: [PATCH 026/140] Register the clocks early during the boot process, so +Subject: [PATCH 026/187] Register the clocks early during the boot process, so that special/critical clocks can get enabled early on in the boot process avoiding the risk of disabling a clock, pll_divider or pll when a claiming driver fails to install propperly - maybe it needs to defer. @@ -1538,10 +1538,10 @@ index 7040c6426e35c11608121893b662c601cd8d6543..21e2a538ff0d0ab4e63adff9b93705f3 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver"); -From a195976d635c3672cae684d6338655aa25f6d98c Mon Sep 17 00:00:00 2001 +From 1885a738a3b5e11b5af867075b97e6fd283d90d4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 6 Dec 2016 17:05:39 +0000 -Subject: [PATCH 027/140] bcm2835-rng: Avoid initialising if already enabled +Subject: [PATCH 027/187] bcm2835-rng: Avoid initialising if already enabled Avoids the 0x40000 cycles of warmup again if firmware has already used it --- @@ -1567,10 +1567,10 @@ index 574211a495491d9d6021dcaefe4274a63ed02055..e66c0fca8c6090e32f72796c0877a1cf err = hwrng_register(&bcm2835_rng_ops); if (err) { -From 6c52812a34fa4ab0d40b57fef10d23fe2fb0768b Mon Sep 17 00:00:00 2001 +From ebd93733bef0834994066fd061e1d64ec524c3f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Aug 2016 16:28:44 +0100 -Subject: [PATCH 028/140] kbuild: Ignore dtco targets when filtering symbols +Subject: [PATCH 028/187] kbuild: Ignore dtco targets when filtering symbols --- scripts/Kbuild.include | 2 +- @@ -1590,10 +1590,10 @@ index 179219845dfcdfbeb586d12c5ec1296095d9fbf4..e0743e44f84188667a0c322e8c3d36f1 esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' -From 8ee6fd93aa3328d325524b8503714e3b4839d1b9 Mon Sep 17 00:00:00 2001 +From 517f6e19e36779402ddfae837f071613d0a07c0e Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 029/140] BCM2835_DT: Fix I2S register map +Subject: [PATCH 029/187] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -1631,10 +1631,10 @@ index 65783de0aedf3da79adc36fd077b7a89954ddb6b..a89fe4220fdc3f26f75ee66daf187554 dmas = <&dma 2>, <&dma 3>; -From 28a1aeb6b49ffdf5cb5ba9e326df962c270c1f34 Mon Sep 17 00:00:00 2001 +From 39da7256f238d3c92e4cd96a6585ceb5534e26ff Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 030/140] Main bcm2708/bcm2709 linux port +Subject: [PATCH 030/187] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1841,10 +1841,10 @@ index cfb4b4496dd9f61362dea012176c146120fada07..d9c6c217c4d6a2408abe2665bf7f2700 MODULE_AUTHOR("Lubomir Rintel "); MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); -From 4c7d2ae77def863967cbc6e73597d92fe0fb24e7 Mon Sep 17 00:00:00 2001 +From 93b5a8b8dcfe84da8fd054e50b8d1fe3dfe7c7fc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 031/140] Add dwc_otg driver +Subject: [PATCH 031/187] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -62901,10 +62901,10 @@ index 0000000000000000000000000000000000000000..cdc9963176e5a4a0d5250613b61e26c5 +test_main(); +0; -From a5db9164cfc4fdbd25b20962f3da042cdc75a4dc Mon Sep 17 00:00:00 2001 +From 39343516c1962fb3e7e035858d8b97ad6f301bc0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 032/140] bcm2708 framebuffer driver +Subject: [PATCH 032/187] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66363,10 +66363,10 @@ index 3c14e43b82fefe1d32f591d1b2f61d2cd28d0fa8..7626beb6a5bb8df601ddf0f6e6909d1f +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From 5ab35842ff7cc211dcfbf1113953778923097496 Mon Sep 17 00:00:00 2001 +From 252a798d80da007d2d636ebcb8ce481b06e3e661 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 033/140] dmaengine: Add support for BCM2708 +Subject: [PATCH 033/187] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66997,10 +66997,10 @@ index 0000000000000000000000000000000000000000..c5bfff2765be4606077e6c8af73040ec + +#endif /* _PLAT_BCM2708_DMA_H */ -From feab5b6b38842fca38720e0b2e9bfdc66d41c991 Mon Sep 17 00:00:00 2001 +From 891e1563c5b2d17a95c286e41b975cc88fc6041d Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 034/140] MMC: added alternative MMC driver +Subject: [PATCH 034/187] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -68750,10 +68750,10 @@ index 0000000000000000000000000000000000000000..4fe8d1fe44578fbefcd48f8c327ba3d0 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 3d0f0b3db1b62e5d913517ce305913cc71803ef1 Mon Sep 17 00:00:00 2001 +From 04187758f889fda7564f2ced4508a61ab561d3ec Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 035/140] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 035/187] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -71158,10 +71158,10 @@ index 0000000000000000000000000000000000000000..a9bc79bfdbb71807819dfe2d8f165144 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From f6be5bc28ee258731e13b5e917d69f601d062014 Mon Sep 17 00:00:00 2001 +From 0c952d59003067b51766f343f3808bdef9b63d12 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 May 2016 12:50:33 +0100 -Subject: [PATCH 036/140] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards +Subject: [PATCH 036/187] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards Some SD cards have been found that corrupt data when small blocks are erased. Add a quirk to indicate that ERASE should not be used, @@ -71297,10 +71297,10 @@ index 73fad83acbcb6a157587180516f9ffe7c61eb7d7..e7c9d3098ac06e3c6554fa3373a311f9 unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ -From a079bbcd1d23f00392eb79d7bcad867844f84cd9 Mon Sep 17 00:00:00 2001 +From d3833aa3ee47d3efd66073d4696567be1e21481e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 037/140] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 037/187] cma: Add vc_cma driver to enable use of CMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -72636,10 +72636,10 @@ index 0000000000000000000000000000000000000000..be2819d5d41f9d5ed65daf8eedb94c9e + +#endif /* VC_CMA_H */ -From 340dfdd9f8dfad3f60665cac7f19d774c001b0de Mon Sep 17 00:00:00 2001 +From a6713fca54e802f6585314cf3a9d408b6fd6a5cd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 038/140] bcm2708: alsa sound driver +Subject: [PATCH 038/187] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75374,10 +75374,10 @@ index 0000000000000000000000000000000000000000..af3e6eb690113fc32ce9e06bd2f0f294 + +#endif // _VC_AUDIO_DEFS_H_ -From 079c7a4a324b1baa4e727c9e3dfacf503345bb18 Mon Sep 17 00:00:00 2001 +From df6bec6bf36ad61d9f5a468cdc6d86b5b5087ffb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 28 Oct 2016 15:36:43 +0100 -Subject: [PATCH 039/140] vc_mem: Add vc_mem driver for querying firmware +Subject: [PATCH 039/187] vc_mem: Add vc_mem driver for querying firmware memory addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -75901,10 +75901,10 @@ index 0000000000000000000000000000000000000000..20a475377eb3078ea1ecaef2b24efc35 + +#endif /* _VC_MEM_H */ -From 148da7d48af0416c716b0103bcc14d01cc97d09b Mon Sep 17 00:00:00 2001 +From 6fba2c3459adf4e1d4a621da9b5afad5a619ba61 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 040/140] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 040/187] vcsm: VideoCore shared memory service for BCM2835 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -80311,10 +80311,10 @@ index 0000000000000000000000000000000000000000..334f36d0d697b047df2922b5f2db67f3 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ -From f035c5328fecc8970b9a9713cd345d56f5e81f98 Mon Sep 17 00:00:00 2001 +From 60c74f5fe52b96703e250e1a24feee4087af7ae4 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 041/140] Add /dev/gpiomem device for rootless user GPIO access +Subject: [PATCH 041/187] Add /dev/gpiomem device for rootless user GPIO access Signed-off-by: Luke Wren @@ -80625,10 +80625,10 @@ index 0000000000000000000000000000000000000000..911f5b7393ed48ceed8751f06967ae64 +MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); +MODULE_AUTHOR("Luke Wren "); -From ddedd1f135c5311bb4615dda5b285ce688cc50d4 Mon Sep 17 00:00:00 2001 +From 15610d99528e08cd09431d4fb8e096f8a1429c30 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 042/140] Add SMI driver +Subject: [PATCH 042/187] Add SMI driver Signed-off-by: Luke Wren --- @@ -82579,10 +82579,10 @@ index 0000000000000000000000000000000000000000..ee3a75edfc033eeb0d90a687ffb68b10 + +#endif /* BCM2835_SMI_H */ -From 6e5058f6cb203dd31935ba03eeff0d98c7531bcf Mon Sep 17 00:00:00 2001 +From c1fc2e3713740d34d3ebffa23562f5517a11e856 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 26 Apr 2016 14:59:21 +0000 -Subject: [PATCH 043/140] MISC: bcm2835: smi: use clock manager and fix reload +Subject: [PATCH 043/187] MISC: bcm2835: smi: use clock manager and fix reload issues Use clock manager instead of self-made clockmanager. @@ -82752,10 +82752,10 @@ index 63a4ea08b9930a3a31a985f0a1d969b488ed49ec..1261540703127d1d63b9f3c87042c6e5 return 0; } -From 83148030b231764e7a5fc14bd2c9ccc6a104a872 Mon Sep 17 00:00:00 2001 +From e33564f1fb6810986eea99d15e1dcfb08854db26 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 044/140] Add SMI NAND driver +Subject: [PATCH 044/187] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -83120,10 +83120,10 @@ index 0000000000000000000000000000000000000000..02adda6da18bd0ba9ab19a104975b79d + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From e12517458be7d5ec0eccc2c23db2b78badd54587 Mon Sep 17 00:00:00 2001 +From fe1ebea96978a74e9d6629319d75e909a2939568 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 045/140] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 045/187] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -83986,10 +83986,10 @@ index 0000000000000000000000000000000000000000..fb69624ccef00ddbdccf8256d6baf1b1 + +#endif -From 91eeb6693671b5ae0220f4a276b84e6597266cb9 Mon Sep 17 00:00:00 2001 +From 4a06b6a752541356b941a1456561d6919ce271de Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 046/140] Add cpufreq driver +Subject: [PATCH 046/187] Add cpufreq driver Signed-off-by: popcornmix --- @@ -84256,10 +84256,10 @@ index 0000000000000000000000000000000000000000..414fbdc10dfbfc6e4bb47870a7af3fd5 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From c83d1bbc2d9feaf23252482682824babbbd7bbd9 Mon Sep 17 00:00:00 2001 +From 55f87fdafb41219c6dfe09205b99995f04344afc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 047/140] Added hwmon/thermal driver for reporting core +Subject: [PATCH 047/187] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -84425,10 +84425,10 @@ index 0000000000000000000000000000000000000000..c63fb9f9d143e19612a18fe530c7b2b3 +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip"); +MODULE_LICENSE("GPL"); -From d34838cfa7c139fa069b7e038d3ea2b56c50a353 Mon Sep 17 00:00:00 2001 +From 7364dbd24a0a0dabf31282739cef4e8e525180b4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 048/140] Add Chris Boot's i2c driver +Subject: [PATCH 048/187] Add Chris Boot's i2c driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85093,10 +85093,10 @@ index 0000000000000000000000000000000000000000..962f2e5c7455d91bf32925d785f5f16b +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From e826eaf145a568f477ab9e5554a563233ad7fb49 Mon Sep 17 00:00:00 2001 +From 3e28d525179e460d15f4597ac3ba3cb3dd5c0654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:27:06 +0200 -Subject: [PATCH 049/140] char: broadcom: Add vcio module +Subject: [PATCH 049/187] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85322,10 +85322,10 @@ index 0000000000000000000000000000000000000000..c19bc2075c77879563ef5e59038b5a14 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From 2838aca7eb2ef14cb94ac43921fc2db291af96a7 Mon Sep 17 00:00:00 2001 +From 14f966c1540fbc4564e283cd04f45ac4f7589c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:25:01 +0200 -Subject: [PATCH 050/140] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 050/187] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85408,10 +85408,10 @@ index dd506cd3a5b874f9e1acd07efb8cd151bb6145d1..3f070bd38a91511c986e3fb114b15bd4 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From 35fa034f52f341a95e10034b2f36e2af05fee117 Mon Sep 17 00:00:00 2001 +From 63c40ffcafaf4fd2b6dac73ffce0ff20fa13bfa4 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 051/140] bcm2835: add v4l2 camera device +Subject: [PATCH 051/187] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -93153,10 +93153,10 @@ index 0000000000000000000000000000000000000000..9d1d11e4a53e510c04a416d92d195a7d + +#endif /* MMAL_VCHIQ_H */ -From 59799351c2a2951565e10b2ef69ccff34f94fd30 Mon Sep 17 00:00:00 2001 +From d8f6d2d3da8a446c4435eedc19eeb78a4c55dccf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 052/140] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 052/187] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -93676,10 +93676,10 @@ index 0000000000000000000000000000000000000000..60206de7fa9a49bd027c635306674a29 + return $trailer; +} -From 913a79481bedcfed6727e899ab3f5a9291328f55 Mon Sep 17 00:00:00 2001 +From e279a8b4fd6b3065f278b8dc178e21fa71b9e7ac Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 10 Aug 2015 09:49:15 +0100 -Subject: [PATCH 053/140] scripts/dtc: Update to upstream version 1.4.1 +Subject: [PATCH 053/187] scripts/dtc: Update to upstream version 1.4.1 Includes the new localfixups format. @@ -96530,10 +96530,10 @@ index ad9b05ae698b0495ecbda42ffcf4743555313a27..2595dfda020fd9e03f0beff5006f229d -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.1-g25efc119" -From 2ad7caa56296821bfab4ce0e808a0d1d2c8ac9f4 Mon Sep 17 00:00:00 2001 +From f5bb88317d954b3a76cebb7611c5695d9873fca5 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 054/140] BCM2708: Add core Device Tree support +Subject: [PATCH 054/187] BCM2708: Add core Device Tree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -106661,10 +106661,10 @@ index 0a07f9014944ed92a8e2e42983ae43be60b3e471..1967878a843461c3ff1f473b9a030eb0 # Bzip2 -From f760337032ce3078b0ecfe2ec8420bbdf173151d Mon Sep 17 00:00:00 2001 +From 2bed5e08a6bc8c22915d5794f36108b06b9d8063 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 055/140] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 055/187] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -106840,10 +106840,10 @@ index ddfcb2df3656cf0ab6aebd1fa3d624a6ec2e94e9..271563eb835f9018712e2076a88f341d /* Set LED brightness level * Must not sleep. Use brightness_set_blocking for drivers -From c19ea76c6206a3e5a897cef2da65d82c6dd76430 Mon Sep 17 00:00:00 2001 +From d4cbcc3c16c64a448532c80d64b33cf2f41696f5 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 056/140] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 056/187] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -107095,10 +107095,10 @@ index fb795c3b3c178ad3cd7c9e9e4547ffd492bac181..703fa8a70574323abe2fb32599254582 __u32 dx; /* screen-relative */ __u32 dy; -From 11db806d75a8958fb706d8a1b4e67818a04d68c7 Mon Sep 17 00:00:00 2001 +From 6bf48a366444156dea2df2500dc242cab2a45bdb Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 057/140] Speed up console framebuffer imageblit function +Subject: [PATCH 057/187] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -107307,10 +107307,10 @@ index a2bb276a8b2463eee98eb237c4647bc00cd93601..436494fba15abecb400ef28688466faf start_index, pitch_index); } else -From d387edf492067aa0d298b90829b784f640375e7c Mon Sep 17 00:00:00 2001 +From 0e0fdde1881539adf417ed1ac11b8b48c7094b59 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 058/140] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 058/187] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -107560,10 +107560,10 @@ index d58594a3232492e33f1dd4babd3798b03e0f0203..feae94256256316fd9d850c3d83325af unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 06dbec311ec4beeac31e1567b5ca499210d1f21e Mon Sep 17 00:00:00 2001 +From 1859374c090dd68d2a7bbbc582e83fa48488db2e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 059/140] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 059/187] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -107571,10 +107571,10 @@ Subject: [PATCH 059/140] config: Enable CONFIG_MEMCG, but leave it disabled 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce0496c69d 100644 +index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b811f26343 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c -@@ -5629,7 +5629,7 @@ int __init cgroup_init_early(void) +@@ -5626,7 +5626,7 @@ int __init cgroup_init_early(void) return 0; } @@ -107583,7 +107583,7 @@ index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce /** * cgroup_init - cgroup initialization -@@ -6166,6 +6166,28 @@ static int __init cgroup_no_v1(char *str) +@@ -6163,6 +6163,28 @@ static int __init cgroup_no_v1(char *str) } __setup("cgroup_no_v1=", cgroup_no_v1); @@ -107613,10 +107613,10 @@ index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce * css_tryget_online_from_dir - get corresponding css from a cgroup dentry * @dentry: directory dentry of interest -From 5f6748b37accdf94cb360cfaa92bca5fdb0a161f Mon Sep 17 00:00:00 2001 +From 7035848318b6cc55db1b828570129c7cd23a2d2a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 060/140] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 060/187] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -107652,10 +107652,10 @@ index ae83af649a607f67239f1a64bf45dd4b5770cc7d..4a7af9d0b910f59d17421ce14138400d ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 712bd947a275fcc4a96363de2aa980111522620a Mon Sep 17 00:00:00 2001 +From 68fc43e57e288e2f60ea3e59cd277e74a3a2b109 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 061/140] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 061/187] rpi-ft5406: Add touchscreen driver for pi LCD display Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected @@ -108013,10 +108013,10 @@ index 227a107214a02deadcca3db202da265eba1fdd21..b0f6e33bd30c35664ceee057f4c3ad32 RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From e1102cfabcece5b4bbd51993bfcf5dcba5470d18 Mon Sep 17 00:00:00 2001 +From 9131e111f37da1075c3b1f3625e67e589c6e3af6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 28 Nov 2016 16:50:04 +0000 -Subject: [PATCH 062/140] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 062/187] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -109591,10 +109591,10 @@ index 333dc3c2e5ffbb2c5ab8fcfb6115b6162643cf20..46b787a6474ffa857da9b663948863ec bool "Broadcom BCM63xx DSL SoC" depends on ARCH_MULTI_V7 -From 565555340550efa6093ef922d0571d795fbce5ee Mon Sep 17 00:00:00 2001 +From 28e35276915860933d56d6054ad6dcf71810e451 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 063/140] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 063/187] gpio-poweroff: Allow it to work on Raspberry Pi The Raspberry Pi firmware manages the power-down and reboot process. To do this it installs a pm_power_off handler, causing @@ -109629,10 +109629,10 @@ index be3d81ff51cc3f510d85e4eed7a52960e51e7bc1..a030ae9fb1fca325061c093696e82186 "%s: pm_power_off function already registered", __func__); -From 2e658b6085a2f857761590e8a780cc19898f3393 Mon Sep 17 00:00:00 2001 +From d7a46aff991220634c119c16d7c55031ba08dc82 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 064/140] mfd: Add Raspberry Pi Sense HAT core driver +Subject: [PATCH 064/187] mfd: Add Raspberry Pi Sense HAT core driver --- drivers/input/joystick/Kconfig | 8 + @@ -110497,10 +110497,10 @@ index 0000000000000000000000000000000000000000..56196dc2af10e464a1e3f98b028dca1c + +#endif -From b463377320e7c95cfe9df94c1fdb7c4cb29d6f35 Mon Sep 17 00:00:00 2001 +From 22848b7aff35ce2e22d395920ac76333cfe9602e Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 065/140] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 065/187] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -110675,10 +110675,10 @@ index 0000000000000000000000000000000000000000..45f2b770ad9e67728ca599a7445d6ae9 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 13807585114080c341126a924de8217edf913e94 Mon Sep 17 00:00:00 2001 +From 7034f481906a088fdfb40bb40862b84ea9974dd0 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 25 Jan 2016 15:48:59 +0000 -Subject: [PATCH 066/140] ASoC: Add support for Rpi-DAC +Subject: [PATCH 066/187] ASoC: Add support for Rpi-DAC --- sound/soc/bcm/Kconfig | 7 +++ @@ -110962,10 +110962,10 @@ index 0000000000000000000000000000000000000000..afe1b419582aa40c4b2729d242bb13cd +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From c7d9bc61bef1c8a08f68d7e0c7685d922fd0da47 Mon Sep 17 00:00:00 2001 +From cbc5d55c367907407b52f7a66930778f6930c536 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 067/140] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 067/187] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -111014,10 +111014,10 @@ index af95d648265b3e92e345101542b332aee35191d4..513f56ba132929662802d15cdc653af3 .component_driver = { .dapm_widgets = wm8804_dapm_widgets, -From 7635da3016caa5b541a80e584a8538125e0b5299 Mon Sep 17 00:00:00 2001 +From 35a5b16cceab45a8c8d790c34aff2f2087e518c0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 068/140] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 068/187] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -111361,10 +111361,10 @@ index 0000000000000000000000000000000000000000..19dc953b7227ba86123fc7a2ba654499 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From bd440ceb58ec584d192d8c0c38c9252119be750c Mon Sep 17 00:00:00 2001 +From 88cac05c9cf1c8b8cfe2c7305aafa139fa51eb36 Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 069/140] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 069/187] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -111694,10 +111694,10 @@ index 0000000000000000000000000000000000000000..4e8e6dec14bcf4a1ff286c43742d4097 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From ab186ec6221b540210504627441a75479f04eb06 Mon Sep 17 00:00:00 2001 +From ed73721503a6da0935a3e51d5331e114250c4e89 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jul 2016 17:06:50 +0100 -Subject: [PATCH 070/140] iqaudio-dac: Compile fix - untested +Subject: [PATCH 070/187] iqaudio-dac: Compile fix - untested --- sound/soc/bcm/iqaudio-dac.c | 6 +++++- @@ -111721,10 +111721,10 @@ index 4e8e6dec14bcf4a1ff286c43742d4097249d6777..aa15bc4b49ca95edec905fddd8fd0a6d if (dapm->dev != codec_dai->dev) return 0; -From 92c77bd4247436d8160e450644faa37a0da6aad5 Mon Sep 17 00:00:00 2001 +From 541f36eeb4c4f38d428639c81e883c39268dd5e4 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 071/140] Added support for HiFiBerry DAC+ +Subject: [PATCH 071/187] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -112354,10 +112354,10 @@ index 72b19e62f6267698aea45d2410d616d91c1825cb..c6839ef6e16754ed9de2698507b8986a dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From 3247df6b45b656dc288ef26723abd9a0888ddf49 Mon Sep 17 00:00:00 2001 +From fc90457b4e4754c9669542fb77325c6089b87c89 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 072/140] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 072/187] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -112372,15 +112372,19 @@ reported correctly by a non-zero return code. HiFiBerry Amp: fix device-tree problems Some code to load the driver based on device-tree-overlays was missing. This is added by this patch. + +hifiberry-amp: Adjust for ALSA object refactoring + +See: https://github.com/raspberrypi/linux/issues/1775 --- sound/soc/bcm/Kconfig | 7 + sound/soc/bcm/Makefile | 2 + sound/soc/bcm/hifiberry_amp.c | 129 +++++++++++++++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++ + sound/soc/codecs/tas5713.c | 371 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++ - 7 files changed, 723 insertions(+) + 7 files changed, 725 insertions(+) create mode 100644 sound/soc/bcm/hifiberry_amp.c create mode 100644 sound/soc/codecs/tas5713.c create mode 100644 sound/soc/codecs/tas5713.h @@ -112404,23 +112408,24 @@ index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..b1d877407dd69c9bd6b2787b0a559f41 tristate "Support for RPi-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 203afc03167acbcad15e836209956bc5ab151157..a4838e2cf8e93c9285836f95f4151daea33e1bd1 100644 +index 203afc03167acbcad15e836209956bc5ab151157..8ffe0725ba10307b5636a252b6bb8d61ecfe2591 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,11 +12,13 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -9,12 +9,14 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o + obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o + + # BCM2708 Machine Support ++snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o -+snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c new file mode 100644 index 0000000000000000000000000000000000000000..d17c29780507dc31c50f1d567ff5cea7c8241ff5 @@ -112600,10 +112605,10 @@ index 77786e7f44a7fa22d9b5beed3eb687e2b7a28526..5a2db0d2fe2f49920eeccfecef62c969 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c new file mode 100644 -index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1eae5867411 +index 0000000000000000000000000000000000000000..560234d58a6b0a6e7fd3a63e8de73339ee002b1c --- /dev/null +++ b/sound/soc/codecs/tas5713.c -@@ -0,0 +1,369 @@ +@@ -0,0 +1,371 @@ +/* + * ASoC Driver for TAS5713 + * @@ -112838,8 +112843,10 @@ index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1ea +static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { + .probe = tas5713_probe, + .remove = tas5713_remove, -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), ++ .component_driver = { ++ .controls = tas5713_snd_controls, ++ .num_controls = ARRAY_SIZE(tas5713_snd_controls), ++ }, +}; + + @@ -113190,835 +113197,10 @@ index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8 + +#endif /* _TAS5713_H */ -From 73485d00032dc13327d26e44a0038505651b35f7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 12 Dec 2016 16:26:54 +0000 -Subject: [PATCH 073/140] Revert "Added driver for HiFiBerry Amp amplifier - add-on board" - -This reverts commit 3e6b00833d92a50cbcc9922deb6e1bc8fcdbb587. ---- - sound/soc/bcm/Kconfig | 7 - - sound/soc/bcm/Makefile | 2 - - sound/soc/bcm/hifiberry_amp.c | 129 --------------- - sound/soc/codecs/Kconfig | 4 - - sound/soc/codecs/Makefile | 2 - - sound/soc/codecs/tas5713.c | 369 ------------------------------------------ - sound/soc/codecs/tas5713.h | 210 ------------------------ - 7 files changed, 723 deletions(-) - delete mode 100644 sound/soc/bcm/hifiberry_amp.c - delete mode 100644 sound/soc/codecs/tas5713.c - delete mode 100644 sound/soc/codecs/tas5713.h - -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b1d877407dd69c9bd6b2787b0a559f4113bc21f2..4473cc728097bda0ce9fe68d4a9da348ec41f8b3 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -38,13 +38,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI - help - Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. - --config SND_BCM2708_SOC_HIFIBERRY_AMP -- tristate "Support for the HifiBerry Amp" -- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -- select SND_SOC_TAS5713 -- help -- Say Y or M if you want to add support for the HifiBerry Amp amplifier board. -- - config SND_BCM2708_SOC_RPI_DAC - tristate "Support for RPi-DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a4838e2cf8e93c9285836f95f4151daea33e1bd1..203afc03167acbcad15e836209956bc5ab151157 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -12,13 +12,11 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o --snd-soc-hifiberry-amp-objs := hifiberry_amp.o - snd-soc-rpi-dac-objs := rpi-dac.o - snd-soc-iqaudio-dac-objs := iqaudio-dac.o - - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o --obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o -diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c -deleted file mode 100644 -index d17c29780507dc31c50f1d567ff5cea7c8241ff5..0000000000000000000000000000000000000000 ---- a/sound/soc/bcm/hifiberry_amp.c -+++ /dev/null -@@ -1,129 +0,0 @@ --/* -- * ASoC Driver for HifiBerry AMP -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#include --#include -- --#include --#include --#include --#include --#include -- --static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd) --{ -- // ToDo: init of the dsp-registers. -- return 0; --} -- --static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params ) --{ -- struct snd_soc_pcm_runtime *rtd = substream->private_data; -- struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -- -- return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); --} -- --static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = { -- .hw_params = snd_rpi_hifiberry_amp_hw_params, --}; -- --static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { -- { -- .name = "HifiBerry AMP", -- .stream_name = "HifiBerry AMP HiFi", -- .cpu_dai_name = "bcm2708-i2s.0", -- .codec_dai_name = "tas5713-hifi", -- .platform_name = "bcm2708-i2s.0", -- .codec_name = "tas5713.1-001b", -- .dai_fmt = SND_SOC_DAIFMT_I2S | -- SND_SOC_DAIFMT_NB_NF | -- SND_SOC_DAIFMT_CBS_CFS, -- .ops = &snd_rpi_hifiberry_amp_ops, -- .init = snd_rpi_hifiberry_amp_init, -- }, --}; -- -- --static struct snd_soc_card snd_rpi_hifiberry_amp = { -- .name = "snd_rpi_hifiberry_amp", -- .driver_name = "HifiberryAmp", -- .owner = THIS_MODULE, -- .dai_link = snd_rpi_hifiberry_amp_dai, -- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), --}; -- --static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = { -- { .compatible = "hifiberry,hifiberry-amp", }, -- {}, --}; --MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match); -- -- --static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) --{ -- int ret = 0; -- -- snd_rpi_hifiberry_amp.dev = &pdev->dev; -- -- if (pdev->dev.of_node) { -- struct device_node *i2s_node; -- struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0]; -- i2s_node = of_parse_phandle(pdev->dev.of_node, -- "i2s-controller", 0); -- -- if (i2s_node) { -- dai->cpu_dai_name = NULL; -- dai->cpu_of_node = i2s_node; -- dai->platform_name = NULL; -- dai->platform_of_node = i2s_node; -- } -- } -- -- ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); -- -- if (ret != 0) { -- dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -- } -- -- return ret; --} -- -- --static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev) --{ -- return snd_soc_unregister_card(&snd_rpi_hifiberry_amp); --} -- -- --static struct platform_driver snd_rpi_hifiberry_amp_driver = { -- .driver = { -- .name = "snd-hifiberry-amp", -- .owner = THIS_MODULE, -- .of_match_table = snd_rpi_hifiberry_amp_of_match, -- }, -- .probe = snd_rpi_hifiberry_amp_probe, -- .remove = snd_rpi_hifiberry_amp_remove, --}; -- -- --module_platform_driver(snd_rpi_hifiberry_amp_driver); -- -- --MODULE_AUTHOR("Sebastian Eickhoff "); --MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); --MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4..74a93e52bdc8116df3db08aaf98fffa1e6f6cc1b 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -139,7 +139,6 @@ config SND_SOC_ALL_CODECS - select SND_SOC_TFA9879 if I2C - select SND_SOC_TLV320AIC23_I2C if I2C - select SND_SOC_TLV320AIC23_SPI if SPI_MASTER -- select SND_SOC_TAS5713 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC31XX if I2C - select SND_SOC_TLV320AIC32X4_I2C if I2C -@@ -822,9 +821,6 @@ config SND_SOC_TFA9879 - tristate "NXP Semiconductors TFA9879 amplifier" - depends on I2C - --config SND_SOC_TAS5713 -- tristate -- - config SND_SOC_TLV320AIC23 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 5a2db0d2fe2f49920eeccfecef62c969ae2e99a1..77786e7f44a7fa22d9b5beed3eb687e2b7a28526 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -144,7 +144,6 @@ snd-soc-tas5086-objs := tas5086.o - snd-soc-tas571x-objs := tas571x.o - snd-soc-tas5720-objs := tas5720.o - snd-soc-tfa9879-objs := tfa9879.o --snd-soc-tas5713-objs := tas5713.o - snd-soc-tlv320aic23-objs := tlv320aic23.o - snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o - snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o -@@ -367,7 +366,6 @@ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o - obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o - obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o - obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o --obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o - obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -deleted file mode 100644 -index 9b2713861dcbed751842ca29c88eb1eae5867411..0000000000000000000000000000000000000000 ---- a/sound/soc/codecs/tas5713.c -+++ /dev/null -@@ -1,369 +0,0 @@ --/* -- * ASoC Driver for TAS5713 -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include -- --#include "tas5713.h" -- -- --static struct i2c_client *i2c; -- --struct tas5713_priv { -- struct regmap *regmap; -- int mclk_div; -- struct snd_soc_codec *codec; --}; -- --static struct tas5713_priv *priv_data; -- -- -- -- --/* -- * _ _ ___ _ ___ _ _ -- * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___ -- * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-< -- * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/ -- * -- */ -- --static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1); -- -- --static const struct snd_kcontrol_new tas5713_snd_controls[] = { -- SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv), -- SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv) --}; -- -- -- -- --/* -- * __ __ _ _ ___ _ -- * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _ -- * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_| -- * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_| -- * -- */ -- --static int tas5713_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params, -- struct snd_soc_dai *dai) --{ -- u16 blen = 0x00; -- -- struct snd_soc_codec *codec; -- codec = dai->codec; -- priv_data->codec = dai->codec; -- -- switch (params_format(params)) { -- case SNDRV_PCM_FORMAT_S16_LE: -- blen = 0x03; -- break; -- case SNDRV_PCM_FORMAT_S20_3LE: -- blen = 0x1; -- break; -- case SNDRV_PCM_FORMAT_S24_LE: -- blen = 0x04; -- break; -- case SNDRV_PCM_FORMAT_S32_LE: -- blen = 0x05; -- break; -- default: -- dev_err(dai->dev, "Unsupported word length: %u\n", -- params_format(params)); -- return -EINVAL; -- } -- -- // set word length -- snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen); -- -- return 0; --} -- -- --static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream) --{ -- unsigned int val = 0; -- -- struct tas5713_priv *tas5713; -- struct snd_soc_codec *codec = dai->codec; -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- if (mute) { -- val = TAS5713_SOFT_MUTE_ALL; -- } -- -- return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val); --} -- -- --static const struct snd_soc_dai_ops tas5713_dai_ops = { -- .hw_params = tas5713_hw_params, -- .mute_stream = tas5713_mute_stream, --}; -- -- --static struct snd_soc_dai_driver tas5713_dai = { -- .name = "tas5713-hifi", -- .playback = { -- .stream_name = "Playback", -- .channels_min = 2, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_48000, -- .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ), -- }, -- .ops = &tas5713_dai_ops, --}; -- -- -- -- --/* -- * ___ _ ___ _ -- * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _ -- * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_| -- * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_| -- * -- */ -- --static int tas5713_remove(struct snd_soc_codec *codec) --{ -- struct tas5713_priv *tas5713; -- -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- return 0; --} -- -- --static int tas5713_probe(struct snd_soc_codec *codec) --{ -- struct tas5713_priv *tas5713; -- int i, ret; -- -- i2c = container_of(codec->dev, struct i2c_client, dev); -- -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- // Reset error -- ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -- if (ret < 0) return ret; -- -- // Trim oscillator -- ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00); -- if (ret < 0) return ret; -- msleep(1000); -- -- // Reset error -- ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -- if (ret < 0) return ret; -- -- // Clock mode: 44/48kHz, MCLK=64xfs -- ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60); -- if (ret < 0) return ret; -- -- // I2S 24bit -- ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05); -- if (ret < 0) return ret; -- -- // Unmute -- ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -- if (ret < 0) return ret; -- ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00); -- if (ret < 0) return ret; -- -- // Set volume to 0db -- ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00); -- if (ret < 0) return ret; -- -- // Now start programming the default initialization sequence -- for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) { -- ret = i2c_master_send(i2c, -- tas5713_init_sequence[i].data, -- tas5713_init_sequence[i].size); -- if (ret < 0) { -- printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret); -- } -- } -- -- // Unmute -- ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -- if (ret < 0) return ret; -- -- return 0; --} -- -- --static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { -- .probe = tas5713_probe, -- .remove = tas5713_remove, -- .controls = tas5713_snd_controls, -- .num_controls = ARRAY_SIZE(tas5713_snd_controls), --}; -- -- -- -- --/* -- * ___ ___ ___ ___ _ -- * |_ _|_ ) __| | \ _ _(_)_ _____ _ _ -- * | | / / (__ | |) | '_| \ V / -_) '_| -- * |___/___\___| |___/|_| |_|\_/\___|_| -- * -- */ -- --static const struct reg_default tas5713_reg_defaults[] = { -- { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB -- { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB -- { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB -- { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB --}; -- -- --static bool tas5713_reg_volatile(struct device *dev, unsigned int reg) --{ -- switch (reg) { -- case TAS5713_DEVICE_ID: -- case TAS5713_ERROR_STATUS: -- return true; -- default: -- return false; -- } --} -- -- --static const struct of_device_id tas5713_of_match[] = { -- { .compatible = "ti,tas5713", }, -- { } --}; --MODULE_DEVICE_TABLE(of, tas5713_of_match); -- -- --static struct regmap_config tas5713_regmap_config = { -- .reg_bits = 8, -- .val_bits = 8, -- -- .max_register = TAS5713_MAX_REGISTER, -- .volatile_reg = tas5713_reg_volatile, -- -- .cache_type = REGCACHE_RBTREE, -- .reg_defaults = tas5713_reg_defaults, -- .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults), --}; -- -- --static int tas5713_i2c_probe(struct i2c_client *i2c, -- const struct i2c_device_id *id) --{ -- int ret; -- -- priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL); -- if (!priv_data) -- return -ENOMEM; -- -- priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config); -- if (IS_ERR(priv_data->regmap)) { -- ret = PTR_ERR(priv_data->regmap); -- return ret; -- } -- -- i2c_set_clientdata(i2c, priv_data); -- -- ret = snd_soc_register_codec(&i2c->dev, -- &soc_codec_dev_tas5713, &tas5713_dai, 1); -- -- return ret; --} -- -- --static int tas5713_i2c_remove(struct i2c_client *i2c) --{ -- snd_soc_unregister_codec(&i2c->dev); -- i2c_set_clientdata(i2c, NULL); -- -- kfree(priv_data); -- -- return 0; --} -- -- --static const struct i2c_device_id tas5713_i2c_id[] = { -- { "tas5713", 0 }, -- { } --}; -- --MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id); -- -- --static struct i2c_driver tas5713_i2c_driver = { -- .driver = { -- .name = "tas5713", -- .owner = THIS_MODULE, -- .of_match_table = tas5713_of_match, -- }, -- .probe = tas5713_i2c_probe, -- .remove = tas5713_i2c_remove, -- .id_table = tas5713_i2c_id --}; -- -- --static int __init tas5713_modinit(void) --{ -- int ret = 0; -- -- ret = i2c_add_driver(&tas5713_i2c_driver); -- if (ret) { -- printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n", -- ret); -- } -- -- return ret; --} --module_init(tas5713_modinit); -- -- --static void __exit tas5713_exit(void) --{ -- i2c_del_driver(&tas5713_i2c_driver); --} --module_exit(tas5713_exit); -- -- --MODULE_AUTHOR("Sebastian Eickhoff "); --MODULE_DESCRIPTION("ASoC driver for TAS5713"); --MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/tas5713.h b/sound/soc/codecs/tas5713.h -deleted file mode 100644 -index 8f019e04898754d2f87e9630137be9e8f612a342..0000000000000000000000000000000000000000 ---- a/sound/soc/codecs/tas5713.h -+++ /dev/null -@@ -1,210 +0,0 @@ --/* -- * ASoC Driver for TAS5713 -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#ifndef _TAS5713_H --#define _TAS5713_H -- -- --// TAS5713 I2C-bus register addresses -- --#define TAS5713_CLOCK_CTRL 0x00 --#define TAS5713_DEVICE_ID 0x01 --#define TAS5713_ERROR_STATUS 0x02 --#define TAS5713_SYSTEM_CTRL1 0x03 --#define TAS5713_SERIAL_DATA_INTERFACE 0x04 --#define TAS5713_SYSTEM_CTRL2 0x05 --#define TAS5713_SOFT_MUTE 0x06 --#define TAS5713_VOL_MASTER 0x07 --#define TAS5713_VOL_CH1 0x08 --#define TAS5713_VOL_CH2 0x09 --#define TAS5713_VOL_HEADPHONE 0x0A --#define TAS5713_VOL_CONFIG 0x0E --#define TAS5713_MODULATION_LIMIT 0x10 --#define TAS5713_IC_DLY_CH1 0x11 --#define TAS5713_IC_DLY_CH2 0x12 --#define TAS5713_IC_DLY_CH3 0x13 --#define TAS5713_IC_DLY_CH4 0x14 -- --#define TAS5713_START_STOP_PERIOD 0x1A --#define TAS5713_OSC_TRIM 0x1B --#define TAS5713_BKND_ERR 0x1C -- --#define TAS5713_INPUT_MUX 0x20 --#define TAS5713_SRC_SELECT_CH4 0x21 --#define TAS5713_PWM_MUX 0x25 -- --#define TAS5713_CH1_BQ0 0x29 --#define TAS5713_CH1_BQ1 0x2A --#define TAS5713_CH1_BQ2 0x2B --#define TAS5713_CH1_BQ3 0x2C --#define TAS5713_CH1_BQ4 0x2D --#define TAS5713_CH1_BQ5 0x2E --#define TAS5713_CH1_BQ6 0x2F --#define TAS5713_CH1_BQ7 0x58 --#define TAS5713_CH1_BQ8 0x59 -- --#define TAS5713_CH2_BQ0 0x30 --#define TAS5713_CH2_BQ1 0x31 --#define TAS5713_CH2_BQ2 0x32 --#define TAS5713_CH2_BQ3 0x33 --#define TAS5713_CH2_BQ4 0x34 --#define TAS5713_CH2_BQ5 0x35 --#define TAS5713_CH2_BQ6 0x36 --#define TAS5713_CH2_BQ7 0x5C --#define TAS5713_CH2_BQ8 0x5D -- --#define TAS5713_CH4_BQ0 0x5A --#define TAS5713_CH4_BQ1 0x5B --#define TAS5713_CH3_BQ0 0x5E --#define TAS5713_CH3_BQ1 0x5F -- --#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B --#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C --#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E --#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F --#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40 --#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43 --#define TAS5713_DRC_CTRL 0x46 -- --#define TAS5713_BANK_SW_CTRL 0x50 --#define TAS5713_CH1_OUTPUT_MIXER 0x51 --#define TAS5713_CH2_OUTPUT_MIXER 0x52 --#define TAS5713_CH1_INPUT_MIXER 0x53 --#define TAS5713_CH2_INPUT_MIXER 0x54 --#define TAS5713_OUTPUT_POST_SCALE 0x56 --#define TAS5713_OUTPUT_PRESCALE 0x57 -- --#define TAS5713_IDF_POST_SCALE 0x62 -- --#define TAS5713_CH1_INLINE_MIXER 0x70 --#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71 --#define TAS5713_CH1_R_CHANNEL_MIXER 0x72 --#define TAS5713_CH1_L_CHANNEL_MIXER 0x73 --#define TAS5713_CH2_INLINE_MIXER 0x74 --#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75 --#define TAS5713_CH2_L_CHANNEL_MIXER 0x76 --#define TAS5713_CH2_R_CHANNEL_MIXER 0x77 -- --#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8 --#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9 -- --#define TAS5713_REGISTER_COUNT 0x46 --#define TAS5713_MAX_REGISTER 0xF9 -- -- --// Bitmasks for registers --#define TAS5713_SOFT_MUTE_ALL 0x07 -- -- -- --struct tas5713_init_command { -- const int size; -- const char *const data; --}; -- --static const struct tas5713_init_command tas5713_init_sequence[] = { -- -- // Trim oscillator -- { .size = 2, .data = "\x1B\x00" }, -- // System control register 1 (0x03): block DC -- { .size = 2, .data = "\x03\x80" }, -- // Mute everything -- { .size = 2, .data = "\x05\x40" }, -- // Modulation limit register (0x10): 97.7% -- { .size = 2, .data = "\x10\x02" }, -- // Interchannel delay registers -- // (0x11, 0x12, 0x13, and 0x14): BD mode -- { .size = 2, .data = "\x11\xB8" }, -- { .size = 2, .data = "\x12\x60" }, -- { .size = 2, .data = "\x13\xA0" }, -- { .size = 2, .data = "\x14\x48" }, -- // PWM shutdown group register (0x19): no shutdown -- { .size = 2, .data = "\x19\x00" }, -- // Input multiplexer register (0x20): BD mode -- { .size = 2, .data = "\x20\x00\x89\x77\x72" }, -- // PWM output mux register (0x25) -- // Channel 1 --> OUTA, channel 1 neg --> OUTB -- // Channel 2 --> OUTC, channel 2 neg --> OUTD -- { .size = 5, .data = "\x25\x01\x02\x13\x45" }, -- // DRC control (0x46): DRC off -- { .size = 5, .data = "\x46\x00\x00\x00\x00" }, -- // BKND_ERR register (0x1C): 299ms reset period -- { .size = 2, .data = "\x1C\x07" }, -- // Mute channel 3 -- { .size = 2, .data = "\x0A\xFF" }, -- // Volume configuration register (0x0E): volume slew 512 steps -- { .size = 2, .data = "\x0E\x90" }, -- // Clock control register (0x00): 44/48kHz, MCLK=64xfs -- { .size = 2, .data = "\x00\x60" }, -- // Bank switch and eq control (0x50): no bank switching -- { .size = 5, .data = "\x50\x00\x00\x00\x00" }, -- // Volume registers (0x07, 0x08, 0x09, 0x0A) -- { .size = 2, .data = "\x07\x20" }, -- { .size = 2, .data = "\x08\x30" }, -- { .size = 2, .data = "\x09\x30" }, -- { .size = 2, .data = "\x0A\xFF" }, -- // 0x72, 0x73, 0x76, 0x77 input mixer: -- // no intermix between channels -- { .size = 5, .data = "\x72\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x73\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x76\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x77\x00\x80\x00\x00" }, -- // 0x70, 0x71, 0x74, 0x75 inline DRC mixer: -- // no inline DRC inmix -- { .size = 5, .data = "\x70\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x71\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x74\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x75\x00\x00\x00\x00" }, -- // 0x56, 0x57 Output scale -- { .size = 5, .data = "\x56\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x57\x00\x02\x00\x00" }, -- // 0x3B, 0x3c -- { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" }, -- { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" }, -- { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- // 0x51, 0x52: output mixer -- { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" }, -- { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" }, -- // PEQ defaults -- { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, --}; -- -- --#endif /* _TAS5713_H */ - -From d57832b2c5b4c66930109bb8f3093c2cb7af4f07 Mon Sep 17 00:00:00 2001 +From 888492e69472efb4ee72996b3910af74eefa1ce1 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 074/140] Update ds1307 driver for device-tree support +Subject: [PATCH 073/187] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -114045,10 +113227,10 @@ index 4e31036ee2596dec93accd26f627c5b95591ae9f..b92044cf03e750afa521a93519500e9d .driver = { .name = "rtc-ds1307", -From bb9ce0a15501a541ebe0848eaac02cbb6528f18e Mon Sep 17 00:00:00 2001 +From d692e87173ff13253c5e1443ea7ba8761db07411 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 075/140] Add driver for rpi-proto +Subject: [PATCH 074/187] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -114068,10 +113250,10 @@ Signed-off-by: Waldemar Brodkorb create mode 100644 sound/soc/bcm/rpi-proto.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..ac0dbaf29b821c4b21855f22104a986f6e0849ec 100644 +index b1d877407dd69c9bd6b2787b0a559f4113bc21f2..eb5a5a14731bc7a144ac421d89e6a9f5ccfbd235 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -45,6 +45,13 @@ config SND_BCM2708_SOC_RPI_DAC +@@ -52,6 +52,13 @@ config SND_BCM2708_SOC_RPI_DAC help Say Y or M if you want to add support for RPi-DAC. @@ -114086,17 +113268,18 @@ index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..ac0dbaf29b821c4b21855f22104a986f tristate "Support for IQaudIO-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 203afc03167acbcad15e836209956bc5ab151157..3badc43cbe1fcb6972829a6d5eb3143cfa812da9 100644 +index 8ffe0725ba10307b5636a252b6bb8d61ecfe2591..5793c83cf2f53a831f5f49bb46b5bd4515d711a7 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -13,10 +13,12 @@ snd-soc-hifiberry-dac-objs := hifiberry_dac.o +@@ -14,6 +14,7 @@ snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o snd-soc-rpi-dac-objs := rpi-dac.o +snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -21,4 +22,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o @@ -114263,10 +113446,10 @@ index 0000000000000000000000000000000000000000..9db678e885efd63d84d60a098a84ed67 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From b167c67288fd6fe5abff0115b02b5a76e1b92a7b Mon Sep 17 00:00:00 2001 +From 618f202699b0a0ae85c2ae4ba2fa63614a89cd63 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 076/140] RaspiDAC3 support +Subject: [PATCH 075/187] RaspiDAC3 support Signed-off-by: Jan Grulich @@ -114284,10 +113467,10 @@ Signed-off-by: Matthias Reichl create mode 100644 sound/soc/bcm/raspidac3.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index ac0dbaf29b821c4b21855f22104a986f6e0849ec..c59c835757a51aa8ad72933d35a83b73a889477c 100644 +index eb5a5a14731bc7a144ac421d89e6a9f5ccfbd235..a2e74be19fa79e3354583b3d110ecb3286e20f3d 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -58,3 +58,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC +@@ -65,3 +65,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC select SND_SOC_PCM512x_I2C help Say Y or M if you want to add support for IQaudIO-DAC. @@ -114300,18 +113483,18 @@ index ac0dbaf29b821c4b21855f22104a986f6e0849ec..c59c835757a51aa8ad72933d35a83b73 + help + Say Y or M if you want to add support for RaspiDAC Rev.3x. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 3badc43cbe1fcb6972829a6d5eb3143cfa812da9..07d2b52376b1d16e427cf6f51cbf4779d6219ce0 100644 +index 5793c83cf2f53a831f5f49bb46b5bd4515d711a7..c078798106818e3a23f4fbb8068c9ff143b8a2c7 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -15,6 +15,7 @@ snd-soc-hifiberry-digi-objs := hifiberry_digi.o +@@ -16,6 +16,7 @@ snd-soc-hifiberry-digi-objs := hifiberry_digi.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o +snd-soc-raspidac3-objs := raspidac3.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o -@@ -22,3 +23,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o +@@ -24,3 +25,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o @@ -114509,10 +113692,10 @@ index 0000000000000000000000000000000000000000..dd9eeea2af0382307f437e6db09d1546 +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From af90a75803c25ed57bc3099fe73d5224c79a8f82 Mon Sep 17 00:00:00 2001 +From 3dfb83d89a6a376903e882e6d72bd75197298f72 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Thu, 7 Apr 2016 21:26:21 +0100 -Subject: [PATCH 077/140] Add Support for JustBoom Audio boards +Subject: [PATCH 076/187] Add Support for JustBoom Audio boards justboom-dac: Adjust for ALSA API change @@ -114530,10 +113713,10 @@ Signed-off-by: Phil Elwell create mode 100644 sound/soc/bcm/justboom-digi.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index c59c835757a51aa8ad72933d35a83b73a889477c..b2f6339c318cdfe3516d73952a5be1fd32bc1156 100644 +index a2e74be19fa79e3354583b3d110ecb3286e20f3d..1130c52314ece624a5555ec0819edf39667f3990 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -52,6 +52,20 @@ config SND_BCM2708_SOC_RPI_PROTO +@@ -59,6 +59,20 @@ config SND_BCM2708_SOC_RPI_PROTO help Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). @@ -114555,10 +113738,10 @@ index c59c835757a51aa8ad72933d35a83b73a889477c..b2f6339c318cdfe3516d73952a5be1fd tristate "Support for IQaudIO-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 07d2b52376b1d16e427cf6f51cbf4779d6219ce0..cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a 100644 +index c078798106818e3a23f4fbb8068c9ff143b8a2c7..94f5a29386d4e164be428f35d98b007f79dad663 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,6 +12,8 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -13,6 +13,8 @@ snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o @@ -114567,7 +113750,7 @@ index 07d2b52376b1d16e427cf6f51cbf4779d6219ce0..cb8ab1901b172bdee0bd9cddd2f2e7ab snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o -@@ -20,6 +22,8 @@ snd-soc-raspidac3-objs := raspidac3.o +@@ -22,6 +24,8 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o @@ -114966,10 +114149,10 @@ index 0000000000000000000000000000000000000000..91acb666380faa3c0deb2230f8a0f8bb +MODULE_DESCRIPTION("ASoC Driver for JustBoom PI Digi HAT Sound Card"); +MODULE_LICENSE("GPL v2"); -From 0c2b4b8751a7d5b17e6b819610f8a48cea1f98f6 Mon Sep 17 00:00:00 2001 +From cac71895bacf68bfa77f1af57f1a3c621cbad0fc Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Tue, 3 May 2016 22:10:59 -0400 -Subject: [PATCH 078/140] ARM: adau1977-adc: Add basic machine driver for +Subject: [PATCH 077/187] ARM: adau1977-adc: Add basic machine driver for adau1977 codec driver. This commit adds basic support for the codec usage including: Device tree overlay, @@ -114985,10 +114168,10 @@ Signed-off-by: Andrey Grodzovsky create mode 100644 sound/soc/bcm/adau1977-adc.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b2f6339c318cdfe3516d73952a5be1fd32bc1156..190a79dffa53a34c2df9b2c9b5160065c759de65 100644 +index 1130c52314ece624a5555ec0819edf39667f3990..0dbeea9227ec59e0072be4f850b11202485aa2cc 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -80,3 +80,10 @@ config SND_BCM2708_SOC_RASPIDAC3 +@@ -87,3 +87,10 @@ config SND_BCM2708_SOC_RASPIDAC3 select SND_SOC_TPA6130A2 help Say Y or M if you want to add support for RaspiDAC Rev.3x. @@ -115000,7 +114183,7 @@ index b2f6339c318cdfe3516d73952a5be1fd32bc1156..190a79dffa53a34c2df9b2c9b5160065 + help + Say Y or M if you want to add support for ADAU1977 ADC. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a..9dd0785532aae24f3366cc2910d4dbc558cb0e5d 100644 +index 94f5a29386d4e164be428f35d98b007f79dad663..8c20ce506f2b0d653be39ceb9224503a0ef63c39 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile @@ -9,6 +9,7 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o @@ -115008,17 +114191,17 @@ index cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a..9dd0785532aae24f3366cc2910d4dbc5 # BCM2708 Machine Support +snd-soc-adau1977-adc-objs := adau1977-adc.o + snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o -@@ -19,6 +20,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o +@@ -20,6 +21,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-raspidac3-objs := raspidac3.o +obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o diff --git a/sound/soc/bcm/adau1977-adc.c b/sound/soc/bcm/adau1977-adc.c new file mode 100644 index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d2434b0e1 @@ -115151,10 +114334,10 @@ index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d +MODULE_DESCRIPTION("ASoC Driver for ADAU1977 ADC"); +MODULE_LICENSE("GPL v2"); -From 35cd58d093a51d20d9f093eb1963fee33e6d9a07 Mon Sep 17 00:00:00 2001 +From c7210de20ddd76773a54e4cb89f3a6f361379352 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 16 May 2016 21:36:31 +1000 -Subject: [PATCH 079/140] New AudioInjector.net Pi soundcard with low jitter +Subject: [PATCH 078/187] New AudioInjector.net Pi soundcard with low jitter audio in and out. Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile. @@ -115173,10 +114356,10 @@ This patch adds headphone and microphone capability to the Audio Injector sound create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 190a79dffa53a34c2df9b2c9b5160065c759de65..eb16c3a7fb316eb5938a54dfa864f66f9b167eb0 100644 +index 0dbeea9227ec59e0072be4f850b11202485aa2cc..0ebfea3c1cbb59513741818cf65ea8ecc4767515 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -87,3 +87,10 @@ config SND_BCM2708_SOC_ADAU1977_ADC +@@ -94,3 +94,10 @@ config SND_BCM2708_SOC_ADAU1977_ADC select SND_SOC_ADAU1977_I2C help Say Y or M if you want to add support for ADAU1977 ADC. @@ -115188,18 +114371,18 @@ index 190a79dffa53a34c2df9b2c9b5160065c759de65..eb16c3a7fb316eb5938a54dfa864f66f + help + Say Y or M if you want to add support for audioinjector.net Pi Hat diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 9dd0785532aae24f3366cc2910d4dbc558cb0e5d..a68469644535a38305bb5b0f3780e03e0ca4f519 100644 +index 8c20ce506f2b0d653be39ceb9224503a0ef63c39..4d4189b6d0c57645c5ec19554f1e77d4ccc716d6 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -19,6 +19,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o +@@ -20,6 +20,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-raspidac3-objs := raspidac3.o +snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -30,3 +31,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -32,3 +33,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o @@ -115405,10 +114588,10 @@ index 0000000000000000000000000000000000000000..ef54e0f07ea03f59e9957b5d98f3e7fd +MODULE_ALIAS("platform:audioinjector-pi-soundcard"); + -From fc549ae82d8c88a4b51d129b4ed5f4aa1ef55b62 Mon Sep 17 00:00:00 2001 +From d2611b7c324fff94443f868061b6651906baa155 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Thu, 30 Jun 2016 18:38:42 +0100 -Subject: [PATCH 080/140] Add IQAudIO Digi WM8804 board support +Subject: [PATCH 079/187] Add IQAudIO Digi WM8804 board support Support IQAudIO Digi board with iqaudio_digi machine driver and iqaudio-digi-wm8804-audio overlay. @@ -115425,10 +114608,10 @@ Signed-off-by: DigitalDreamtime create mode 100644 sound/soc/bcm/iqaudio_digi.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index eb16c3a7fb316eb5938a54dfa864f66f9b167eb0..9cba69ab877ef73beb2dff2f4f82d1d243f7c604 100644 +index 0ebfea3c1cbb59513741818cf65ea8ecc4767515..24723d09e7bda0c6c06292b159220b180310b12b 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -73,6 +73,13 @@ config SND_BCM2708_SOC_IQAUDIO_DAC +@@ -80,6 +80,13 @@ config SND_BCM2708_SOC_IQAUDIO_DAC help Say Y or M if you want to add support for IQaudIO-DAC. @@ -115443,10 +114626,10 @@ index eb16c3a7fb316eb5938a54dfa864f66f9b167eb0..9cba69ab877ef73beb2dff2f4f82d1d2 tristate "Support for RaspiDAC Rev.3x" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a68469644535a38305bb5b0f3780e03e0ca4f519..fa2739206b79a9f9d2e1173b2099e1156e4e08c8 100644 +index 4d4189b6d0c57645c5ec19554f1e77d4ccc716d6..ee41d6bbdbbda2913aba143a59b4953e800bdb3c 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -18,6 +18,7 @@ snd-soc-justboom-digi-objs := justboom-digi.o +@@ -19,6 +19,7 @@ snd-soc-justboom-digi-objs := justboom-digi.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o @@ -115454,7 +114637,7 @@ index a68469644535a38305bb5b0f3780e03e0ca4f519..fa2739206b79a9f9d2e1173b2099e115 snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o -@@ -30,6 +31,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o +@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o @@ -115708,10 +114891,10 @@ index 0000000000000000000000000000000000000000..9b6e829bcb5b1762a853775e78163196 +MODULE_DESCRIPTION("ASoC Driver for IQAudIO WM8804 Digi"); +MODULE_LICENSE("GPL v2"); -From bd20905a5f6f0e22433f9e56d83dc838c77d16b3 Mon Sep 17 00:00:00 2001 +From f33b80d08fc3c8155844b48da5fe553be1f41f44 Mon Sep 17 00:00:00 2001 From: escalator2015 Date: Tue, 24 May 2016 16:20:09 +0100 -Subject: [PATCH 081/140] New driver for RRA DigiDAC1 soundcard using WM8741 + +Subject: [PATCH 080/187] New driver for RRA DigiDAC1 soundcard using WM8741 + WM8804 --- @@ -115722,10 +114905,10 @@ Subject: [PATCH 081/140] New driver for RRA DigiDAC1 soundcard using WM8741 + create mode 100644 sound/soc/bcm/digidac1-soundcard.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 9cba69ab877ef73beb2dff2f4f82d1d243f7c604..2be5b64fb0d5dcad0d5747626015a6886c3c273b 100644 +index 24723d09e7bda0c6c06292b159220b180310b12b..c432ef568823787baeccd296be0c107ca8c124ab 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -101,3 +101,11 @@ config SND_AUDIOINJECTOR_PI_SOUNDCARD +@@ -108,3 +108,11 @@ config SND_AUDIOINJECTOR_PI_SOUNDCARD select SND_SOC_WM8731 help Say Y or M if you want to add support for audioinjector.net Pi Hat @@ -115738,18 +114921,18 @@ index 9cba69ab877ef73beb2dff2f4f82d1d243f7c604..2be5b64fb0d5dcad0d5747626015a688 + help + Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index fa2739206b79a9f9d2e1173b2099e1156e4e08c8..a5c30c0bdacafb2bd09b6ac2f8a3bdc6a85a8404 100644 +index ee41d6bbdbbda2913aba143a59b4953e800bdb3c..855f4dbe574fcb725b0309710611fa381e1e29d6 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -21,6 +21,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac.o +@@ -22,6 +22,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-iqaudio-digi-objs := iqaudio_digi.o snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o +snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -34,4 +35,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -36,4 +37,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o @@ -116184,10 +115367,10 @@ index 0000000000000000000000000000000000000000..446796e7e4c14a7d95b2f2a01211d9a0 +MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1"); +MODULE_LICENSE("GPL v2"); -From d769f04e989d8ca654b67d64f021982382e75f47 Mon Sep 17 00:00:00 2001 +From 4948d886046e68390cb574d40b9741681c040a11 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Sat, 2 Jul 2016 16:26:19 +0100 -Subject: [PATCH 082/140] Add support for Dion Audio LOCO DAC-AMP HAT +Subject: [PATCH 081/187] Add support for Dion Audio LOCO DAC-AMP HAT Using dedicated machine driver and pcm5102a codec driver. @@ -116200,10 +115383,10 @@ Signed-off-by: DigitalDreamtime create mode 100644 sound/soc/bcm/dionaudio_loco.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 2be5b64fb0d5dcad0d5747626015a6886c3c273b..b8cb5eb7af9b3e6d8d100926e04bfef629641d1d 100644 +index c432ef568823787baeccd296be0c107ca8c124ab..668d163c37051dddafa6ee6d0984705966c883ef 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -109,3 +109,10 @@ config SND_DIGIDAC1_SOUNDCARD +@@ -116,3 +116,10 @@ config SND_DIGIDAC1_SOUNDCARD select SND_SOC_WM8741 help Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board. @@ -116215,18 +115398,18 @@ index 2be5b64fb0d5dcad0d5747626015a6886c3c273b..b8cb5eb7af9b3e6d8d100926e04bfef6 + help + Say Y or M if you want to add support for Dion Audio LOCO. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a5c30c0bdacafb2bd09b6ac2f8a3bdc6a85a8404..28cdf019dbc7aafda194c83817d260ad1a477666 100644 +index 855f4dbe574fcb725b0309710611fa381e1e29d6..fca9d682bbd2e7821ae01aefc7a5a94e0880a41e 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -22,6 +22,7 @@ snd-soc-iqaudio-digi-objs := iqaudio_digi.o +@@ -23,6 +23,7 @@ snd-soc-iqaudio-digi-objs := iqaudio_digi.o snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o +snd-soc-dionaudio-loco-objs := dionaudio_loco.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -36,4 +37,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -38,4 +39,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o @@ -116360,10 +115543,10 @@ index 0000000000000000000000000000000000000000..89e65317512bc774453ac8d0d5b0ff98 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO"); +MODULE_LICENSE("GPL v2"); -From f8dbc341d0ecfa295a817771e693b2e37612c20c Mon Sep 17 00:00:00 2001 +From 852ce462975b2c46948a559739463d913ede1326 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Mon, 19 Sep 2016 14:01:04 +0100 -Subject: [PATCH 083/140] Allo Piano DAC boards: Initial 2 channel (stereo) +Subject: [PATCH 082/187] Allo Piano DAC boards: Initial 2 channel (stereo) support (#1645) Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards, @@ -116388,10 +115571,10 @@ Tested-by: Clive Messer create mode 100644 sound/soc/bcm/allo-piano-dac.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b8cb5eb7af9b3e6d8d100926e04bfef629641d1d..4f0330a6c06115f077938cba3dc744d4ae10f056 100644 +index 668d163c37051dddafa6ee6d0984705966c883ef..4e83bd6b1703a0bd3de60ad8c799e0cd3bc16b66 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -116,3 +116,10 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO +@@ -123,3 +123,10 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO select SND_SOC_PCM5102a help Say Y or M if you want to add support for Dion Audio LOCO. @@ -116403,18 +115586,18 @@ index b8cb5eb7af9b3e6d8d100926e04bfef629641d1d..4f0330a6c06115f077938cba3dc744d4 + help + Say Y or M if you want to add support for Allo Piano DAC. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 28cdf019dbc7aafda194c83817d260ad1a477666..4b94a42efecaee41df37f3c59fddefa5fe78521c 100644 +index fca9d682bbd2e7821ae01aefc7a5a94e0880a41e..64f007f8ba38276a42e0bd8db92544db9412544b 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -23,6 +23,7 @@ snd-soc-raspidac3-objs := raspidac3.o +@@ -24,6 +24,7 @@ snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o snd-soc-dionaudio-loco-objs := dionaudio_loco.o +snd-soc-allo-piano-dac-objs := allo-piano-dac.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -38,3 +39,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -40,3 +41,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o @@ -116570,10 +115753,10 @@ index 0000000000000000000000000000000000000000..8e8e62e5a36a279b425ed4655cfbac99 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC"); +MODULE_LICENSE("GPL v2"); -From e1275c43efe1053a9916fb11e27b286338f87195 Mon Sep 17 00:00:00 2001 +From cd1a43e18d800ec4c2c8a7c5350bc1e13b267169 Mon Sep 17 00:00:00 2001 From: gtrainavicius Date: Sun, 23 Oct 2016 12:06:53 +0300 -Subject: [PATCH 084/140] Support for Blokas Labs pisound board +Subject: [PATCH 083/187] Support for Blokas Labs pisound board Pisound dynamic overlay (#1760) @@ -116724,10 +115907,10 @@ index 7cdfc29ba4fbffd3216376677922e7ae26019055..5197e656a3d741d14bd9dd6c812b4b93 - }; }; diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4f0330a6c06115f077938cba3dc744d4ae10f056..a0ef6a028136beb27ed13a4136712a70a60f2966 100644 +index 4e83bd6b1703a0bd3de60ad8c799e0cd3bc16b66..d024377e8450fb5402dcb5ea27161f774b04a8ec 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -123,3 +123,9 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC +@@ -130,3 +130,9 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC select SND_SOC_PCM512x_I2C help Say Y or M if you want to add support for Allo Piano DAC. @@ -116738,18 +115921,18 @@ index 4f0330a6c06115f077938cba3dc744d4ae10f056..a0ef6a028136beb27ed13a4136712a70 + help + Say Y or M if you want to add support for Blokas Labs pisound. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 4b94a42efecaee41df37f3c59fddefa5fe78521c..f720a3d3b5832844ee6d0558317c728f00c40b65 100644 +index 64f007f8ba38276a42e0bd8db92544db9412544b..bb1df438540193652ec5464e8bc51f636a1b844e 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -24,6 +24,7 @@ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o +@@ -25,6 +25,7 @@ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o snd-soc-dionaudio-loco-objs := dionaudio_loco.o snd-soc-allo-piano-dac-objs := allo-piano-dac.o +snd-soc-pisound-objs := pisound.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -40,3 +41,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundca + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -42,3 +43,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundca obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o @@ -117750,10 +116933,10 @@ index 0000000000000000000000000000000000000000..4b8545487d06e4ea70073a5d063fb231 +MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound"); +MODULE_LICENSE("GPL v2"); -From cb9c788998e6d04f2095a3d079a294389886f22a Mon Sep 17 00:00:00 2001 +From 7b14e374b8add26dc1d2d883d190e43c85820325 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 085/140] rpi_display: add backlight driver and overlay +Subject: [PATCH 084/187] rpi_display: add backlight driver and overlay Add a mailbox-driven backlight controller for the Raspberry Pi DSI touchscreen display. Requires updated GPU firmware to recognise the @@ -117922,10 +117105,10 @@ index 0000000000000000000000000000000000000000..14a0d9b037395497c1fdae2961feccd5 +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); -From 1e42c44b40a1be7fc26e92375504e9008156490a Mon Sep 17 00:00:00 2001 +From 3b430599904c04d437a81f7a1c287bc6e4c35532 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Feb 2016 19:56:04 +0000 -Subject: [PATCH 086/140] bcm2835-virtgpio: Virtual GPIO driver +Subject: [PATCH 085/187] bcm2835-virtgpio: Virtual GPIO driver Add a virtual GPIO driver that uses the firmware mailbox interface to request that the VPU toggles LEDs. @@ -118199,10 +117382,10 @@ index b0f6e33bd30c35664ceee057f4c3ad32b914291d..e92278968b2b979db2a1f855f70e7aaf RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From c8452a4f0c6aecede8c8cd2e0f8d571df62f7d77 Mon Sep 17 00:00:00 2001 +From e46e675846fab8bd468653486071b72afbd6ef6b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 23 Feb 2016 17:26:48 +0000 -Subject: [PATCH 087/140] amba_pl011: Don't use DT aliases for numbering +Subject: [PATCH 086/187] amba_pl011: Don't use DT aliases for numbering The pl011 driver looks for DT aliases of the form "serial", and if found uses as the device ID. This can cause @@ -118231,10 +117414,10 @@ index e2c33b9528d82ed7a2c27d083d7b1d222da68178..5a11ff833e1fd112ba04df3a427cd94b uap->old_cr = 0; uap->port.dev = dev; -From d1429c129c393594f65f2da36b42687973498747 Mon Sep 17 00:00:00 2001 +From 6324540ac51de67caef39b5281b005c77372e74d Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 3 Dec 2014 13:23:28 +0200 -Subject: [PATCH 088/140] OF: DT-Overlay configfs interface +Subject: [PATCH 087/187] OF: DT-Overlay configfs interface This is a port of Pantelis Antoniou's v3 port that makes use of the new upstreamed configfs support for binary attributes. @@ -118666,10 +117849,10 @@ index 0000000000000000000000000000000000000000..0037e6868a6cda8706c88194c6a4454b +} +late_initcall(of_cfs_init); -From 375ba3269f5ef7044260d9ee190c936fc72c9836 Mon Sep 17 00:00:00 2001 +From bfbb95a2357ad45f96920b21216a0061d89ae04a Mon Sep 17 00:00:00 2001 From: Cheong2K Date: Fri, 26 Feb 2016 18:20:10 +0800 -Subject: [PATCH 089/140] brcm: adds support for BCM43341 wifi +Subject: [PATCH 088/187] brcm: adds support for BCM43341 wifi brcmfmac: Disable power management @@ -118832,10 +118015,10 @@ index d0407d9ad7827cd756b6311410ffe2d9a7cacc78..f1fb8a3c7a3211e8429585861f2f42e0 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 -From 5c75e3d1bc4df013f745e78385f458613bf7b32e Mon Sep 17 00:00:00 2001 +From d08b3b2e366e63348adc2ed3601f184bc00aa80c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 17 Dec 2015 13:37:07 +0000 -Subject: [PATCH 090/140] hci_h5: Don't send conf_req when ACTIVE +Subject: [PATCH 089/187] hci_h5: Don't send conf_req when ACTIVE Without this patch, a modem and kernel can continuously bombard each other with conf_req and conf_rsp messages, in a demented game of tag. @@ -118858,10 +118041,10 @@ index 0879d64b1caf58afb6e5d494c07d9ab7e7cdf983..5161ab30fd533d50f516bb93d5b9f402 if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data[2] & 0x07); -From 1fbc772f5f537bdab6e27783d6acc2d10e7aecec Mon Sep 17 00:00:00 2001 +From 3490894ce5d697151ca18d1125e865f0aa5cd499 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 091/140] config: Add default configs +Subject: [PATCH 090/187] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1297 +++++++++++++++++++++++++++++++++++ @@ -121488,10 +120671,10 @@ index 0000000000000000000000000000000000000000..8acee9f31202ec14f2933d92dd70831c +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From e565c8cc4a7024d22170905c846b8545cd7fa662 Mon Sep 17 00:00:00 2001 +From 9d9231cb2087d2b16c74d7be316aa81d23f94929 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Wed, 24 Aug 2016 03:35:56 -0700 -Subject: [PATCH 092/140] Add arm64 configuration and device tree differences. +Subject: [PATCH 091/187] Add arm64 configuration and device tree differences. Disable MMC_BCM2835_SDHOST and MMC_BCM2835 since these drivers are crashing at the moment. @@ -122906,10 +122089,10 @@ index 0000000000000000000000000000000000000000..d7406f5a4620151044b8f716b4d10bb8 +CONFIG_LIBCRC32C=y +CONFIG_BCM2708_VCHIQ=n -From 35fd48cb4edfef0dbf91800e07655db35533305a Mon Sep 17 00:00:00 2001 +From 20fb3a0e5c039dbdef223ca31bdf8e56e50ae601 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 7 Mar 2016 15:05:11 +0000 -Subject: [PATCH 093/140] vchiq_arm: Tweak the logging output +Subject: [PATCH 092/187] vchiq_arm: Tweak the logging output Signed-off-by: Phil Elwell --- @@ -122984,10 +122167,10 @@ index 2c98da4307dff994a00dc246574ef0aaee05d5da..160db24aeea33a8296923501009c1f02 switch (type) { -From 7ec1488f0ba404ea96cfee0f8f28bbdbab20a7d6 Mon Sep 17 00:00:00 2001 +From 601d9ca790405317d2d4b02bb9b88b7397bf3ddb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 14:16:25 +0000 -Subject: [PATCH 094/140] vchiq_arm: Access the dequeue_pending flag locked +Subject: [PATCH 093/187] vchiq_arm: Access the dequeue_pending flag locked Reading through this code looking for another problem (now found in userland) the use of dequeue_pending outside a lock didn't seem safe. @@ -123045,10 +122228,10 @@ index 7b6cd4d80621e38ff6d47fcd87b45fbe9cd4259b..d8669fa7f39b077877eca1829ba9538b return add_completion(instance, reason, header, user_service, -From f17f2d01f807587bb82898dad5753c74ad5e966c Mon Sep 17 00:00:00 2001 +From 2f27e6a032314fbb27c3859a96fa49fe99b53b04 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 20:53:47 +0000 -Subject: [PATCH 095/140] vchiq_arm: Service callbacks must not fail +Subject: [PATCH 094/187] vchiq_arm: Service callbacks must not fail Service callbacks are not allowed to return an error. The internal callback that delivers events and messages to user tasks does not enqueue them if @@ -123074,10 +122257,10 @@ index d8669fa7f39b077877eca1829ba9538bf2e21a82..54552c6ce54f413c9781ba279b936f98 DEBUG_TRACE(SERVICE_CALLBACK_LINE); } -From 357aa48f33262ca57a65682b9b9e70a13ecada2d Mon Sep 17 00:00:00 2001 +From c04c96f22141ed319200757d1c1dad8cbd2e3658 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 21 Apr 2016 13:49:32 +0100 -Subject: [PATCH 096/140] vchiq_arm: Add completion records under the mutex +Subject: [PATCH 095/187] vchiq_arm: Add completion records under the mutex An issue was observed when flushing openmax components which generate a large number of messages returning @@ -123140,10 +122323,10 @@ index 54552c6ce54f413c9781ba279b936f98be4f47b0..bde8955b7d8505d73579b77b5b392154 return VCHIQ_SUCCESS; -From e55fbce2a8a409274e1f13ceceb9fa856f3241bf Mon Sep 17 00:00:00 2001 +From 5305ba9a2ed0c51be45ee36fa9c547413341612c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jun 2016 13:51:44 +0100 -Subject: [PATCH 097/140] vchiq_arm: Avoid use of mutex in add_completion +Subject: [PATCH 096/187] vchiq_arm: Avoid use of mutex in add_completion Claiming the completion_mutex within add_completion did prevent some messages appearing twice, but provokes a deadlock caused by vcsm using @@ -123337,10 +122520,10 @@ index 160db24aeea33a8296923501009c1f02bc41e599..71a3bedc55314f3b22dbff40c05dedf0 up(&state->slot_available_event); } -From 79c80fcffa0edd56fd39cde6225a8595d20b8e13 Mon Sep 17 00:00:00 2001 +From 3f088bf35e3319a4efcf593c7eb717429f59c783 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:14:10 -0700 -Subject: [PATCH 098/140] staging/vchi: Convert to current get_user_pages() +Subject: [PATCH 097/187] staging/vchi: Convert to current get_user_pages() arguments. Signed-off-by: Eric Anholt @@ -123377,10 +122560,10 @@ index e5cdda12c7e5c35c69eb96991cfdb8326def167f..085d37588c59198b4e5f00b9249bb842 num_pages, /* len */ 0, /* gup_flags */ -From 1e387fd101bc3670fe99c7470ccce6a0a73a82ef Mon Sep 17 00:00:00 2001 +From aca21ab5ab5b57a8f013380ff7f2b9dfff14636a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:16:03 -0700 -Subject: [PATCH 099/140] staging/vchi: Update for rename of +Subject: [PATCH 098/187] staging/vchi: Update for rename of page_cache_release() to put_page(). Signed-off-by: Eric Anholt @@ -123425,10 +122608,10 @@ index 085d37588c59198b4e5f00b9249bb8421695854f..5a2b8fb459ebe086ec229f37b6381bdb kfree(pages); } -From fa0f59766f7817bbafb26e74fabadf9770cd0c54 Mon Sep 17 00:00:00 2001 +From 789222dfdfbfdcfbc2513f3680fc13c1dded8050 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:21:17 -0700 -Subject: [PATCH 100/140] drivers/vchi: Remove dependency on CONFIG_BROKEN. +Subject: [PATCH 099/187] drivers/vchi: Remove dependency on CONFIG_BROKEN. The driver builds now. @@ -123450,10 +122633,10 @@ index 9676fb29075a457109e4d4235f086987aec74868..db8e1beb89f9f8c48ea5964016c8285e help Kernel to VideoCore communication interface for the -From 348cb13e9eb0943b5a3d2ccc9f8447bd906fafb9 Mon Sep 17 00:00:00 2001 +From 13af1452d680d811bb10721f7b08b9b6a2718ccc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:16:19 +0100 -Subject: [PATCH 101/140] raspberrypi-firmware: Export the general transaction +Subject: [PATCH 100/187] raspberrypi-firmware: Export the general transaction function. The vc4-firmware-kms module is going to be doing the MBOX FB call. @@ -123497,10 +122680,10 @@ index e92278968b2b979db2a1f855f70e7aafb224fa98..09e3d871d110eb0762ebdb5ea3293537 #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -From 1464fdba20dabf739325675298b8cfc94751a531 Mon Sep 17 00:00:00 2001 +From abd4f74c5ead8e51449e3196fda2868f07db87b2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:18:09 +0100 -Subject: [PATCH 102/140] raspberrypi-firmware: Define the MBOX channel in the +Subject: [PATCH 101/187] raspberrypi-firmware: Define the MBOX channel in the header. Signed-off-by: Eric Anholt @@ -123522,10 +122705,10 @@ index 09e3d871d110eb0762ebdb5ea329353738d58661..2859db09e25bb945251e85edb39bc434 enum rpi_firmware_property_status { -From da93c067a6faf0915da62d4763d15fec197e4632 Mon Sep 17 00:00:00 2001 +From 223f7c7232f19ded00dad5e51e2ac13f3c004d1c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 08:39:33 +0100 -Subject: [PATCH 103/140] drm/vc4: Add a mode for using the closed firmware for +Subject: [PATCH 102/187] drm/vc4: Add a mode for using the closed firmware for display. Signed-off-by: Eric Anholt @@ -124292,10 +123475,10 @@ index 0000000000000000000000000000000000000000..d18a1dae51a2275846c9826b5bf1ba57 + }, +}; -From 0c64daf4fec58a7f3bc174a3d73e3ac845f65b86 Mon Sep 17 00:00:00 2001 +From 2c21818d67bd9603071d0920fa147617c8ef5d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 17 Sep 2016 15:07:10 +0200 -Subject: [PATCH 104/140] i2c: bcm2835: Fix hang for writing messages larger +Subject: [PATCH 103/187] i2c: bcm2835: Fix hang for writing messages larger than 16 bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124385,10 +123568,10 @@ index d4f3239b56865919e1b781b20a7c5ebcd76b4eb9..f283b714aa79e2e4685ed95b04b6b289 i2c_dev->msg_buf_remaining = msg->len; reinit_completion(&i2c_dev->completion); -From 0aaf65741593a9fd06e98263363832bd498cc2f7 Mon Sep 17 00:00:00 2001 +From bd85fc46ace73c104fa58bc8f0747609ffef341b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 18:24:38 +0200 -Subject: [PATCH 105/140] i2c: bcm2835: Protect against unexpected TXW/RXR +Subject: [PATCH 104/187] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124513,10 +123696,10 @@ index f283b714aa79e2e4685ed95b04b6b289f7e9eee7..d2ba1a4de36af512e8e3c97251bd3537 return -ETIMEDOUT; } -From 37f07694782131d58654fdddec13530647665c41 Mon Sep 17 00:00:00 2001 +From 7410e42e332b47dd3ac0b0fc44953b24f941429f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 19 Sep 2016 17:19:41 +0200 -Subject: [PATCH 106/140] i2c: bcm2835: Use dev_dbg logging on transfer errors +Subject: [PATCH 105/187] i2c: bcm2835: Use dev_dbg logging on transfer errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124548,10 +123731,10 @@ index d2ba1a4de36af512e8e3c97251bd3537ae61591a..54d510abd46a117c9238fc6d7edec840 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From ecacf486b572638bc4f48ec95ce7487176db6379 Mon Sep 17 00:00:00 2001 +From 588f321b996ccfac8f507323d61c8a530d0e67a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 22 Sep 2016 22:05:50 +0200 -Subject: [PATCH 107/140] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK +Subject: [PATCH 106/187] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124595,10 +123778,10 @@ index 54d510abd46a117c9238fc6d7edec84019d1f60d..565ef69ce61423544dc0558c85ef318b if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) -From f1d345c2d724219a84d35c6b5a0f7c245a350fdc Mon Sep 17 00:00:00 2001 +From 6b38636136ea4492ede6905ae66c53d1c72630d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:54:27 +0200 -Subject: [PATCH 108/140] i2c: bcm2835: Add support for Repeated Start +Subject: [PATCH 107/187] i2c: bcm2835: Add support for Repeated Start Condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124780,10 +123963,10 @@ index 565ef69ce61423544dc0558c85ef318b0ae9c324..241e08ae7c27cec23fad3c1bf3ebad3a static u32 bcm2835_i2c_func(struct i2c_adapter *adap) -From a4506104d5e6a1163413848796c70bafeb83b529 Mon Sep 17 00:00:00 2001 +From fcb0461ba98a06eb4fe21701f8f075cf9926d437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:57:17 +0200 -Subject: [PATCH 109/140] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT +Subject: [PATCH 108/187] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124820,10 +124003,10 @@ index 241e08ae7c27cec23fad3c1bf3ebad3a4d2a8e6f..d2085dd3742eabebc537621968088261 bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -From bc8206e909535c9cf57538b0c5121b98a880017f Mon Sep 17 00:00:00 2001 +From 8e1ede04b3ed0f4caa6f350bf079c5c39536d786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 27 Sep 2016 01:00:08 +0200 -Subject: [PATCH 110/140] i2c: bcm2835: Add support for dynamic clock +Subject: [PATCH 109/187] i2c: bcm2835: Add support for dynamic clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124939,10 +124122,10 @@ index d2085dd3742eabebc537621968088261f8dc7ea8..c3436f627028477f7e21b47e079fd5ab irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { -From 15d85dfe50f97f181498356e9ef735aa45adcd1d Mon Sep 17 00:00:00 2001 +From 3e3241d385371be14a6beb09565a5046ae9474dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 1 Nov 2016 15:15:41 +0100 -Subject: [PATCH 111/140] i2c: bcm2835: Add debug support +Subject: [PATCH 110/187] i2c: bcm2835: Add debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -125131,10 +124314,10 @@ index c3436f627028477f7e21b47e079fd5ab06ec188a..8642f580ce41803bd22c76a0fa80d083 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From e28b55c5e8d7411c32f6ec15101276060c71c7d1 Mon Sep 17 00:00:00 2001 +From 64556f2c8cd15271c6932c41e3c1722ea5c2a7a2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 31 Dec 2016 14:15:50 +0000 -Subject: [PATCH 112/140] arm64: Add CONFIG_ARCH_BCM2835 +Subject: [PATCH 111/187] arm64: Add CONFIG_ARCH_BCM2835 --- arch/arm64/configs/bcmrpi3_defconfig | 1 + @@ -125150,10 +124333,10 @@ index d7406f5a4620151044b8f716b4d10bb818648e06..53da5c7a33e5898a66e549fb0c39fe3d CONFIG_BCM2708_VCHIQ=n +CONFIG_ARCH_BCM2835=y -From 504cbe6331e8e2fb20532f2cd78d39dc04f5ff54 Mon Sep 17 00:00:00 2001 +From 23096cda9201811a9f0a7e5ae9bacd047deb126b Mon Sep 17 00:00:00 2001 From: Alex Tucker Date: Tue, 13 Dec 2016 19:50:18 +0000 -Subject: [PATCH 113/140] Add support for Silicon Labs Si7013/20/21 +Subject: [PATCH 112/187] Add support for Silicon Labs Si7013/20/21 humidity/temperature sensor. --- @@ -125228,10 +124411,10 @@ index f6d134c095af2398fc55ae7d2b0e86456c30627c..31bda8da4cb6a56bfe493a81b9189009 }; }; -From 7fd3189681ab1e4bcde0efba4d7b9cb92f5bce72 Mon Sep 17 00:00:00 2001 +From 272d577c609238d107527ed6b7120d2b4c3f373c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Jan 2017 21:27:46 +0000 -Subject: [PATCH 114/140] Document the si7020 option +Subject: [PATCH 113/187] Document the si7020 option --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -125252,10 +124435,10 @@ index 81d991803be335e5a1bc3bb0a8c7a2c9f5c392bd..e8fa4ccb44c34a20485c4e6155467af9 Name: i2c0-bcm2708 Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations -From ceb29f8e53ca711738de6c72eeb9d9cb3a857575 Mon Sep 17 00:00:00 2001 +From 0a5470acf780e9ce5aff826f1f9592f298f0df08 Mon Sep 17 00:00:00 2001 From: Giedrius Trainavicius Date: Thu, 5 Jan 2017 02:38:16 +0200 -Subject: [PATCH 115/140] pisound improvements: +Subject: [PATCH 114/187] pisound improvements: * Added a writable sysfs object to enable scripts / user space software to blink MIDI activity LEDs for variable duration. @@ -125549,958 +124732,10 @@ index 4b8545487d06e4ea70073a5d063fb2310b3b94d0..ba70734b89e61a11201657406223f0b3 }; -From f431961cbef359e679dcecd15eac69489e537d07 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 9 Jan 2017 09:23:06 +0000 -Subject: [PATCH 116/140] Revert "Revert "Added driver for HiFiBerry Amp - amplifier add-on board"" - -This reverts commit bf84babd8fffcb79c60f1342c2416f8e1e4b7af9. ---- - sound/soc/bcm/Kconfig | 7 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_amp.c | 129 +++++++++++++++ - sound/soc/codecs/Kconfig | 4 + - sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++ - sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++ - 7 files changed, 723 insertions(+) - create mode 100644 sound/soc/bcm/hifiberry_amp.c - create mode 100644 sound/soc/codecs/tas5713.c - create mode 100644 sound/soc/codecs/tas5713.h - -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index a0ef6a028136beb27ed13a4136712a70a60f2966..d024377e8450fb5402dcb5ea27161f774b04a8ec 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -38,6 +38,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI - help - Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. - -+config SND_BCM2708_SOC_HIFIBERRY_AMP -+ tristate "Support for the HifiBerry Amp" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_TAS5713 -+ help -+ Say Y or M if you want to add support for the HifiBerry Amp amplifier board. -+ - config SND_BCM2708_SOC_RPI_DAC - tristate "Support for RPi-DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index f720a3d3b5832844ee6d0558317c728f00c40b65..bb1df438540193652ec5464e8bc51f636a1b844e 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o - - # BCM2708 Machine Support - snd-soc-adau1977-adc-objs := adau1977-adc.o -+snd-soc-hifiberry-amp-objs := hifiberry_amp.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o -@@ -27,6 +28,7 @@ snd-soc-allo-piano-dac-objs := allo-piano-dac.o - snd-soc-pisound-objs := pisound.o - - obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o -diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d17c29780507dc31c50f1d567ff5cea7c8241ff5 ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_amp.c -@@ -0,0 +1,129 @@ -+/* -+ * ASoC Driver for HifiBerry AMP -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ // ToDo: init of the dsp-registers. -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params ) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); -+} -+ -+static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = { -+ .hw_params = snd_rpi_hifiberry_amp_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { -+ { -+ .name = "HifiBerry AMP", -+ .stream_name = "HifiBerry AMP HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "tas5713-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "tas5713.1-001b", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_amp_ops, -+ .init = snd_rpi_hifiberry_amp_init, -+ }, -+}; -+ -+ -+static struct snd_soc_card snd_rpi_hifiberry_amp = { -+ .name = "snd_rpi_hifiberry_amp", -+ .driver_name = "HifiberryAmp", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_amp_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), -+}; -+ -+static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-amp", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match); -+ -+ -+static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_hifiberry_amp.dev = &pdev->dev; -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ -+ if (i2s_node) { -+ dai->cpu_dai_name = NULL; -+ dai->cpu_of_node = i2s_node; -+ dai->platform_name = NULL; -+ dai->platform_of_node = i2s_node; -+ } -+ } -+ -+ ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); -+ -+ if (ret != 0) { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_hifiberry_amp); -+} -+ -+ -+static struct platform_driver snd_rpi_hifiberry_amp_driver = { -+ .driver = { -+ .name = "snd-hifiberry-amp", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_amp_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_amp_probe, -+ .remove = snd_rpi_hifiberry_amp_remove, -+}; -+ -+ -+module_platform_driver(snd_rpi_hifiberry_amp_driver); -+ -+ -+MODULE_AUTHOR("Sebastian Eickhoff "); -+MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 74a93e52bdc8116df3db08aaf98fffa1e6f6cc1b..9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -139,6 +139,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_TFA9879 if I2C - select SND_SOC_TLV320AIC23_I2C if I2C - select SND_SOC_TLV320AIC23_SPI if SPI_MASTER -+ select SND_SOC_TAS5713 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC31XX if I2C - select SND_SOC_TLV320AIC32X4_I2C if I2C -@@ -821,6 +822,9 @@ config SND_SOC_TFA9879 - tristate "NXP Semiconductors TFA9879 amplifier" - depends on I2C - -+config SND_SOC_TAS5713 -+ tristate -+ - config SND_SOC_TLV320AIC23 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 77786e7f44a7fa22d9b5beed3eb687e2b7a28526..5a2db0d2fe2f49920eeccfecef62c969ae2e99a1 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -144,6 +144,7 @@ snd-soc-tas5086-objs := tas5086.o - snd-soc-tas571x-objs := tas571x.o - snd-soc-tas5720-objs := tas5720.o - snd-soc-tfa9879-objs := tfa9879.o -+snd-soc-tas5713-objs := tas5713.o - snd-soc-tlv320aic23-objs := tlv320aic23.o - snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o - snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o -@@ -366,6 +367,7 @@ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o - obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o - obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o - obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o -+obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o - obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1eae5867411 ---- /dev/null -+++ b/sound/soc/codecs/tas5713.c -@@ -0,0 +1,369 @@ -+/* -+ * ASoC Driver for TAS5713 -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "tas5713.h" -+ -+ -+static struct i2c_client *i2c; -+ -+struct tas5713_priv { -+ struct regmap *regmap; -+ int mclk_div; -+ struct snd_soc_codec *codec; -+}; -+ -+static struct tas5713_priv *priv_data; -+ -+ -+ -+ -+/* -+ * _ _ ___ _ ___ _ _ -+ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___ -+ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-< -+ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/ -+ * -+ */ -+ -+static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1); -+ -+ -+static const struct snd_kcontrol_new tas5713_snd_controls[] = { -+ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv), -+ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv) -+}; -+ -+ -+ -+ -+/* -+ * __ __ _ _ ___ _ -+ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _ -+ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_| -+ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static int tas5713_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ u16 blen = 0x00; -+ -+ struct snd_soc_codec *codec; -+ codec = dai->codec; -+ priv_data->codec = dai->codec; -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ blen = 0x03; -+ break; -+ case SNDRV_PCM_FORMAT_S20_3LE: -+ blen = 0x1; -+ break; -+ case SNDRV_PCM_FORMAT_S24_LE: -+ blen = 0x04; -+ break; -+ case SNDRV_PCM_FORMAT_S32_LE: -+ blen = 0x05; -+ break; -+ default: -+ dev_err(dai->dev, "Unsupported word length: %u\n", -+ params_format(params)); -+ return -EINVAL; -+ } -+ -+ // set word length -+ snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen); -+ -+ return 0; -+} -+ -+ -+static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream) -+{ -+ unsigned int val = 0; -+ -+ struct tas5713_priv *tas5713; -+ struct snd_soc_codec *codec = dai->codec; -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ if (mute) { -+ val = TAS5713_SOFT_MUTE_ALL; -+ } -+ -+ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val); -+} -+ -+ -+static const struct snd_soc_dai_ops tas5713_dai_ops = { -+ .hw_params = tas5713_hw_params, -+ .mute_stream = tas5713_mute_stream, -+}; -+ -+ -+static struct snd_soc_dai_driver tas5713_dai = { -+ .name = "tas5713-hifi", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ), -+ }, -+ .ops = &tas5713_dai_ops, -+}; -+ -+ -+ -+ -+/* -+ * ___ _ ___ _ -+ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _ -+ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_| -+ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static int tas5713_remove(struct snd_soc_codec *codec) -+{ -+ struct tas5713_priv *tas5713; -+ -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ return 0; -+} -+ -+ -+static int tas5713_probe(struct snd_soc_codec *codec) -+{ -+ struct tas5713_priv *tas5713; -+ int i, ret; -+ -+ i2c = container_of(codec->dev, struct i2c_client, dev); -+ -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ // Reset error -+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -+ if (ret < 0) return ret; -+ -+ // Trim oscillator -+ ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00); -+ if (ret < 0) return ret; -+ msleep(1000); -+ -+ // Reset error -+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -+ if (ret < 0) return ret; -+ -+ // Clock mode: 44/48kHz, MCLK=64xfs -+ ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60); -+ if (ret < 0) return ret; -+ -+ // I2S 24bit -+ ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05); -+ if (ret < 0) return ret; -+ -+ // Unmute -+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -+ if (ret < 0) return ret; -+ ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00); -+ if (ret < 0) return ret; -+ -+ // Set volume to 0db -+ ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00); -+ if (ret < 0) return ret; -+ -+ // Now start programming the default initialization sequence -+ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) { -+ ret = i2c_master_send(i2c, -+ tas5713_init_sequence[i].data, -+ tas5713_init_sequence[i].size); -+ if (ret < 0) { -+ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret); -+ } -+ } -+ -+ // Unmute -+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -+ if (ret < 0) return ret; -+ -+ return 0; -+} -+ -+ -+static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { -+ .probe = tas5713_probe, -+ .remove = tas5713_remove, -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+}; -+ -+ -+ -+ -+/* -+ * ___ ___ ___ ___ _ -+ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _ -+ * | | / / (__ | |) | '_| \ V / -_) '_| -+ * |___/___\___| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static const struct reg_default tas5713_reg_defaults[] = { -+ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB -+ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB -+ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB -+ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB -+}; -+ -+ -+static bool tas5713_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case TAS5713_DEVICE_ID: -+ case TAS5713_ERROR_STATUS: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+ -+static const struct of_device_id tas5713_of_match[] = { -+ { .compatible = "ti,tas5713", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, tas5713_of_match); -+ -+ -+static struct regmap_config tas5713_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ -+ .max_register = TAS5713_MAX_REGISTER, -+ .volatile_reg = tas5713_reg_volatile, -+ -+ .cache_type = REGCACHE_RBTREE, -+ .reg_defaults = tas5713_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults), -+}; -+ -+ -+static int tas5713_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ int ret; -+ -+ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL); -+ if (!priv_data) -+ return -ENOMEM; -+ -+ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config); -+ if (IS_ERR(priv_data->regmap)) { -+ ret = PTR_ERR(priv_data->regmap); -+ return ret; -+ } -+ -+ i2c_set_clientdata(i2c, priv_data); -+ -+ ret = snd_soc_register_codec(&i2c->dev, -+ &soc_codec_dev_tas5713, &tas5713_dai, 1); -+ -+ return ret; -+} -+ -+ -+static int tas5713_i2c_remove(struct i2c_client *i2c) -+{ -+ snd_soc_unregister_codec(&i2c->dev); -+ i2c_set_clientdata(i2c, NULL); -+ -+ kfree(priv_data); -+ -+ return 0; -+} -+ -+ -+static const struct i2c_device_id tas5713_i2c_id[] = { -+ { "tas5713", 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id); -+ -+ -+static struct i2c_driver tas5713_i2c_driver = { -+ .driver = { -+ .name = "tas5713", -+ .owner = THIS_MODULE, -+ .of_match_table = tas5713_of_match, -+ }, -+ .probe = tas5713_i2c_probe, -+ .remove = tas5713_i2c_remove, -+ .id_table = tas5713_i2c_id -+}; -+ -+ -+static int __init tas5713_modinit(void) -+{ -+ int ret = 0; -+ -+ ret = i2c_add_driver(&tas5713_i2c_driver); -+ if (ret) { -+ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n", -+ ret); -+ } -+ -+ return ret; -+} -+module_init(tas5713_modinit); -+ -+ -+static void __exit tas5713_exit(void) -+{ -+ i2c_del_driver(&tas5713_i2c_driver); -+} -+module_exit(tas5713_exit); -+ -+ -+MODULE_AUTHOR("Sebastian Eickhoff "); -+MODULE_DESCRIPTION("ASoC driver for TAS5713"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/tas5713.h b/sound/soc/codecs/tas5713.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8f612a342 ---- /dev/null -+++ b/sound/soc/codecs/tas5713.h -@@ -0,0 +1,210 @@ -+/* -+ * ASoC Driver for TAS5713 -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#ifndef _TAS5713_H -+#define _TAS5713_H -+ -+ -+// TAS5713 I2C-bus register addresses -+ -+#define TAS5713_CLOCK_CTRL 0x00 -+#define TAS5713_DEVICE_ID 0x01 -+#define TAS5713_ERROR_STATUS 0x02 -+#define TAS5713_SYSTEM_CTRL1 0x03 -+#define TAS5713_SERIAL_DATA_INTERFACE 0x04 -+#define TAS5713_SYSTEM_CTRL2 0x05 -+#define TAS5713_SOFT_MUTE 0x06 -+#define TAS5713_VOL_MASTER 0x07 -+#define TAS5713_VOL_CH1 0x08 -+#define TAS5713_VOL_CH2 0x09 -+#define TAS5713_VOL_HEADPHONE 0x0A -+#define TAS5713_VOL_CONFIG 0x0E -+#define TAS5713_MODULATION_LIMIT 0x10 -+#define TAS5713_IC_DLY_CH1 0x11 -+#define TAS5713_IC_DLY_CH2 0x12 -+#define TAS5713_IC_DLY_CH3 0x13 -+#define TAS5713_IC_DLY_CH4 0x14 -+ -+#define TAS5713_START_STOP_PERIOD 0x1A -+#define TAS5713_OSC_TRIM 0x1B -+#define TAS5713_BKND_ERR 0x1C -+ -+#define TAS5713_INPUT_MUX 0x20 -+#define TAS5713_SRC_SELECT_CH4 0x21 -+#define TAS5713_PWM_MUX 0x25 -+ -+#define TAS5713_CH1_BQ0 0x29 -+#define TAS5713_CH1_BQ1 0x2A -+#define TAS5713_CH1_BQ2 0x2B -+#define TAS5713_CH1_BQ3 0x2C -+#define TAS5713_CH1_BQ4 0x2D -+#define TAS5713_CH1_BQ5 0x2E -+#define TAS5713_CH1_BQ6 0x2F -+#define TAS5713_CH1_BQ7 0x58 -+#define TAS5713_CH1_BQ8 0x59 -+ -+#define TAS5713_CH2_BQ0 0x30 -+#define TAS5713_CH2_BQ1 0x31 -+#define TAS5713_CH2_BQ2 0x32 -+#define TAS5713_CH2_BQ3 0x33 -+#define TAS5713_CH2_BQ4 0x34 -+#define TAS5713_CH2_BQ5 0x35 -+#define TAS5713_CH2_BQ6 0x36 -+#define TAS5713_CH2_BQ7 0x5C -+#define TAS5713_CH2_BQ8 0x5D -+ -+#define TAS5713_CH4_BQ0 0x5A -+#define TAS5713_CH4_BQ1 0x5B -+#define TAS5713_CH3_BQ0 0x5E -+#define TAS5713_CH3_BQ1 0x5F -+ -+#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B -+#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C -+#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E -+#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F -+#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40 -+#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43 -+#define TAS5713_DRC_CTRL 0x46 -+ -+#define TAS5713_BANK_SW_CTRL 0x50 -+#define TAS5713_CH1_OUTPUT_MIXER 0x51 -+#define TAS5713_CH2_OUTPUT_MIXER 0x52 -+#define TAS5713_CH1_INPUT_MIXER 0x53 -+#define TAS5713_CH2_INPUT_MIXER 0x54 -+#define TAS5713_OUTPUT_POST_SCALE 0x56 -+#define TAS5713_OUTPUT_PRESCALE 0x57 -+ -+#define TAS5713_IDF_POST_SCALE 0x62 -+ -+#define TAS5713_CH1_INLINE_MIXER 0x70 -+#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71 -+#define TAS5713_CH1_R_CHANNEL_MIXER 0x72 -+#define TAS5713_CH1_L_CHANNEL_MIXER 0x73 -+#define TAS5713_CH2_INLINE_MIXER 0x74 -+#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75 -+#define TAS5713_CH2_L_CHANNEL_MIXER 0x76 -+#define TAS5713_CH2_R_CHANNEL_MIXER 0x77 -+ -+#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8 -+#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9 -+ -+#define TAS5713_REGISTER_COUNT 0x46 -+#define TAS5713_MAX_REGISTER 0xF9 -+ -+ -+// Bitmasks for registers -+#define TAS5713_SOFT_MUTE_ALL 0x07 -+ -+ -+ -+struct tas5713_init_command { -+ const int size; -+ const char *const data; -+}; -+ -+static const struct tas5713_init_command tas5713_init_sequence[] = { -+ -+ // Trim oscillator -+ { .size = 2, .data = "\x1B\x00" }, -+ // System control register 1 (0x03): block DC -+ { .size = 2, .data = "\x03\x80" }, -+ // Mute everything -+ { .size = 2, .data = "\x05\x40" }, -+ // Modulation limit register (0x10): 97.7% -+ { .size = 2, .data = "\x10\x02" }, -+ // Interchannel delay registers -+ // (0x11, 0x12, 0x13, and 0x14): BD mode -+ { .size = 2, .data = "\x11\xB8" }, -+ { .size = 2, .data = "\x12\x60" }, -+ { .size = 2, .data = "\x13\xA0" }, -+ { .size = 2, .data = "\x14\x48" }, -+ // PWM shutdown group register (0x19): no shutdown -+ { .size = 2, .data = "\x19\x00" }, -+ // Input multiplexer register (0x20): BD mode -+ { .size = 2, .data = "\x20\x00\x89\x77\x72" }, -+ // PWM output mux register (0x25) -+ // Channel 1 --> OUTA, channel 1 neg --> OUTB -+ // Channel 2 --> OUTC, channel 2 neg --> OUTD -+ { .size = 5, .data = "\x25\x01\x02\x13\x45" }, -+ // DRC control (0x46): DRC off -+ { .size = 5, .data = "\x46\x00\x00\x00\x00" }, -+ // BKND_ERR register (0x1C): 299ms reset period -+ { .size = 2, .data = "\x1C\x07" }, -+ // Mute channel 3 -+ { .size = 2, .data = "\x0A\xFF" }, -+ // Volume configuration register (0x0E): volume slew 512 steps -+ { .size = 2, .data = "\x0E\x90" }, -+ // Clock control register (0x00): 44/48kHz, MCLK=64xfs -+ { .size = 2, .data = "\x00\x60" }, -+ // Bank switch and eq control (0x50): no bank switching -+ { .size = 5, .data = "\x50\x00\x00\x00\x00" }, -+ // Volume registers (0x07, 0x08, 0x09, 0x0A) -+ { .size = 2, .data = "\x07\x20" }, -+ { .size = 2, .data = "\x08\x30" }, -+ { .size = 2, .data = "\x09\x30" }, -+ { .size = 2, .data = "\x0A\xFF" }, -+ // 0x72, 0x73, 0x76, 0x77 input mixer: -+ // no intermix between channels -+ { .size = 5, .data = "\x72\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x73\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x76\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x77\x00\x80\x00\x00" }, -+ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer: -+ // no inline DRC inmix -+ { .size = 5, .data = "\x70\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x71\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x74\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x75\x00\x00\x00\x00" }, -+ // 0x56, 0x57 Output scale -+ { .size = 5, .data = "\x56\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x57\x00\x02\x00\x00" }, -+ // 0x3B, 0x3c -+ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" }, -+ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" }, -+ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ // 0x51, 0x52: output mixer -+ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" }, -+ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" }, -+ // PEQ defaults -+ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+}; -+ -+ -+#endif /* _TAS5713_H */ - -From 6114307aaa8e31dd0d336fbd67eefd50444a58b3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 9 Jan 2017 09:42:09 +0000 -Subject: [PATCH 117/140] hifiberry-amp: Adjust for ALSA object refactoring - -See: https://github.com/raspberrypi/linux/issues/1775 ---- - sound/soc/codecs/tas5713.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -index 9b2713861dcbed751842ca29c88eb1eae5867411..560234d58a6b0a6e7fd3a63e8de73339ee002b1c 100644 ---- a/sound/soc/codecs/tas5713.c -+++ b/sound/soc/codecs/tas5713.c -@@ -232,8 +232,10 @@ static int tas5713_probe(struct snd_soc_codec *codec) - static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { - .probe = tas5713_probe, - .remove = tas5713_remove, -- .controls = tas5713_snd_controls, -- .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+ .component_driver = { -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+ }, - }; - - - -From 8640eb5ad8ecd1ed2eff1428f4ef19d9a0f5af18 Mon Sep 17 00:00:00 2001 -From: Giedrius Trainavicius -Date: Sun, 8 Jan 2017 15:58:54 +0200 -Subject: [PATCH 118/140] bcm2835-i2s: Changes for allowing asymmetric sample - formats. - -This is achieved by making changes only to the requested -stream direction format, keeping the other stream direction -configuration intact. - -Signed-off-by: Giedrius Trainavicius ---- - sound/soc/bcm/bcm2835-i2s.c | 54 +++++++++++++++++++++++++++++++-------------- - 1 file changed, 38 insertions(+), 16 deletions(-) - -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index 6ba20498202ed36906b52096893a88867a79269f..171c2401dfe192740fca3356268aff6432f284ea 100644 ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -237,7 +237,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - unsigned int sampling_rate = params_rate(params); - unsigned int data_length, data_delay, bclk_ratio; - unsigned int ch1pos, ch2pos, mode, format; -+ unsigned int previous_ftxp, previous_frxp; - uint32_t csreg; -+ bool packed; - - /* - * If a stream is already enabled, -@@ -320,26 +322,46 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- /* -- * Set format for both streams. -- * We cannot set another frame length -- * (and therefore word length) anyway, -- * so the format will be the same. -- */ -- regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -- regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -+ /* Set the format for the matching stream direction. */ -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -+ break; -+ default: -+ return -EINVAL; -+ } - - /* Setup the I2S mode */ -+ /* Keep existing FTXP and FRXP values. */ -+ regmap_read(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, &mode); -+ -+ previous_ftxp = mode & BCM2835_I2S_FTXP; -+ previous_frxp = mode & BCM2835_I2S_FRXP; -+ - mode = 0; - -- if (data_length <= 16) { -- /* -- * Use frame packed mode (2 channels per 32 bit word) -- * We cannot set another frame length in the second stream -- * (and therefore word length) anyway, -- * so the format will be the same. -- */ -- mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; -+ /* -+ * Retain the frame packed mode (2 channels per 32 bit word) -+ * of the other direction stream intact. The formats of each -+ * direction can be different as long as the frame length is -+ * shared for both. -+ */ -+ packed = data_length <= 16; -+ -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ mode |= previous_frxp; -+ mode |= packed ? BCM2835_I2S_FTXP : 0; -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ mode |= previous_ftxp; -+ mode |= packed ? BCM2835_I2S_FRXP : 0; -+ break; -+ default: -+ return -EINVAL; - } - - mode |= BCM2835_I2S_FLEN(bclk_ratio - 1); - -From ecf8e89a531ac228706cc49b6caed1d4dfe4adc7 Mon Sep 17 00:00:00 2001 +From 6d7eabf9e6c2652ed71b4fa01951a7e19f47a985 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:05:41 +0000 -Subject: [PATCH 119/140] Add driver_name property +Subject: [PATCH 115/187] Add driver_name property Add driver name property for use with 5.1 passthrough audio in LibreElec and other Kodi based OSs --- @@ -126520,10 +124755,10 @@ index 8fd50dbe681508a2cfe8fdde1c9fedbe9a507fa7..05a224ec712d06b8b7587ab6b8bb562d .dai_link = snd_rpi_justboom_dac_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai), -From 66434539f08795819e610de5df739cf461205bc1 Mon Sep 17 00:00:00 2001 +From 48c21dc46d473a6362e66bfcae1b7cfe1996a497 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:11:04 +0000 -Subject: [PATCH 120/140] Add driver_name paramater +Subject: [PATCH 116/187] Add driver_name paramater Add driver_name parameter for use with 5.1 passthrough audio in LibreElec and other Kodi OSs --- @@ -126543,10 +124778,10 @@ index 91acb666380faa3c0deb2230f8a0f8bbec59417b..abfdc5c4dd5811e6847bddda4921abe3 .dai_link = snd_rpi_justboom_digi_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_digi_dai), -From 296fcf4cadef94895b86e0d6f1cd5480675cc94b Mon Sep 17 00:00:00 2001 +From ee8c66d4165cfa623d1050d2cf48078bae5769d2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Jan 2017 13:01:21 +0000 -Subject: [PATCH 121/140] BCM270X_DT: Add pi3-disable-wifi overlay +Subject: [PATCH 117/187] BCM270X_DT: Add pi3-disable-wifi overlay pi3-disable-wifi is a minimal overlay to disable the onboard WiFi. @@ -126607,10 +124842,10 @@ index 0000000000000000000000000000000000000000..017199554bf2f4e381efcc7bb71e750c + }; +}; -From 0b46fbc4be5ddfec19dbaf619a9c9ef3d8559df3 Mon Sep 17 00:00:00 2001 +From 6a3c02c8633387502a4d76347a540ba402ee8d09 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Thu, 12 Jan 2017 07:07:08 -0800 -Subject: [PATCH 122/140] ARM64: Make it work again on 4.9 (#1790) +Subject: [PATCH 118/187] ARM64: Make it work again on 4.9 (#1790) * Invoke the dtc compiler with the same options used in arm mode. * ARM64 now uses the bcm2835 platform just like ARM32. @@ -127015,10 +125250,10 @@ index 53da5c7a33e5898a66e549fb0c39fe3da555ca87..c7e891d72969a388d9b135a36dbfc9c9 -CONFIG_BCM2708_VCHIQ=n -CONFIG_ARCH_BCM2835=y -From 070417bfe80223f042349b5322d0694e249c6125 Mon Sep 17 00:00:00 2001 +From 5189f9eb2e9e8f1b4e916f2c37b14c564eae6366 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Sat, 14 Jan 2017 02:54:26 -0800 -Subject: [PATCH 123/140] ARM64: Enable Kernel Address Space Randomization +Subject: [PATCH 119/187] ARM64: Enable Kernel Address Space Randomization (#1792) Randomization allows the mapping between virtual addresses and physical @@ -127050,10 +125285,10 @@ index c7e891d72969a388d9b135a36dbfc9c9cb609bf8..974d8889c0cf695eb88b57bbef11bc5a CONFIG_BINFMT_MISC=y CONFIG_COMPAT=y -From 8b1dcc577913872e592b15aead4e90e1e2e7184c Mon Sep 17 00:00:00 2001 +From e5169833aa70954251b7c3486f5706c4f3dd8ccb Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sun, 15 Jan 2017 07:31:59 -0800 -Subject: [PATCH 124/140] ARM64: Enable RTL8187/RTL8192CU wifi in build config +Subject: [PATCH 120/187] ARM64: Enable RTL8187/RTL8192CU wifi in build config These drivers build now, so they can be enabled back in the build configuration just like they are for @@ -127078,10 +125313,10 @@ index 974d8889c0cf695eb88b57bbef11bc5aa556b635..4670a490dfb1e582ec24a3b39a3cb9b2 CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From e3e2c6018b7d88fc2d66e5646e8f026ebd54c3ef Mon Sep 17 00:00:00 2001 +From a825be7b435a9666323b636455d8547c6a4e3ac0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Jan 2017 14:53:12 +0000 -Subject: [PATCH 125/140] BCM270X_DT: Add spi0-cs overlay +Subject: [PATCH 121/187] BCM270X_DT: Add spi0-cs overlay The spi0-cs overlay allows the software chip selectts to be modified using the cs0_pin and cs1_pin parameters. @@ -127169,10 +125404,10 @@ index 0000000000000000000000000000000000000000..7f79029d043c04d7496c7c3480450c69 + }; +}; -From f59b0251d9406e66fdea34d7bf00b996ed949084 Mon Sep 17 00:00:00 2001 +From ddbcf48e6e8560635ca6c7284b3c04d36b3c86f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 126/140] spi-bcm2835: Disable forced software CS +Subject: [PATCH 122/187] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -127198,10 +125433,10 @@ index 74dd21b7373c7564ede01d84a4f63b93a6d52fa7..51cdefbf5eb265f49bd05e0aa91dfbee i2c0: i2c@7e205000 { -From 96fc8668c38ec7d5d97a85851a8f61c2ad16e619 Mon Sep 17 00:00:00 2001 +From 51b4a593707de53db9daa9b8933a16ff5d383671 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 16 Jan 2017 16:33:54 +0000 -Subject: [PATCH 127/140] config: Add CONFIG_TCP_CONG_BBR See: +Subject: [PATCH 123/187] config: Add CONFIG_TCP_CONG_BBR See: https://github.com/raspberrypi/linux/issues/1784 --- @@ -127236,103 +125471,10 @@ index 8acee9f31202ec14f2933d92dd70831cda8d7b51..219f67051a2542329449b0099165ae28 CONFIG_IPV6_ROUTER_PREF=y CONFIG_INET6_AH=m -From aad9e6a0506b7365903934a6b86d8d960e5274f3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 16 Jan 2017 21:02:26 +0000 -Subject: [PATCH 128/140] Revert "bcm2835-i2s: Changes for allowing asymmetric - sample formats." - -This reverts commit f5a6236a32e82068122301d246a94ca755d61704. - -See: https://github.com/raspberrypi/linux/issues/1799 - -Signed-off-by: Phil Elwell ---- - sound/soc/bcm/bcm2835-i2s.c | 54 ++++++++++++++------------------------------- - 1 file changed, 16 insertions(+), 38 deletions(-) - -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index 171c2401dfe192740fca3356268aff6432f284ea..6ba20498202ed36906b52096893a88867a79269f 100644 ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -237,9 +237,7 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - unsigned int sampling_rate = params_rate(params); - unsigned int data_length, data_delay, bclk_ratio; - unsigned int ch1pos, ch2pos, mode, format; -- unsigned int previous_ftxp, previous_frxp; - uint32_t csreg; -- bool packed; - - /* - * If a stream is already enabled, -@@ -322,46 +320,26 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- /* Set the format for the matching stream direction. */ -- switch (substream->stream) { -- case SNDRV_PCM_STREAM_PLAYBACK: -- regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -- break; -- case SNDRV_PCM_STREAM_CAPTURE: -- regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -- break; -- default: -- return -EINVAL; -- } -+ /* -+ * Set format for both streams. -+ * We cannot set another frame length -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); - - /* Setup the I2S mode */ -- /* Keep existing FTXP and FRXP values. */ -- regmap_read(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, &mode); -- -- previous_ftxp = mode & BCM2835_I2S_FTXP; -- previous_frxp = mode & BCM2835_I2S_FRXP; -- - mode = 0; - -- /* -- * Retain the frame packed mode (2 channels per 32 bit word) -- * of the other direction stream intact. The formats of each -- * direction can be different as long as the frame length is -- * shared for both. -- */ -- packed = data_length <= 16; -- -- switch (substream->stream) { -- case SNDRV_PCM_STREAM_PLAYBACK: -- mode |= previous_frxp; -- mode |= packed ? BCM2835_I2S_FTXP : 0; -- break; -- case SNDRV_PCM_STREAM_CAPTURE: -- mode |= previous_ftxp; -- mode |= packed ? BCM2835_I2S_FRXP : 0; -- break; -- default: -- return -EINVAL; -+ if (data_length <= 16) { -+ /* -+ * Use frame packed mode (2 channels per 32 bit word) -+ * We cannot set another frame length in the second stream -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; - } - - mode |= BCM2835_I2S_FLEN(bclk_ratio - 1); - -From 7ce4883feb777ba20f03f111fe3e6a208a21f2d4 Mon Sep 17 00:00:00 2001 +From 7729ddc311ba53dd238d7271dd2d023d6e02e8e8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 11:34:58 +0000 -Subject: [PATCH 129/140] BCM270X_DT: Enable UART0 on CM3 +Subject: [PATCH 124/187] BCM270X_DT: Enable UART0 on CM3 Signed-off-by: Phil Elwell --- @@ -127355,10 +125497,10 @@ index 41874c25a84226c0e4af92ec4059e0a571fe6123..3ba6e621856c288ae4694f758604619f sdhost_pins: sdhost_pins { brcm,pins = <48 49 50 51 52 53>; -From 1b279d3d8a778bf7c085e15e02351b5fc336a95b Mon Sep 17 00:00:00 2001 +From eb2a61b5b76a74ec88f6806ad3f17e21087f56ce Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 14:39:39 +0000 -Subject: [PATCH 130/140] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR +Subject: [PATCH 125/187] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR See: https://github.com/raspberrypi/linux/issues/1781 @@ -127397,10 +125539,10 @@ index 219f67051a2542329449b0099165ae2885022bec..c4898d63d74718097ec3a1d1fe60b230 CONFIG_OF_CONFIGFS=y CONFIG_ZRAM=m -From 5623259cfc13aef68cff35a43f080fe9d084bfb3 Mon Sep 17 00:00:00 2001 +From c1ec27e76b5fcd2382170a75115de85200d4ab26 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:33:51 -0800 -Subject: [PATCH 131/140] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 +Subject: [PATCH 126/187] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 In ARM64, the FIQ mechanism used by this driver is not current implemented. As a workaround, reqular IRQ is used instead @@ -127743,10 +125885,10 @@ index 6b2c7d0c93f36a63863ff4b0ecc1f3eab77e058b..d7b700ff17821ad1944e36721fe6b2db /** The OS page size */ #define DWC_OS_PAGE_SIZE PAGE_SIZE -From 8573f30283e6c0e99e42ce97ef61203e936daab7 Mon Sep 17 00:00:00 2001 +From aef6479d8851c123def265acb03814ce7e5210b1 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:43:57 -0800 -Subject: [PATCH 132/140] ARM64: Round-Robin dispatch IRQs between CPUs. +Subject: [PATCH 127/187] ARM64: Round-Robin dispatch IRQs between CPUs. IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced @@ -127820,10 +125962,10 @@ index 93e3f7660c4230c9f1dd3b195958cb498949b0ca..486bcbfb32305ee417f6b3be7e91a3ff .name = "bcm2836-gpu", .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, -From c705045a8d00541a9af2d3a1a10369bd50e2709c Mon Sep 17 00:00:00 2001 +From dd7b1d1f7f28f380616a77bff9440adea1c73aa2 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:45:03 -0800 -Subject: [PATCH 133/140] ARM64: Enable DWC_OTG Driver In ARM64 Build +Subject: [PATCH 128/187] ARM64: Enable DWC_OTG Driver In ARM64 Build Config(bcmrpi3_defconfig) Signed-off-by: Michael Zoran @@ -127844,10 +125986,10 @@ index 4670a490dfb1e582ec24a3b39a3cb9b2488b1864..8c4392344eb4495689c220d5d176ee8c CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From d0b7366a47e0582ee9848bda8ffa3d5996e97c1b Mon Sep 17 00:00:00 2001 +From 39d91c3f6eb913b61b5041cd1816770ebac505ed Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:46:04 -0800 -Subject: [PATCH 134/140] ARM64: Use dwc_otg driver by default for USB. +Subject: [PATCH 129/187] ARM64: Use dwc_otg driver by default for USB. If it breaks on anybody, they can use the standard device tree overlays to switch back to the dwc2 driver. @@ -127873,10 +126015,10 @@ index f6def5d7e5d622cf09e8f87332c7374fe28da08b..3e134a1208610b90e2d0fc22f03c6e9f -}; -#endif -From 5723ba9c29dc308ee19f7da6b70a4925ba54ca1c Mon Sep 17 00:00:00 2001 +From 7813c02fe43f9d4455abe5ac1c6b796470eade2d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 23 Jan 2017 17:36:50 +0000 -Subject: [PATCH 135/140] BCM270X_DT: Add reference to audio_pins to CM dtb +Subject: [PATCH 130/187] BCM270X_DT: Add reference to audio_pins to CM dtb The CM1 dtb contains an empty audio_pins node, but no reference to it. Adding the usual pinctrl reference from the audio node enables the @@ -127904,10 +126046,10 @@ index eb8662f0d222b4c0a9a2bcb8bccb13e86a0006b3..10be69972bd1440f574e35d515f3d6a0 hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; }; -From ba726d8da740161357c3b7a9e255625c5a1304bf Mon Sep 17 00:00:00 2001 +From 8410bf895888f1f20bf80d48a36f96383f76de9b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 25 Jan 2017 11:30:38 +0000 -Subject: [PATCH 136/140] config: Add additional network scheduling modules +Subject: [PATCH 131/187] config: Add additional network scheduling modules --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -127959,10 +126101,10 @@ index c4898d63d74718097ec3a1d1fe60b2307a6a3140..b448eaa866c200f48351819072c7fefc CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS_BASIC=m -From 2cd75a8398d19b0323ff47b166fbe612fb7b5c97 Mon Sep 17 00:00:00 2001 +From 1ab4fe548cc9dbe6dedfee18ddca1811c5562ab2 Mon Sep 17 00:00:00 2001 From: chris johnson Date: Sun, 22 Jan 2017 03:27:31 +0000 -Subject: [PATCH 137/140] ASoC: A simple-card overlay for ADAU7002 +Subject: [PATCH 132/187] ASoC: A simple-card overlay for ADAU7002 Usage: `dtoverlay=adau7002-simple` --- @@ -128060,10 +126202,10 @@ index 0000000000000000000000000000000000000000..e67e6625d7967abc92cf00cb604d4c12 + }; +}; -From 0570bcd7820363a26cf7bfbed6665a1d9268c702 Mon Sep 17 00:00:00 2001 +From 1c434c14fb7e622ff23d95f0837b94614127f701 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Jan 2017 21:17:23 +0000 -Subject: [PATCH 138/140] config: Add SND_SOC_ADAU7002 codec module +Subject: [PATCH 133/187] config: Add SND_SOC_ADAU7002 codec module As there is now an overlay requiring it, build the codec module. @@ -128098,10 +126240,10 @@ index b448eaa866c200f48351819072c7fefcd8ad8132..5105a592c9bcfee1cc6a8b50fd1c6c32 CONFIG_SND_SOC_WM8804_I2C=m CONFIG_SND_SIMPLE_CARD=m -From 87966e84bc93b3e7abda4b1d4fef3e2e0f4db1d6 Mon Sep 17 00:00:00 2001 +From f1af816d887be644255e2ece60875757d156a5d8 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Fri, 27 Jan 2017 06:42:42 -0500 -Subject: [PATCH 139/140] Add overlay for mcp3008 adc (#1818) +Subject: [PATCH 134/187] Add overlay for mcp3008 adc (#1818) Some example usage: @@ -128387,10 +126529,10 @@ index 0000000000000000000000000000000000000000..06bf4264959c380d8a9f90f74e780397 + }; +}; -From 2b2775a3943171ed31f958d5ad86ff478b8ce351 Mon Sep 17 00:00:00 2001 +From ec652ea2f70a6db722dbbc2fc2ac274fe6b4f008 Mon Sep 17 00:00:00 2001 From: ED6E0F17 Date: Fri, 3 Feb 2017 14:52:42 +0000 -Subject: [PATCH 140/140] usb: dwc2: Avoid suspending if we're in gadget mode +Subject: [PATCH 135/187] usb: dwc2: Avoid suspending if we're in gadget mode (#1825) I've found when booting HiKey with the usb gadget cable attached @@ -128441,3 +126583,8896 @@ index df5a065780054f21841ca9f08b8ab118922c530b..619ccfe1eafc4643b16970f8a1129ff9 if (!hsotg->core_params->hibernation) goto skip_power_saving; + +From d909483370a6c9793a9d4295933a17c3e04102d0 Mon Sep 17 00:00:00 2001 +From: JamesH65 +Date: Mon, 6 Feb 2017 15:24:47 +0000 +Subject: [PATCH 136/187] gpio_mem: Remove unnecessary dev_info output (#1830) + +The open function was spamming syslog every time +called, so have removed call completely. +--- + drivers/char/broadcom/bcm2835-gpiomem.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +index 911f5b7393ed48ceed8751f06967ae6463453f9c..f5e7f1ba8fb6f18dee77fad06a17480c6603cb4e 100644 +--- a/drivers/char/broadcom/bcm2835-gpiomem.c ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -76,8 +76,6 @@ static int bcm2835_gpiomem_open(struct inode *inode, struct file *file) + int dev = iminor(inode); + int ret = 0; + +- dev_info(inst->dev, "gpiomem device opened."); +- + if (dev != DEVICE_MINOR) { + dev_err(inst->dev, "Unknown minor device: %d", dev); + ret = -ENXIO; + +From 8c9140191f4c6753156aec36e31a253c34b9f54e Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 137/187] config: Enable regulator support + +Signed-off-by: Matthias Reichl +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 31163b59b9c6f2cc4f4f94afe1b10bd1a195470f..611b63c3fdf18f1df6288bb229f827ecd1619958 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -664,6 +664,8 @@ CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 5105a592c9bcfee1cc6a8b50fd1c6c32f1381158..74bc0d81bcb4d7f6676368926cdcc10e581fbcae 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -658,6 +658,8 @@ CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y + +From 1abcd09eb0db59b22c78234508194f6c4e71429f Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 138/187] BCM270x DT: expose 3.3V and 5V system rails + +Signed-off-by: Matthias Reichl +--- + arch/arm/boot/dts/bcm270x.dtsi | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi +index a46cb4a8b1419edd95e0e07c18b0f373222dc2bf..36d853715f2379e1952ce3d3be58dd670e305159 100644 +--- a/arch/arm/boot/dts/bcm270x.dtsi ++++ b/arch/arm/boot/dts/bcm270x.dtsi +@@ -138,4 +138,20 @@ + status = "disabled"; + }; + }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "5v0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; + }; + +From 3b33b3f1a3395b6dbc560073e2374b11e2d89228 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 139/187] BCM270x DT: Consolidate audio card overlays + +Reference 3.3V / 5V system rails instead of instantiating local +regulators. + +Add missing power supply properties for codecs where these are +required according to the DT bindings docs. + +Signed-off-by: Matthias Reichl +--- + .../arm/boot/dts/overlays/adau1977-adc-overlay.dts | 19 ++-------- + .../dts/overlays/akkordion-iqdacplus-overlay.dts | 3 ++ + .../dts/overlays/hifiberry-dacplus-overlay.dts | 3 ++ + .../boot/dts/overlays/hifiberry-digi-overlay.dts | 2 + + .../dts/overlays/hifiberry-digi-pro-overlay.dts | 2 + + arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 3 ++ + .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 3 ++ + .../overlays/iqaudio-digi-wm8804-audio-overlay.dts | 4 +- + .../arm/boot/dts/overlays/justboom-dac-overlay.dts | 3 ++ + .../boot/dts/overlays/justboom-digi-overlay.dts | 2 + + arch/arm/boot/dts/overlays/raspidac3-overlay.dts | 4 ++ + .../overlays/rra-digidac1-wm8741-audio-overlay.dts | 44 +++------------------- + 12 files changed, 36 insertions(+), 56 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts +index 24fcd58fd1dc61d97a77def3d5d1f7c65130dde6..1aaca71c1b677e414ada9a3f94e60e5e2cf30815 100644 +--- a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts +@@ -6,19 +6,6 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; +- +- __overlay__ { +- codec_supply: fixedregulator@0 { +- compatible = "regulator-fixed"; +- regulator-name = "AVDD"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- }; +- }; +- +- fragment@1 { + target = <&i2c>; + + __overlay__ { +@@ -30,19 +17,19 @@ + compatible = "adi,adau1977"; + reg = <0x11>; + reset-gpios = <&gpio 5 0>; +- AVDD-supply = <&codec_supply>; ++ AVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; + +- fragment@2 { ++ fragment@1 { + target = <&i2s>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@3 { ++ fragment@2 { + target = <&sound>; + __overlay__ { + compatible = "adi,adau1977-adc"; +diff --git a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts +index 208849d5c39274ed0aa557f63a19430a451a95f5..241d03b9b79ef5e833cc28819003946a9eb319fd 100644 +--- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +index 2f078d4747ccfdc5172e24b18ce65454f1219b9d..b4dc99633b9d409565c0443de378a4460c7a966a 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -34,6 +34,9 @@ + compatible = "ti,pcm5122"; + reg = <0x4d>; + clocks = <&dacpro_osc>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts +index f5e41f48ba4fed92194ff5a63d13c70bb2d1c091..64cb1e00343b57e3d7dee864416e558dc3163117 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts +index 2a26d9cfffb0f3d7958eb3756ca7c4ba28400e1c..d02479ca4a25c3b2da75fe737fd457b1882c20b1 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts +index 0d35c85382bb5766b3eeb9de1bd4a94621229e4b..f16586f05971f69b928200d212015982e388ce96 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +index d4bad8742a985e2f15eed19ca52ef283a74fefb9..4dcf17515f95589addd5194cf825be813d1e0c98 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts +index da4fbfdfdbbbcf2505b9eb4789ddb779ec72cea8..b86e1e5edc89fb78fd1ab8482bfff6c7ec4ec9f5 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts +@@ -24,8 +24,8 @@ + compatible = "wlf,wm8804"; + reg = <0x3b>; + status = "okay"; +- // DVDD-supply = <®_3v3>; +- // PVDD-supply = <®_3v3>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ PVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts +index 312632ad376d5b8c8ff1dbf31fa03d0d18181d94..2b8dba0c231b20ac7660152356a06abeacc83c2d 100644 +--- a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4d>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts +index cbbede9a541166ba257122918081982016e0b7eb..1212e3ff591b6071604ee4a519c89ec50ac95d00 100644 +--- a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/raspidac3-overlay.dts b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts +index 2fac57ca179fcf114655ea91dbef419c16aceb79..2c3c97813f22c94eff6da2193aff0920ac7c39b1 100644 +--- a/arch/arm/boot/dts/overlays/raspidac3-overlay.dts ++++ b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts +@@ -23,12 +23,16 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + + tpa6130a2: tpa6130a2@60 { + compatible = "ti,tpa6130a2"; + reg = <0x60>; ++ Vdd-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts +index 16b1247bfa618ff85936ddf78c3aea58075eaa67..f8d48233e28c7c18509b4a95692f6aff29ea33fd 100644 +--- a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts +@@ -6,45 +6,13 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target-path = "/"; +- __overlay__ { +- aliases { +- ldo0 = &ldo0; +- ldo1 = &ldo1; +- }; +- }; +- }; +- +- fragment@1 { +- target-path = "/soc"; +- __overlay__ { +- +- ldo1: ldo1 { +- compatible = "regulator-fixed"; +- regulator-name = "DC_5V"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-always-on; +- }; +- +- ldo0: ldo0 { +- compatible = "regulator-fixed"; +- regulator-name = "DC_3V3"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- }; +- }; +- +- fragment@2 { + target = <&i2s>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@3 { ++ fragment@1 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; +@@ -56,21 +24,21 @@ + compatible = "wlf,wm8804"; + reg = <0x3b>; + status = "okay"; +- PVDD-supply = <&ldo0>; +- DVDD-supply = <&ldo0>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + }; + + wm8742: wm8741@1a { + compatible = "wlf,wm8741"; + reg = <0x1a>; + status = "okay"; +- AVDD-supply = <&ldo1>; +- DVDD-supply = <&ldo0>; ++ AVDD-supply = <&vdd_5v0_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; + +- fragment@4 { ++ fragment@2 { + target = <&sound>; + __overlay__ { + compatible = "rra,digidac1-soundcard"; + +From 1cc84b5f80871ee81f439f4e7571edef15242a6f Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:37 +0100 +Subject: [PATCH 140/187] ASoC: Add driver for Cirrus Logic Audio Card + +Note: due to problems with deferred probing of regulators +the following softdep should be added to a modprobe.d file + +softdep arizona-spi pre: arizona-ldo1 + +Signed-off-by: Matthias Reichl +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 + + .../dts/overlays/rpi-cirrus-wm5102-overlay.dts | 146 +++ + sound/soc/bcm/Kconfig | 9 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/rpi-cirrus.c | 1003 ++++++++++++++++++++ + 6 files changed, 1167 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts + create mode 100644 sound/soc/bcm/rpi-cirrus.c + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index e915dff8a4cdf5af3df0aa519b3ee08dd970d831..0a7d30cd573060964bb081ee6617d5b77a17b974 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -68,6 +68,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + qca7000.dtbo \ + raspidac3.dtbo \ + rpi-backlight.dtbo \ ++ rpi-cirrus-wm5102.dtbo \ + rpi-dac.dtbo \ + rpi-display.dtbo \ + rpi-ft5406.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index aa9b6128c397b33e9c40eec29476d8352933c237..46228fd324fc4c52eb0ba50316b4c02f8245bf04 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -995,6 +995,12 @@ Load: dtoverlay=rpi-backlight + Params: + + ++Name: rpi-cirrus-wm5102 ++Info: Configures the Cirrus Logic Audio Card ++Load: dtoverlay=rpi-cirrus-wm5102 ++Params: ++ ++ + Name: rpi-dac + Info: Configures the RPi DAC audio card + Load: dtoverlay=rpi-dac +diff --git a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..cf85f0af224067cf58053a143664f0716d5ce71a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +@@ -0,0 +1,146 @@ ++// Definitions for the Cirrus Logic Audio Card ++/dts-v1/; ++/plugin/; ++#include ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ wlf_pins: wlf_pins { ++ brcm,pins = <17 22 27 8>; ++ brcm,function = < ++ BCM2835_FSEL_GPIO_OUT ++ BCM2835_FSEL_GPIO_OUT ++ BCM2835_FSEL_GPIO_IN ++ BCM2835_FSEL_GPIO_OUT ++ >; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "RPi-Cirrus 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&spi0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ ++ wm5102@1{ ++ compatible = "wlf,wm5102"; ++ reg = <1>; ++ ++ spi-max-frequency = <500000>; ++ ++ interrupt-parent = <&gpio>; ++ interrupts = <27 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ LDOVDD-supply = <&rpi_cirrus_reg_1v8>; ++ AVDD-supply = <&rpi_cirrus_reg_1v8>; ++ DBVDD1-supply = <&rpi_cirrus_reg_1v8>; ++ DBVDD2-supply = <&vdd_3v3_reg>; ++ DBVDD3-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&rpi_cirrus_reg_1v8>; ++ SPKVDDL-supply = <&vdd_5v0_reg>; ++ SPKVDDR-supply = <&vdd_5v0_reg>; ++ DCVDD-supply = <&arizona_ldo1>; ++ ++ wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>; ++ wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>; ++ wlf,gpio-defaults = < ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ >; ++ wlf,micd-configs = <0 1 0>; ++ wlf,dmic-ref = < ++ ARIZONA_DMIC_MICVDD ++ ARIZONA_DMIC_MICBIAS2 ++ ARIZONA_DMIC_MICVDD ++ ARIZONA_DMIC_MICVDD ++ >; ++ wlf,inmode = < ++ ARIZONA_INMODE_DIFF ++ ARIZONA_INMODE_DMIC ++ ARIZONA_INMODE_SE ++ ARIZONA_INMODE_DIFF ++ >; ++ status = "okay"; ++ ++ arizona_ldo1: ldo1 { ++ regulator-name = "LDO1"; ++ // default constraints as in ++ // arizona-ldo1.c ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wm8804@3b { ++ compatible = "wlf,wm8804"; ++ reg = <0x3b>; ++ status = "okay"; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "wlf,rpi-cirrus"; ++ i2s-controller = <&i2s>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig +index d024377e8450fb5402dcb5ea27161f774b04a8ec..10f6b201777946af8e8e78d2ffb0b0cff38093df 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -45,6 +45,15 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP + help + Say Y or M if you want to add support for the HifiBerry Amp amplifier board. + ++config SND_BCM2708_SOC_RPI_CIRRUS ++ tristate "Support for Cirrus Logic Audio Card" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_WM5102 ++ select SND_SOC_WM8804 ++ help ++ Say Y or M if you want to add support for the Wolfson and ++ Cirrus Logic audio cards. ++ + config SND_BCM2708_SOC_RPI_DAC + tristate "Support for RPi-DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index bb1df438540193652ec5464e8bc51f636a1b844e..84c2b20ce2e51b525797ee58de95734ee7847e15 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o + snd-soc-hifiberry-digi-objs := hifiberry_digi.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-justboom-digi-objs := justboom-digi.o ++snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-dac-objs := rpi-dac.o + snd-soc-rpi-proto-objs := rpi-proto.o + snd-soc-iqaudio-dac-objs := iqaudio-dac.o +@@ -34,6 +35,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o ++obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o + obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o +diff --git a/sound/soc/bcm/rpi-cirrus.c b/sound/soc/bcm/rpi-cirrus.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ac8651ddff7bd3701dffe22c7fb88352f912dff3 +--- /dev/null ++++ b/sound/soc/bcm/rpi-cirrus.c +@@ -0,0 +1,1003 @@ ++/* ++ * ASoC machine driver for Cirrus Logic Audio Card ++ * (with WM5102 and WM8804 codecs) ++ * ++ * Copyright 2015-2017 Matthias Reichl ++ * ++ * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "../codecs/wm5102.h" ++#include "../codecs/wm8804.h" ++ ++#define WM8804_CLKOUT_HZ 12000000 ++ ++#define RPI_CIRRUS_DEFAULT_RATE 44100 ++#define WM5102_MAX_SYSCLK_1 49152000 /* max sysclk for 4K family */ ++#define WM5102_MAX_SYSCLK_2 45158400 /* max sysclk for 11.025K family */ ++ ++static inline unsigned int calc_sysclk(unsigned int rate) ++{ ++ return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1; ++} ++ ++enum { ++ DAI_WM5102 = 0, ++ DAI_WM8804, ++}; ++ ++struct rpi_cirrus_priv { ++ /* mutex for synchronzing FLL1 access with DAPM */ ++ struct mutex lock; ++ unsigned int card_rate; ++ int sync_path_enable; ++ int fll1_freq; /* negative means RefClock in spdif rx case */ ++ ++ /* track hw params/free for substreams */ ++ unsigned int params_set; ++ unsigned int min_rate_idx, max_rate_idx; ++ unsigned char iec958_status[4]; ++}; ++ ++/* helper functions */ ++static inline struct snd_soc_pcm_runtime *get_wm5102_runtime( ++ struct snd_soc_card *card) { ++ return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); ++} ++ ++static inline struct snd_soc_pcm_runtime *get_wm8804_runtime( ++ struct snd_soc_card *card) { ++ return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name); ++} ++ ++ ++struct rate_info { ++ unsigned int value; ++ char *text; ++}; ++ ++static struct rate_info min_rates[] = { ++ { 0, "off"}, ++ { 32000, "32kHz"}, ++ { 44100, "44.1kHz"} ++}; ++ ++#define NUM_MIN_RATES ARRAY_SIZE(min_rates) ++ ++static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_MIN_RATES; ++ ++ if (uinfo->value.enumerated.item >= NUM_MIN_RATES) ++ uinfo->value.enumerated.item = NUM_MIN_RATES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ min_rates[uinfo->value.enumerated.item].text); ++ return 0; ++} ++ ++static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ ++ ucontrol->value.enumerated.item[0] = priv->min_rate_idx; ++ return 0; ++} ++ ++static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int changed = 0; ++ ++ if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) { ++ changed = 1; ++ priv->min_rate_idx = ucontrol->value.enumerated.item[0]; ++ } ++ ++ return changed; ++} ++ ++static struct rate_info max_rates[] = { ++ { 0, "off"}, ++ { 48000, "48kHz"}, ++ { 96000, "96kHz"} ++}; ++ ++#define NUM_MAX_RATES ARRAY_SIZE(max_rates) ++ ++static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_MAX_RATES; ++ if (uinfo->value.enumerated.item >= NUM_MAX_RATES) ++ uinfo->value.enumerated.item = NUM_MAX_RATES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ max_rates[uinfo->value.enumerated.item].text); ++ return 0; ++} ++ ++static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ ++ ucontrol->value.enumerated.item[0] = priv->max_rate_idx; ++ return 0; ++} ++ ++static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int changed = 0; ++ ++ if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) { ++ changed = 1; ++ priv->max_rate_idx = ucontrol->value.enumerated.item[0]; ++ } ++ ++ return changed; ++} ++ ++static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ ucontrol->value.iec958.status[i] = priv->iec958_status[i]; ++ ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned char *stat = priv->iec958_status; ++ unsigned char *ctrl_stat = ucontrol->value.iec958.status; ++ unsigned int mask; ++ int i, changed = 0; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ if ((ctrl_stat[i] & mask) != (stat[i] & mask)) { ++ changed = 1; ++ stat[i] = ctrl_stat[i] & mask; ++ snd_soc_update_bits(wm8804_codec, ++ WM8804_SPDTX1 + i, mask, stat[i]); ++ } ++ } ++ ++ return changed; ++} ++ ++static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ ucontrol->value.iec958.status[0] = 0xff; ++ ucontrol->value.iec958.status[1] = 0xff; ++ ucontrol->value.iec958.status[2] = 0xff; ++ ucontrol->value.iec958.status[3] = 0x3f; ++ ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ unsigned int mask; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ ucontrol->value.iec958.status[i] = ++ snd_soc_read(wm8804_codec, WM8804_RXCHAN1 + i) & mask; ++ } ++ ++ return 0; ++} ++ ++#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \ ++{ \ ++ .access = SNDRV_CTL_ELEM_ACCESS_READ \ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) \ ++ desc " Flag", \ ++ .info = snd_ctl_boolean_mono_info, \ ++ .get = rpi_cirrus_spdif_status_flag_get, \ ++ .private_value = \ ++ (bit) | ((reg) << 8) | ((invert) << 16) \ ++} ++ ++static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ ++ unsigned int bit = kcontrol->private_value & 0xff; ++ unsigned int reg = (kcontrol->private_value >> 8) & 0xff; ++ unsigned int invert = (kcontrol->private_value >> 16) & 0xff; ++ ++ bool flag = snd_soc_read(wm8804_codec, reg) & (1 << bit); ++ ++ ucontrol->value.integer.value[0] = invert ? !flag : flag; ++ ++ return 0; ++} ++ ++static const char * const recovered_frequency_texts[] = { ++ "176.4/192 kHz", ++ "88.2/96 kHz", ++ "44.1/48 kHz", ++ "32 kHz" ++}; ++ ++#define NUM_RECOVERED_FREQUENCIES \ ++ ARRAY_SIZE(recovered_frequency_texts) ++ ++static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_RECOVERED_FREQUENCIES; ++ if (uinfo->value.enumerated.item >= NUM_RECOVERED_FREQUENCIES) ++ uinfo->value.enumerated.item = NUM_RECOVERED_FREQUENCIES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ recovered_frequency_texts[uinfo->value.enumerated.item]); ++ return 0; ++} ++ ++static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ ++ ucontrol->value.enumerated.item[0] = ++ (snd_soc_read(wm8804_codec, WM8804_SPDSTAT) >> 4) & 0x03; ++ return 0; ++} ++ ++static const struct snd_kcontrol_new rpi_cirrus_controls[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Min Sample Rate", ++ .info = rpi_cirrus_min_rate_info, ++ .get = rpi_cirrus_min_rate_get, ++ .put = rpi_cirrus_min_rate_put, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Max Sample Rate", ++ .info = rpi_cirrus_max_rate_info, ++ .get = rpi_cirrus_max_rate_get, ++ .put = rpi_cirrus_max_rate_put, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_playback_get, ++ .put = rpi_cirrus_spdif_playback_put, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_capture_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_mask_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) ++ "Recovered Frequency", ++ .info = rpi_cirrus_recovered_frequency_info, ++ .get = rpi_cirrus_recovered_frequency_get, ++ }, ++ SPDIF_FLAG_CTRL("Audio", WM8804_SPDSTAT, 0, 1), ++ SPDIF_FLAG_CTRL("Non-PCM", WM8804_SPDSTAT, 1, 0), ++ SPDIF_FLAG_CTRL("Copyright", WM8804_SPDSTAT, 2, 1), ++ SPDIF_FLAG_CTRL("De-Emphasis", WM8804_SPDSTAT, 3, 0), ++ SPDIF_FLAG_CTRL("Lock", WM8804_SPDSTAT, 6, 1), ++ SPDIF_FLAG_CTRL("Invalid", WM8804_INTSTAT, 1, 0), ++ SPDIF_FLAG_CTRL("TransErr", WM8804_INTSTAT, 3, 0), ++}; ++ ++static const char * const linein_micbias_texts[] = { ++ "off", "on", ++}; ++ ++static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum, ++ linein_micbias_texts); ++ ++static const struct snd_kcontrol_new linein_micbias_mux = ++ SOC_DAPM_ENUM("Route", linein_micbias_enum); ++ ++static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event); ++ ++const struct snd_soc_dapm_widget rpi_cirrus_dapm_widgets[] = { ++ SND_SOC_DAPM_MIC("DMIC", NULL), ++ SND_SOC_DAPM_MIC("Headset Mic", NULL), ++ SND_SOC_DAPM_INPUT("Line Input"), ++ SND_SOC_DAPM_MIC("Line Input with Micbias", NULL), ++ SND_SOC_DAPM_MUX("Line Input Micbias", SND_SOC_NOPM, 0, 0, ++ &linein_micbias_mux), ++ SND_SOC_DAPM_INPUT("dummy SPDIF in"), ++ SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0, NULL, 0, ++ rpi_cirrus_spdif_rx_enable_event, ++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_INPUT("Dummy Input"), ++ SND_SOC_DAPM_OUTPUT("Dummy Output"), ++}; ++ ++const struct snd_soc_dapm_route rpi_cirrus_dapm_routes[] = { ++ { "IN1L", NULL, "Headset Mic" }, ++ { "IN1R", NULL, "Headset Mic" }, ++ { "Headset Mic", NULL, "MICBIAS1" }, ++ ++ { "IN2L", NULL, "DMIC" }, ++ { "IN2R", NULL, "DMIC" }, ++ { "DMIC", NULL, "MICBIAS2" }, ++ ++ { "IN3L", NULL, "Line Input Micbias" }, ++ { "IN3R", NULL, "Line Input Micbias" }, ++ ++ { "Line Input Micbias", "off", "Line Input" }, ++ { "Line Input Micbias", "on", "Line Input with Micbias" }, ++ ++ /* Make sure MICVDD is enabled, otherwise we get noise */ ++ { "Line Input", NULL, "MICVDD" }, ++ { "Line Input with Micbias", NULL, "MICBIAS3" }, ++ ++ /* Dummy routes to check whether SPDIF RX is enabled or not */ ++ {"dummy SPDIFRX", NULL, "dummy SPDIF in"}, ++ {"AIFTX", NULL, "dummy SPDIFRX"}, ++ ++ /* ++ * Dummy routes to keep wm5102 from staying off on ++ * playback/capture if all mixers are off. ++ */ ++ { "Dummy Output", NULL, "AIF1RX1" }, ++ { "Dummy Output", NULL, "AIF1RX2" }, ++ { "AIF1TX1", NULL, "Dummy Input" }, ++ { "AIF1TX2", NULL, "Dummy Input" }, ++}; ++ ++static int rpi_cirrus_clear_flls(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec) { ++ ++ int ret1, ret2; ++ ++ ret1 = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); ++ ret2 = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0); ++ ++ if (ret1) { ++ dev_warn(card->dev, ++ "setting FLL1 to zero failed: %d\n", ret1); ++ return ret1; ++ } ++ if (ret2) { ++ dev_warn(card->dev, ++ "setting FLL1_REFCLK to zero failed: %d\n", ret2); ++ return ret2; ++ } ++ return 0; ++} ++ ++static int rpi_cirrus_set_fll(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec, unsigned int clk_freq) ++{ ++ int ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ++ ARIZONA_CLK_SRC_MCLK1, ++ WM8804_CLKOUT_HZ, ++ clk_freq); ++ if (ret) ++ dev_err(card->dev, "Failed to set FLL1 to %d: %d\n", ++ clk_freq, ret); ++ ++ usleep_range(1000, 2000); ++ return ret; ++} ++ ++static int rpi_cirrus_set_fll_refclk(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec, ++ unsigned int clk_freq, unsigned int aif2_freq) ++{ ++ int ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1_REFCLK, ++ ARIZONA_CLK_SRC_MCLK1, ++ WM8804_CLKOUT_HZ, ++ clk_freq); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set FLL1_REFCLK to %d: %d\n", ++ clk_freq, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ++ ARIZONA_CLK_SRC_AIF2BCLK, ++ aif2_freq, clk_freq); ++ if (ret) ++ dev_err(card->dev, ++ "Failed to set FLL1 with Sync Clock %d to %d: %d\n", ++ aif2_freq, clk_freq, ret); ++ ++ usleep_range(1000, 2000); ++ return ret; ++} ++ ++static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_card *card = w->dapm->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_codec *wm5102_codec = get_wm5102_runtime(card)->codec; ++ ++ unsigned int clk_freq, aif2_freq; ++ int ret = 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ mutex_lock(&priv->lock); ++ ++ /* Enable sync path in case of SPDIF capture use case */ ++ ++ clk_freq = calc_sysclk(priv->card_rate); ++ aif2_freq = 64 * priv->card_rate; ++ ++ dev_dbg(card->dev, ++ "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n", ++ clk_freq, aif2_freq); ++ ++ ret = rpi_cirrus_clear_flls(card, wm5102_codec); ++ if (ret) { ++ dev_err(card->dev, "spdif_rx: failed to clear FLLs\n"); ++ goto out; ++ } ++ ++ ret = rpi_cirrus_set_fll_refclk(card, wm5102_codec, ++ clk_freq, aif2_freq); ++ ++ if (ret) { ++ dev_err(card->dev, "spdif_rx: failed to set FLLs\n"); ++ goto out; ++ } ++ ++ /* set to negative to indicate we're doing spdif rx */ ++ priv->fll1_freq = -clk_freq; ++ priv->sync_path_enable = 1; ++ break; ++ ++ case SND_SOC_DAPM_POST_PMD: ++ mutex_lock(&priv->lock); ++ priv->sync_path_enable = 0; ++ break; ++ ++ default: ++ return 0; ++ } ++ ++out: ++ mutex_unlock(&priv->lock); ++ return ret; ++} ++ ++static int rpi_cirrus_set_bias_level(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, ++ enum snd_soc_bias_level level) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec; ++ ++ int ret = 0; ++ unsigned int clk_freq; ++ ++ if (dapm->dev != wm5102_runtime->codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_PREPARE: ++ if (dapm->bias_level == SND_SOC_BIAS_ON) ++ break; ++ ++ mutex_lock(&priv->lock); ++ ++ if (!priv->sync_path_enable) { ++ clk_freq = calc_sysclk(priv->card_rate); ++ ++ dev_dbg(card->dev, ++ "set_bias: changing FLL1 from %d to %d\n", ++ priv->fll1_freq, clk_freq); ++ ++ ret = rpi_cirrus_set_fll(card, wm5102_codec, clk_freq); ++ if (ret) ++ dev_err(card->dev, ++ "set_bias: Failed to set FLL1\n"); ++ else ++ priv->fll1_freq = clk_freq; ++ } ++ mutex_unlock(&priv->lock); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static int rpi_cirrus_set_bias_level_post(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, ++ enum snd_soc_bias_level level) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec; ++ ++ if (dapm->dev != wm5102_runtime->codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_STANDBY: ++ mutex_lock(&priv->lock); ++ ++ dev_dbg(card->dev, ++ "set_bias_post: changing FLL1 from %d to off\n", ++ priv->fll1_freq); ++ ++ if (rpi_cirrus_clear_flls(card, wm5102_codec)) ++ dev_err(card->dev, ++ "set_bias_post: failed to clear FLLs\n"); ++ else ++ priv->fll1_freq = 0; ++ ++ mutex_unlock(&priv->lock); ++ ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card, ++ struct snd_soc_dai *wm8804_dai, unsigned int rate) ++{ ++ int ret; ++ ++ /* use 256fs */ ++ unsigned int clk_freq = rate * 256; ++ ++ ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0, ++ WM8804_CLKOUT_HZ, clk_freq); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret); ++ return ret; ++ } ++ ++ /* Set MCLK as PLL Output */ ++ ret = snd_soc_dai_set_sysclk(wm8804_dai, ++ WM8804_TX_CLKSRC_PLL, clk_freq, 0); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set MCLK as PLL Output: %d\n", ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int rpi_cirrus_startup(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned int min_rate = min_rates[priv->min_rate_idx].value; ++ unsigned int max_rate = max_rates[priv->max_rate_idx].value; ++ ++ if (min_rate || max_rate) { ++ if (max_rate == 0) ++ max_rate = UINT_MAX; ++ ++ dev_dbg(card->dev, ++ "startup: limiting rate to %u-%u\n", ++ min_rate, max_rate); ++ ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate); ++ } ++ ++ return 0; ++} ++ ++static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = { ++ .formats = SNDRV_PCM_FMTBIT_S24_LE, ++ .channels_min = 2, ++ .channels_max = 2, ++ .rate_min = RPI_CIRRUS_DEFAULT_RATE, ++ .rate_max = RPI_CIRRUS_DEFAULT_RATE, ++}; ++ ++static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_dai *bcm_i2s_dai = rtd->cpu_dai; ++ struct snd_soc_codec *wm5102_codec = rtd->codec; ++ struct snd_soc_dai *wm8804_dai = get_wm8804_runtime(card)->codec_dai; ++ ++ int ret; ++ ++ unsigned int width = snd_pcm_format_physical_width( ++ params_format(params)); ++ unsigned int rate = params_rate(params); ++ unsigned int clk_freq = calc_sysclk(rate); ++ ++ mutex_lock(&priv->lock); ++ ++ dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate); ++ ++ ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width); ++ if (ret) { ++ dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret); ++ goto out; ++ } ++ ++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03, 2, width); ++ if (ret) { ++ dev_err(card->dev, "set_tdm_slot failed: %d\n", ret); ++ goto out; ++ } ++ ++ /* WM8804 supports sample rates from 32k only */ ++ if (rate >= 32000) { ++ ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate); ++ if (ret) ++ goto out; ++ } ++ ++ ret = snd_soc_codec_set_sysclk(wm5102_codec, ++ ARIZONA_CLK_SYSCLK, ++ ARIZONA_CLK_SRC_FLL1, ++ clk_freq, ++ SND_SOC_CLOCK_IN); ++ if (ret) { ++ dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret); ++ goto out; ++ } ++ ++ if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) { ++ dev_dbg(card->dev, ++ "hw_params: changing FLL1 from %d to %d\n", ++ priv->fll1_freq, clk_freq); ++ ++ if (rpi_cirrus_clear_flls(card, wm5102_codec)) { ++ dev_err(card->dev, "hw_params: failed to clear FLLs\n"); ++ goto out; ++ } ++ ++ if (rpi_cirrus_set_fll(card, wm5102_codec, clk_freq)) { ++ dev_err(card->dev, "hw_params: failed to set FLL\n"); ++ goto out; ++ } ++ ++ priv->fll1_freq = clk_freq; ++ } ++ ++ priv->card_rate = rate; ++ rpi_cirrus_dai_link2_params.rate_min = rate; ++ rpi_cirrus_dai_link2_params.rate_max = rate; ++ ++ priv->params_set |= 1 << substream->stream; ++ ++out: ++ mutex_unlock(&priv->lock); ++ ++ return ret; ++} ++ ++static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_codec *wm5102_codec = rtd->codec; ++ int ret; ++ unsigned int old_params_set = priv->params_set; ++ ++ priv->params_set &= ~(1 << substream->stream); ++ ++ /* disable sysclk if this was the last open stream */ ++ if (priv->params_set == 0 && old_params_set) { ++ dev_dbg(card->dev, ++ "hw_free: Setting SYSCLK to Zero\n"); ++ ++ ret = snd_soc_codec_set_sysclk(wm5102_codec, ++ ARIZONA_CLK_SYSCLK, ++ ARIZONA_CLK_SRC_FLL1, ++ 0, ++ SND_SOC_CLOCK_IN); ++ if (ret) ++ dev_err(card->dev, ++ "hw_free: Failed to set SYSCLK to Zero: %d\n", ++ ret); ++ } ++ return 0; ++} ++ ++static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ int ret; ++ ++ /* no 32kHz input, derive it from sysclk if needed */ ++ snd_soc_update_bits(codec, ++ ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, 2); ++ ++ if (rpi_cirrus_clear_flls(rtd->card, codec)) ++ dev_warn(rtd->card->dev, ++ "init_wm5102: failed to clear FLLs\n"); ++ ++ ret = snd_soc_codec_set_sysclk(codec, ++ ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, ++ 0, SND_SOC_CLOCK_IN); ++ if (ret) { ++ dev_err(rtd->card->dev, ++ "Failed to set SYSCLK to Zero: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned int mask; ++ int i, ret; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ priv->iec958_status[i] = ++ snd_soc_read(codec, WM8804_SPDTX1 + i) & mask; ++ } ++ ++ /* Setup for 256fs */ ++ ret = snd_soc_dai_set_clkdiv(codec_dai, ++ WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS); ++ if (ret) { ++ dev_err(card->dev, ++ "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Output OSC on CLKOUT */ ++ ret = snd_soc_dai_set_sysclk(codec_dai, ++ WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0); ++ if (ret) ++ dev_err(card->dev, ++ "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n", ++ ret); ++ ++ /* Init PLL with default samplerate */ ++ ret = rpi_cirrus_set_wm8804_pll(card, codec_dai, ++ RPI_CIRRUS_DEFAULT_RATE); ++ if (ret) ++ dev_err(card->dev, ++ "init_wm8804: Failed to setup PLL for %dHz: %d\n", ++ RPI_CIRRUS_DEFAULT_RATE, ret); ++ ++ return ret; ++} ++ ++static struct snd_soc_ops rpi_cirrus_ops = { ++ .startup = rpi_cirrus_startup, ++ .hw_params = rpi_cirrus_hw_params, ++ .hw_free = rpi_cirrus_hw_free, ++}; ++ ++static struct snd_soc_dai_link rpi_cirrus_dai[] = { ++ [DAI_WM5102] = { ++ .name = "WM5102", ++ .stream_name = "WM5102 AiFi", ++ .codec_dai_name = "wm5102-aif1", ++ .codec_name = "wm5102-codec", ++ .dai_fmt = SND_SOC_DAIFMT_I2S ++ | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM, ++ .ops = &rpi_cirrus_ops, ++ .init = rpi_cirrus_init_wm5102, ++ }, ++ [DAI_WM8804] = { ++ .name = "WM5102 SPDIF", ++ .stream_name = "SPDIF Tx/Rx", ++ .cpu_dai_name = "wm5102-aif2", ++ .codec_dai_name = "wm8804-spdif", ++ .codec_name = "wm8804.1-003b", ++ .dai_fmt = SND_SOC_DAIFMT_I2S ++ | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM, ++ .ignore_suspend = 1, ++ .params = &rpi_cirrus_dai_link2_params, ++ .init = rpi_cirrus_init_wm8804, ++ }, ++}; ++ ++ ++static int rpi_cirrus_late_probe(struct snd_soc_card *card) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_pcm_runtime *wm8804_runtime = get_wm8804_runtime(card); ++ int ret; ++ ++ dev_dbg(card->dev, "iec958_bits: %02x %02x %02x %02x\n", ++ priv->iec958_status[0], ++ priv->iec958_status[1], ++ priv->iec958_status[2], ++ priv->iec958_status[3]); ++ ++ ret = snd_soc_dai_set_sysclk( ++ wm5102_runtime->codec_dai, ARIZONA_CLK_SYSCLK, 0, 0); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set WM5102 codec dai clk domain: %d\n", ret); ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_sysclk( ++ wm8804_runtime->cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0); ++ if (ret) ++ dev_err(card->dev, ++ "Failed to set WM8804 codec dai clk domain: %d\n", ret); ++ ++ return ret; ++} ++ ++/* audio machine driver */ ++static struct snd_soc_card rpi_cirrus_card = { ++ .name = "RPi-Cirrus", ++ .driver_name = "RPiCirrus", ++ .owner = THIS_MODULE, ++ .dai_link = rpi_cirrus_dai, ++ .num_links = ARRAY_SIZE(rpi_cirrus_dai), ++ .late_probe = rpi_cirrus_late_probe, ++ .controls = rpi_cirrus_controls, ++ .num_controls = ARRAY_SIZE(rpi_cirrus_controls), ++ .dapm_widgets = rpi_cirrus_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(rpi_cirrus_dapm_widgets), ++ .dapm_routes = rpi_cirrus_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(rpi_cirrus_dapm_routes), ++ .set_bias_level = rpi_cirrus_set_bias_level, ++ .set_bias_level_post = rpi_cirrus_set_bias_level_post, ++}; ++ ++static int rpi_cirrus_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct rpi_cirrus_priv *priv; ++ struct device_node *i2s_node; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->min_rate_idx = 1; /* min samplerate 32kHz */ ++ priv->card_rate = RPI_CIRRUS_DEFAULT_RATE; ++ ++ mutex_init(&priv->lock); ++ ++ snd_soc_card_set_drvdata(&rpi_cirrus_card, priv); ++ ++ if (!pdev->dev.of_node) ++ return -ENODEV; ++ ++ i2s_node = of_parse_phandle( ++ pdev->dev.of_node, "i2s-controller", 0); ++ if (!i2s_node) { ++ dev_err(&pdev->dev, "i2s-controller missing in DT\n"); ++ return -ENODEV; ++ } ++ ++ rpi_cirrus_dai[DAI_WM5102].cpu_of_node = i2s_node; ++ rpi_cirrus_dai[DAI_WM5102].platform_of_node = i2s_node; ++ ++ rpi_cirrus_card.dev = &pdev->dev; ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card); ++ if (ret) { ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(&pdev->dev, ++ "register card requested probe deferral\n"); ++ else ++ dev_err(&pdev->dev, ++ "Failed to register card: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static const struct of_device_id rpi_cirrus_of_match[] = { ++ { .compatible = "wlf,rpi-cirrus", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match); ++ ++static struct platform_driver rpi_cirrus_driver = { ++ .driver = { ++ .name = "snd-rpi-cirrus", ++ .of_match_table = of_match_ptr(rpi_cirrus_of_match), ++ }, ++ .probe = rpi_cirrus_probe, ++}; ++ ++module_platform_driver(rpi_cirrus_driver); ++ ++MODULE_AUTHOR("Matthias Reichl "); ++MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card"); ++MODULE_LICENSE("GPL"); + +From a7a1497e08e063e172d327ae2cdaaf4aa77bd505 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:37 +0100 +Subject: [PATCH 141/187] config: enable Cirrus Logic Audio Card + +Signed-off-by: Matthias Reichl +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 611b63c3fdf18f1df6288bb229f827ecd1619958..858143b9b68a9cf29714452394cb800e4f41198d 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -666,6 +666,7 @@ CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y + CONFIG_REGULATOR=y + CONFIG_REGULATOR_FIXED_VOLTAGE=m ++CONFIG_REGULATOR_ARIZONA=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +@@ -872,6 +873,7 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m ++CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m + CONFIG_SND_BCM2708_SOC_RPI_DAC=m + CONFIG_SND_BCM2708_SOC_RPI_PROTO=m + CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 74bc0d81bcb4d7f6676368926cdcc10e581fbcae..f0b87d15e959d88eb26e5a11244365dadb57a298 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -660,6 +660,7 @@ CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y + CONFIG_REGULATOR=y + CONFIG_REGULATOR_FIXED_VOLTAGE=m ++CONFIG_REGULATOR_ARIZONA=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +@@ -866,6 +867,7 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m ++CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m + CONFIG_SND_BCM2708_SOC_RPI_DAC=m + CONFIG_SND_BCM2708_SOC_RPI_PROTO=m + CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m + +From 1f1ed77cc7e1090e1eaef2efe32d9f197cb46c01 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:33:30 +0000 +Subject: [PATCH 142/187] irq-bcm2836: Avoid "Invalid trigger warning" + +Initialise the level for each IRQ to avoid a warning from the +arm arch timer code. + +Signed-off-by: Phil Elwell +--- + drivers/irqchip/irq-bcm2836.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c +index 486bcbfb32305ee417f6b3be7e91a3ff069a586c..e10597c1a1e51e5e27aa574b6a26d87181f26221 100644 +--- a/drivers/irqchip/irq-bcm2836.c ++++ b/drivers/irqchip/irq-bcm2836.c +@@ -178,7 +178,7 @@ static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) + + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); +- irq_set_status_flags(irq, IRQ_NOAUTOEN); ++ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW); + } + + static void + +From 2c4ff814c0a6b93a698bc30960651c90975afd25 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:36:44 +0000 +Subject: [PATCH 143/187] sound: Demote deferral errors to INFO level + +At present there is no mechanism to specify driver load order, +which can lead to deferrals and repeated retries until successful. +Since this situation is expected, reduce the dmesg level to +INFO and mention that the operation will be retried. + +Signed-off-by: Phil Elwell +--- + sound/soc/soc-core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index c0bbcd9032613a78aef551ce697cabc792880bad..a2504d8c83d74d7227e65be142a26cc9d0a88158 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1013,7 +1013,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); + if (!rtd->cpu_dai) { +- dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", ++ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n", + dai_link->cpu_dai_name); + goto _err_defer; + } +@@ -1025,7 +1025,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, + for (i = 0; i < rtd->num_codecs; i++) { + codec_dais[i] = snd_soc_find_dai(&codecs[i]); + if (!codec_dais[i]) { +- dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", ++ dev_info(card->dev, "ASoC: CODEC DAI %s not registered - will retry\n", + codecs[i].dai_name); + goto _err_defer; + } + +From 4570c9447e94aae1b7fe93d534d46625089935fa Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:40:33 +0000 +Subject: [PATCH 144/187] sound: Suppress error message about deferrals + +Since driver load deferrals are expected and will already +have resulted in a kernel message, suppress an essentially +duplicate error message from the RPi audio board drivers. + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/adau1977-adc.c | 2 +- + sound/soc/bcm/allo-piano-dac.c | 2 +- + sound/soc/bcm/digidac1-soundcard.c | 4 ++-- + sound/soc/bcm/dionaudio_loco.c | 2 +- + sound/soc/bcm/hifiberry_amp.c | 3 +-- + sound/soc/bcm/hifiberry_dac.c | 2 +- + sound/soc/bcm/hifiberry_dacplus.c | 2 +- + sound/soc/bcm/hifiberry_digi.c | 2 +- + sound/soc/bcm/iqaudio-dac.c | 5 +++-- + sound/soc/bcm/iqaudio_digi.c | 2 +- + sound/soc/bcm/justboom-dac.c | 2 +- + sound/soc/bcm/justboom-digi.c | 2 +- + sound/soc/bcm/pisound.c | 3 ++- + sound/soc/bcm/raspidac3.c | 2 +- + sound/soc/bcm/rpi-dac.c | 2 +- + sound/soc/bcm/rpi-proto.c | 3 +-- + 16 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/sound/soc/bcm/adau1977-adc.c b/sound/soc/bcm/adau1977-adc.c +index 6e2ee027926ee63c89222f75ceb89e3d2434b0e1..f3d7e5db7bb912e1d7ca6f8e8d42df5f59c9edb8 100644 +--- a/sound/soc/bcm/adau1977-adc.c ++++ b/sound/soc/bcm/adau1977-adc.c +@@ -90,7 +90,7 @@ static int snd_adau1977_adc_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_adau1977_adc); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/allo-piano-dac.c b/sound/soc/bcm/allo-piano-dac.c +index 8e8e62e5a36a279b425ed4655cfbac99ecd7e4cf..eaf50fb6dbca1970ae1c6f8662088b0f1573fecb 100644 +--- a/sound/soc/bcm/allo-piano-dac.c ++++ b/sound/soc/bcm/allo-piano-dac.c +@@ -109,7 +109,7 @@ static int snd_allo_piano_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_allo_piano_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/digidac1-soundcard.c b/sound/soc/bcm/digidac1-soundcard.c +index 446796e7e4c14a7d95b2f2a01211d9a0b151f1f3..f200688bb4ae32b90a0ced555aed94b0add0ac8a 100644 +--- a/sound/soc/bcm/digidac1-soundcard.c ++++ b/sound/soc/bcm/digidac1-soundcard.c +@@ -387,9 +387,9 @@ static int digidac1_soundcard_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&digidac1_soundcard); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", +- ret); ++ ret); + + return ret; + } +diff --git a/sound/soc/bcm/dionaudio_loco.c b/sound/soc/bcm/dionaudio_loco.c +index 89e65317512bc774453ac8d0d5b0ff98aacb740a..65e03741d349a2dc5bd91f69855ea952d9cf87a2 100644 +--- a/sound/soc/bcm/dionaudio_loco.c ++++ b/sound/soc/bcm/dionaudio_loco.c +@@ -86,7 +86,7 @@ static int snd_rpi_dionaudio_loco_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_dionaudio_loco); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + +diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c +index d17c29780507dc31c50f1d567ff5cea7c8241ff5..221c6c38e6465ffe5d5ad77fa80a0b146d0b6841 100644 +--- a/sound/soc/bcm/hifiberry_amp.c ++++ b/sound/soc/bcm/hifiberry_amp.c +@@ -96,9 +96,8 @@ static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) + + ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); + +- if (ret != 0) { ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); +- } + + return ret; + } +diff --git a/sound/soc/bcm/hifiberry_dac.c b/sound/soc/bcm/hifiberry_dac.c +index 45f2b770ad9e67728ca599a7445d6ae9a01c0c29..ee9f133953544629282631e5ef3f73fec857a7c5 100644 +--- a/sound/soc/bcm/hifiberry_dac.c ++++ b/sound/soc/bcm/hifiberry_dac.c +@@ -90,7 +90,7 @@ static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index bdc35e7e6bc12dc1cf04f5ffad8f9ab49a0b0266..b7b401cbe2b0d510d8b12d2dda6d5ff1fff42eb0 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -324,7 +324,7 @@ static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index 19dc953b7227ba86123fc7a2ba654499e0c581c5..7620dd02de40b6d644ff038b445d375d8f632def 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -242,7 +242,7 @@ static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_digi); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index aa15bc4b49ca95edec905fddd8fd0a6d839ca627..1ee4097c846376666775272ed692ca330881b0cb 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -197,8 +197,9 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) + + ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); + if (ret) { +- dev_err(&pdev->dev, +- "snd_soc_register_card() failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); + return ret; + } + +diff --git a/sound/soc/bcm/iqaudio_digi.c b/sound/soc/bcm/iqaudio_digi.c +index 9b6e829bcb5b1762a853775e7816319639e39d65..33aa2be8a43a12a12cfb5d844dd9732c2393d510 100644 +--- a/sound/soc/bcm/iqaudio_digi.c ++++ b/sound/soc/bcm/iqaudio_digi.c +@@ -204,7 +204,7 @@ static int snd_rpi_iqaudio_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(card); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + +diff --git a/sound/soc/bcm/justboom-dac.c b/sound/soc/bcm/justboom-dac.c +index 05a224ec712d06b8b7587ab6b8bb562d19956d47..9bab6cf063d3d450d96b4ee2196a7384e071cbdb 100644 +--- a/sound/soc/bcm/justboom-dac.c ++++ b/sound/soc/bcm/justboom-dac.c +@@ -128,7 +128,7 @@ static int snd_rpi_justboom_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_justboom_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/justboom-digi.c b/sound/soc/bcm/justboom-digi.c +index abfdc5c4dd5811e6847bddda4921abe33fa02812..909cf8928f2f4313982316f9c5b8a709c1d47ab8 100644 +--- a/sound/soc/bcm/justboom-digi.c ++++ b/sound/soc/bcm/justboom-digi.c +@@ -181,7 +181,7 @@ static int snd_rpi_justboom_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_justboom_digi); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/pisound.c b/sound/soc/bcm/pisound.c +index ba70734b89e61a11201657406223f0b37d54f74a..06ff1e53dc9d860946965b6303577762f958fae2 100644 +--- a/sound/soc/bcm/pisound.c ++++ b/sound/soc/bcm/pisound.c +@@ -1076,7 +1076,8 @@ static int pisnd_probe(struct platform_device *pdev) + ret = snd_soc_register_card(&pisnd_card); + + if (ret < 0) { +- printe("snd_soc_register_card() failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ printe("snd_soc_register_card() failed: %d\n", ret); + pisnd_uninit_gpio(); + kobject_put(pisnd_kobj); + pisnd_spi_uninit(); +diff --git a/sound/soc/bcm/raspidac3.c b/sound/soc/bcm/raspidac3.c +index dd9eeea2af0382307f437e6db09d15468c1a470a..ad2b5b89bc8213dc2e277306ef50d6e32448759c 100644 +--- a/sound/soc/bcm/raspidac3.c ++++ b/sound/soc/bcm/raspidac3.c +@@ -149,7 +149,7 @@ static int snd_rpi_raspidac3_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_raspidac3); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/rpi-dac.c b/sound/soc/bcm/rpi-dac.c +index 59dc89ecabc082c0a1ed8adacdc4f0f1337a1c73..38224467cbab7d5be3be731e73e2cf787cd9908a 100644 +--- a/sound/soc/bcm/rpi-dac.c ++++ b/sound/soc/bcm/rpi-dac.c +@@ -85,7 +85,7 @@ static int snd_rpi_rpi_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_rpi_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c +index 9db678e885efd63d84d60a098a84ed6772b19a2d..fadbfade100228aaafabb0d3bdf35c01f8d10485 100644 +--- a/sound/soc/bcm/rpi-proto.c ++++ b/sound/soc/bcm/rpi-proto.c +@@ -117,10 +117,9 @@ static int snd_rpi_proto_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_proto); +- if (ret) { ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); +- } + + return ret; + } + +From 1cf189752ecea25d1f57940051cb81477110cb7a Mon Sep 17 00:00:00 2001 +From: Claggy3 +Date: Sat, 11 Feb 2017 14:00:30 +0000 +Subject: [PATCH 145/187] Update vfpmodule.c + +Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. +This patch fixes a problem with VFP state save and restore related +to exception handling (panic with message "BUG: unsupported FP +instruction in kernel mode") present on VFP11 floating point units +(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry +Pi boards). This patch was developed and discussed on + + https://github.com/raspberrypi/linux/issues/859 + +A precondition to see the crashes is that floating point exception +traps are enabled. In this case, the VFP11 might determine that a FPU +operation needs to trap at a point in time when it is not possible to +signal this to the ARM11 core any more. The VFP11 will then set the +FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases, +a second opcode might have been accepted by the VFP11 before the +exception was detected and could be reported to the ARM11 - in this +case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in +FPINST2.) + +If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued +by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode +trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits +to decide what actions to take, i.e., whether to emulate the opcodes +found in FPINST and FPINST2, and whether to retry the bounced instruction. + +If a user space application has left the VFP11 in this "pending trap" +state, the next FPU opcode issued to the VFP11 might actually be the +VSTMIA operation vfp_save_state() uses to store the FPU registers +to memory (in our test cases, when building the signal stack frame). +In this case, the kernel crashes as described above. + +This patch fixes the problem by making sure that vfp_save_state() is +always entered with FPEXC.EX cleared. (The current value of FPEXC has +already been saved, so this does not corrupt the context. Clearing +FPEXC.EX has no effects on FPINST or FPINST2. Also note that many +callers already modify FPEXC by setting FPEXC.EN before invoking +vfp_save_state().) + +This patch also addresses a second problem related to FPEXC.EX: After +returning from signal handling, the kernel reloads the VFP context +from the user mode stack. However, the current code explicitly clears +both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these +bits to be preserved, this patch disables clearing them for VFP +implementations belonging to architecture 1. There should be no +negative side effects: the user can set both bits by executing FPU +opcodes anyway, and while user code may now place arbitrary values +into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support +code knows which instructions can be emulated, and rejects other +opcodes with "unhandled bounce" messages, so there should be no +security impact from allowing reloading FPEXC.EX and FPEXC.FP2V. + +Signed-off-by: Christopher Alexander Tobias Schulze +--- + arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index da0b33deba6d3c2906eef271f253ab7a30a92680..c6f1d6da808cda78a58f184e19e83522bc738815 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) + * case the thread migrates to a different CPU. The + * restoring is done lazily. + */ +- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) ++ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + vfp_save_state(vfp_current_hw_state[cpu], fpexc); ++ } + #endif + + /* +@@ -463,13 +466,16 @@ static int vfp_pm_suspend(void) + /* if vfp is on, then save state for resumption */ + if (fpexc & FPEXC_EN) { + pr_debug("%s: saving vfp state\n", __func__); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + vfp_save_state(&ti->vfpstate, fpexc); + + /* disable, just in case */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + } else if (vfp_current_hw_state[ti->cpu]) { + #ifndef CONFIG_SMP +- fmxr(FPEXC, fpexc | FPEXC_EN); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); + vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); + fmxr(FPEXC, fpexc); + #endif +@@ -532,7 +538,8 @@ void vfp_sync_hwstate(struct thread_info *thread) + /* + * Save the last VFP state on this CPU. + */ +- fmxr(FPEXC, fpexc | FPEXC_EN); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); + vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); + fmxr(FPEXC, fpexc); + } +@@ -604,6 +611,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, + struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; + unsigned long fpexc; + int err = 0; ++ u32 fpsid = fmrx(FPSID); + + /* Disable VFP to avoid corrupting the new thread state. */ + vfp_flush_hwstate(thread); +@@ -627,8 +635,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, + /* Ensure the VFP is enabled. */ + fpexc |= FPEXC_EN; + +- /* Ensure FPINST2 is invalid and the exception flag is cleared. */ +- fpexc &= ~(FPEXC_EX | FPEXC_FP2V); ++ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */ ++ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) { ++ /* Ensure FPINST2 is invalid and the exception flag is cleared. */ ++ fpexc &= ~(FPEXC_EX | FPEXC_FP2V); ++ } ++ + hwstate->fpexc = fpexc; + + __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); +@@ -698,7 +710,8 @@ void kernel_neon_begin(void) + cpu = get_cpu(); + + fpexc = fmrx(FPEXC) | FPEXC_EN; +- fmxr(FPEXC, fpexc); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + + /* + * Save the userland NEON/VFP state. Under UP, + +From c6c5a7c11bc71d5ab6d648e652ce068f77436928 Mon Sep 17 00:00:00 2001 +From: Martin Cerveny +Date: Mon, 13 Feb 2017 17:23:47 +0100 +Subject: [PATCH 146/187] dwc_otg: fix summarize urb->actual_length for + isochronous transfers + +Kernel does not copy input data of ISO transfers to userspace +if actual_length is set only in ISO transfers and not summarized +in urb->actual_length. Fixes raspberrypi/linux#903 +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +index 162a656501988e56c9d780b7793d365fde09f801..992269d61ecf48126379a38e528f719009ee1d75 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +@@ -334,10 +334,12 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + int i; + + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); ++ urb->actual_length = 0; + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = + dwc_otg_hcd_urb_get_iso_desc_actual_length + (dwc_otg_urb, i); ++ urb->actual_length += urb->iso_frame_desc[i].actual_length; + urb->iso_frame_desc[i].status = + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); + } + +From e4289e93507bd88011935f952254c631152dcbd5 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Tue, 22 Nov 2016 12:45:28 -0800 +Subject: [PATCH 147/187] clk: bcm2835: Fix ->fixed_divider of pllh_aux + +There is no fixed divider on pllh_aux. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit f2a46926aba1f0c33944901d2420a6a887455ddc) +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 21e2a538ff0d0ab4e63adff9b93705f3d45fa15d..a99ccf9f056d3a3e7c482339e08483f3701ebc04 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1607,7 +1607,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 1), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( + .name = "pllh_pix", + .source_pll = "pllh", + +From ed089f64e82626e60252bc56fda8286e2eb7e110 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 1 Dec 2016 22:00:19 +0100 +Subject: [PATCH 148/187] clk: bcm: Support rate change propagation on bcm2835 + clocks + +Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set +to a precise rate (in our case 108MHz). With the current implementation, +where peripheral clocks are not allowed to forward rate change requests +to their parents, it is impossible to match this requirement unless the +bootloader has configured things correctly, or a specific rate has been +assigned through the DT (with the assigned-clk-rates property). + +Add a new field to struct bcm2835_clock_data to specify which parent +clocks accept rate change propagation, and support set rate propagation +in bcm2835_clock_determine_rate(). + +Signed-off-by: Boris Brezillon +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 155e8b3b0ee320ae866b97dd31eba8a1f080a772) +--- + drivers/clk/bcm/clk-bcm2835.c | 67 ++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 63 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index a99ccf9f056d3a3e7c482339e08483f3701ebc04..dafaa6b22724ab41dac1327cfa81de09908a4dfd 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -436,6 +436,9 @@ struct bcm2835_clock_data { + const char *const *parents; + int num_mux_parents; + ++ /* Bitmap encoding which parents accept rate change propagation. */ ++ unsigned int set_rate_parent; ++ + u32 ctl_reg; + u32 div_reg; + +@@ -1017,10 +1020,60 @@ bcm2835_clk_is_pllc(struct clk_hw *hw) + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; + } + ++static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, ++ int parent_idx, ++ unsigned long rate, ++ u32 *div, ++ unsigned long *prate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ struct bcm2835_cprman *cprman = clock->cprman; ++ const struct bcm2835_clock_data *data = clock->data; ++ unsigned long best_rate; ++ u32 curdiv, mindiv, maxdiv; ++ struct clk_hw *parent; ++ ++ parent = clk_hw_get_parent_by_index(hw, parent_idx); ++ ++ if (!(BIT(parent_idx) & data->set_rate_parent)) { ++ *prate = clk_hw_get_rate(parent); ++ *div = bcm2835_clock_choose_div(hw, rate, *prate, true); ++ ++ return bcm2835_clock_rate_from_divisor(clock, *prate, ++ *div); ++ } ++ ++ if (data->frac_bits) ++ dev_warn(cprman->dev, ++ "frac bits are not used when propagating rate change"); ++ ++ /* clamp to min divider of 2 if we're dealing with a mash clock */ ++ mindiv = data->is_mash_clock ? 2 : 1; ++ maxdiv = BIT(data->int_bits) - 1; ++ ++ /* TODO: Be smart, and only test a subset of the available divisors. */ ++ for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) { ++ unsigned long tmp_rate; ++ ++ tmp_rate = clk_hw_round_rate(parent, rate * curdiv); ++ tmp_rate /= curdiv; ++ if (curdiv == mindiv || ++ (tmp_rate > best_rate && tmp_rate <= rate)) ++ best_rate = tmp_rate; ++ ++ if (best_rate == rate) ++ break; ++ } ++ ++ *div = curdiv << CM_DIV_FRAC_BITS; ++ *prate = curdiv * best_rate; ++ ++ return best_rate; ++} ++ + static int bcm2835_clock_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct clk_hw *parent, *best_parent = NULL; + bool current_parent_is_pllc; + unsigned long rate, best_rate = 0; +@@ -1048,9 +1101,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) + continue; + +- prate = clk_hw_get_rate(parent); +- div = bcm2835_clock_choose_div(hw, req->rate, prate, true); +- rate = bcm2835_clock_rate_from_divisor(clock, prate, div); ++ rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, ++ &div, &prate); + if (rate > best_rate && rate <= req->rate) { + best_parent = parent; + best_prate = prate; +@@ -1271,6 +1323,13 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, + if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0) + init.flags &= ~CLK_IS_CRITICAL; + ++ /* ++ * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate ++ * rate changes on at least of the parents. ++ */ ++ if (data->set_rate_parent) ++ init.flags |= CLK_SET_RATE_PARENT; ++ + if (data->is_vpu_clock) { + init.ops = &bcm2835_vpu_clock_clk_ops; + } else { + +From 1363bc916516c74bd7a56f1b44ae383d9a96d2e2 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 1 Dec 2016 22:00:20 +0100 +Subject: [PATCH 149/187] clk: bcm: Allow rate change propagation to PLLH_AUX + on VEC clock + +The VEC clock requires needs to be set at exactly 108MHz. Allow rate +change propagation on PLLH_AUX to match this requirement wihtout +impacting other IPs (PLLH is currently only used by the HDMI encoder, +which cannot be enabled when the VEC encoder is enabled). + +Signed-off-by: Boris Brezillon +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit d86d46af84855403c00018be1c3e7bc190f2a6cd) +--- + drivers/clk/bcm/clk-bcm2835.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index dafaa6b22724ab41dac1327cfa81de09908a4dfd..0453d7c6a63923370e4191db2c4d083b893b3b47 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1870,7 +1870,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_VECCTL, + .div_reg = CM_VECDIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ /* ++ * Allow rate change propagation only on PLLH_AUX which is ++ * assigned index 7 in the parent array. ++ */ ++ .set_rate_parent = BIT(7)), + + /* dsi clocks */ + [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( + +From 9566e3eae15f82c4d58908e6941723413a6794e1 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 12 Dec 2016 09:00:53 +0100 +Subject: [PATCH 150/187] clk: bcm: Fix 'maybe-uninitialized' warning in + bcm2835_clock_choose_div_and_prate() + +best_rate is reported as potentially uninitialized by gcc. + +Signed-off-by: Boris Brezillon +Fixes: 155e8b3b0ee3 ("clk: bcm: Support rate change propagation on bcm2835 clocks") +Reported-by: Stephen Rothwell +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 2aab7a2055a1705c9e30920d95a596226999eb21) +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 0453d7c6a63923370e4191db2c4d083b893b3b47..9d895726ebb24bc78a2014870dbdd7c779cd1cdf 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1029,7 +1029,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + const struct bcm2835_clock_data *data = clock->data; +- unsigned long best_rate; ++ unsigned long best_rate = 0; + u32 curdiv, mindiv, maxdiv; + struct clk_hw *parent; + + +From bea6b2c5eb021f0e20eb9600159a3c9351411670 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:55 +1100 +Subject: [PATCH 151/187] clk: bcm2835: Don't rate change PLLs on behalf of DSI + PLL dividers. + +Our core PLLs are intended to be configured once and left alone. With +the SET_RATE_PARENT, asking to set the PLLD_DSI1 clock rate would +change PLLD just to get closer to the requested DSI clock, thus +changing PLLD_PER, the UART and ethernet PHY clock rates downstream of +it, and breaking ethernet. + +We *do* want PLLH to change so that PLLH_AUX can be exactly the value +we want, though. Thus, we need to have a per-divider policy of +whether to pass rate changes up. + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 55486091bd1e1c5ed28c43c0d6b3392468a9adb5) +--- + drivers/clk/bcm/clk-bcm2835.c | 42 ++++++++++++++++++++++++++++-------------- + 1 file changed, 28 insertions(+), 14 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 9d895726ebb24bc78a2014870dbdd7c779cd1cdf..b58cff2756581ba7e0be8a818cdbdf72eedcb182 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -428,6 +428,7 @@ struct bcm2835_pll_divider_data { + u32 load_mask; + u32 hold_mask; + u32 fixed_divider; ++ u32 flags; + }; + + struct bcm2835_clock_data { +@@ -1252,7 +1253,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + init.num_parents = 1; + init.name = divider_name; + init.ops = &bcm2835_pll_divider_clk_ops; +- init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; ++ init.flags = data->flags | CLK_IGNORE_UNUSED; + + divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); + if (!divider) +@@ -1475,7 +1476,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_CORE, + .load_mask = CM_PLLA_LOADCORE, + .hold_mask = CM_PLLA_HOLDCORE, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( + .name = "plla_per", + .source_pll = "plla", +@@ -1483,7 +1485,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_PER, + .load_mask = CM_PLLA_LOADPER, + .hold_mask = CM_PLLA_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( + .name = "plla_dsi0", + .source_pll = "plla", +@@ -1499,7 +1502,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_CCP2, + .load_mask = CM_PLLA_LOADCCP2, + .hold_mask = CM_PLLA_HOLDCCP2, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* PLLB is used for the ARM's clock. */ + [BCM2835_PLLB] = REGISTER_PLL( +@@ -1523,7 +1527,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLB_ARM, + .load_mask = CM_PLLB_LOADARM, + .hold_mask = CM_PLLB_HOLDARM, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* + * PLLC is the core PLL, used to drive the core VPU clock. +@@ -1552,7 +1557,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE0, + .load_mask = CM_PLLC_LOADCORE0, + .hold_mask = CM_PLLC_HOLDCORE0, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV( + .name = "pllc_core1", + .source_pll = "pllc", +@@ -1560,7 +1566,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE1, + .load_mask = CM_PLLC_LOADCORE1, + .hold_mask = CM_PLLC_HOLDCORE1, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV( + .name = "pllc_core2", + .source_pll = "pllc", +@@ -1568,7 +1575,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE2, + .load_mask = CM_PLLC_LOADCORE2, + .hold_mask = CM_PLLC_HOLDCORE2, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_PER] = REGISTER_PLL_DIV( + .name = "pllc_per", + .source_pll = "pllc", +@@ -1576,7 +1584,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_PER, + .load_mask = CM_PLLC_LOADPER, + .hold_mask = CM_PLLC_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* + * PLLD is the display PLL, used to drive DSI display panels. +@@ -1605,7 +1614,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLD_CORE, + .load_mask = CM_PLLD_LOADCORE, + .hold_mask = CM_PLLD_HOLDCORE, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLD_PER] = REGISTER_PLL_DIV( + .name = "plld_per", + .source_pll = "plld", +@@ -1613,7 +1623,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLD_PER, + .load_mask = CM_PLLD_LOADPER, + .hold_mask = CM_PLLD_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV( + .name = "plld_dsi0", + .source_pll = "plld", +@@ -1658,7 +1669,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_RCAL, + .load_mask = CM_PLLH_LOADRCAL, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 10, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV( + .name = "pllh_aux", + .source_pll = "pllh", +@@ -1666,7 +1678,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( + .name = "pllh_pix", + .source_pll = "pllh", +@@ -1674,7 +1687,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_PIX, + .load_mask = CM_PLLH_LOADPIX, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 10, ++ .flags = CLK_SET_RATE_PARENT), + + /* the clocks */ + + +From 006ab754ec12782715f3331a6fb2cda2b49e6b1d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:56 +1100 +Subject: [PATCH 152/187] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. + +The DSI pixel clocks are muxed from clocks generated in the analog phy +by the DSI driver. In order to set them as parents, we need to do the +same name lookup dance on them as we do for our root oscillator. + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 8a39e9fa578229fd4604266c6ebb1a3a77d7994c) +--- + .../bindings/clock/brcm,bcm2835-cprman.txt | 15 ++- + drivers/clk/bcm/clk-bcm2835.c | 121 +++++++++++++++++++-- + include/dt-bindings/clock/bcm2835.h | 2 + + 3 files changed, 125 insertions(+), 13 deletions(-) + +diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +index e56a1df3a9d3ca7fefbc5058072ee392c49b4cfc..dd906db34b328a581e4f4d99d11284544ff817f4 100644 +--- a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt ++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +@@ -16,7 +16,20 @@ Required properties: + - #clock-cells: Should be <1>. The permitted clock-specifier values can be + found in include/dt-bindings/clock/bcm2835.h + - reg: Specifies base physical address and size of the registers +-- clocks: The external oscillator clock phandle ++- clocks: phandles to the parent clocks used as input to the module, in ++ the following order: ++ ++ - External oscillator ++ - DSI0 byte clock ++ - DSI0 DDR2 clock ++ - DSI0 DDR clock ++ - DSI1 byte clock ++ - DSI1 DDR2 clock ++ - DSI1 DDR clock ++ ++ Only external oscillator is required. The DSI clocks may ++ not be present, in which case their children will be ++ unusable. + + Example: + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index b58cff2756581ba7e0be8a818cdbdf72eedcb182..b2c277b378ee799a4f8e05ad076d1253e85cb392 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -297,11 +297,32 @@ + #define LOCK_TIMEOUT_NS 100000000 + #define BCM2835_MAX_FB_RATE 1750000000u + ++/* ++ * Names of clocks used within the driver that need to be replaced ++ * with an external parent's name. This array is in the order that ++ * the clocks node in the DT references external clocks. ++ */ ++static const char *const cprman_parent_names[] = { ++ "xosc", ++ "dsi0_byte", ++ "dsi0_ddr2", ++ "dsi0_ddr", ++ "dsi1_byte", ++ "dsi1_ddr2", ++ "dsi1_ddr", ++}; ++ + struct bcm2835_cprman { + struct device *dev; + void __iomem *regs; + spinlock_t regs_lock; /* spinlock for all clocks */ +- const char *osc_name; ++ ++ /* ++ * Real names of cprman clock parents looked up through ++ * of_clk_get_parent_name(), which will be used in the ++ * parent_names[] arrays for clock registration. ++ */ ++ const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)]; + + /* Must be last */ + struct clk_hw_onecell_data onecell; +@@ -907,6 +928,9 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, + const struct bcm2835_clock_data *data = clock->data; + u64 temp; + ++ if (data->int_bits == 0 && data->frac_bits == 0) ++ return parent_rate; ++ + /* + * The divisor is a 12.12 fixed point field, but only some of + * the bits are populated in any given clock. +@@ -930,7 +954,12 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + const struct bcm2835_clock_data *data = clock->data; +- u32 div = cprman_read(cprman, data->div_reg); ++ u32 div; ++ ++ if (data->int_bits == 0 && data->frac_bits == 0) ++ return parent_rate; ++ ++ div = cprman_read(cprman, data->div_reg); + + return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); + } +@@ -1209,7 +1238,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + memset(&init, 0, sizeof(init)); + + /* All of the PLLs derive from the external oscillator. */ +- init.parent_names = &cprman->osc_name; ++ init.parent_names = &cprman->real_parent_names[0]; + init.num_parents = 1; + init.name = data->name; + init.ops = &bcm2835_pll_clk_ops; +@@ -1295,18 +1324,22 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, + struct bcm2835_clock *clock; + struct clk_init_data init; + const char *parents[1 << CM_SRC_BITS]; +- size_t i; ++ size_t i, j; + int ret; + + /* +- * Replace our "xosc" references with the oscillator's +- * actual name. ++ * Replace our strings referencing parent clocks with the ++ * actual clock-output-name of the parent. + */ + for (i = 0; i < data->num_mux_parents; i++) { +- if (strcmp(data->parents[i], "xosc") == 0) +- parents[i] = cprman->osc_name; +- else +- parents[i] = data->parents[i]; ++ parents[i] = data->parents[i]; ++ ++ for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) { ++ if (strcmp(parents[i], cprman_parent_names[j]) == 0) { ++ parents[i] = cprman->real_parent_names[j]; ++ break; ++ } ++ } + } + + memset(&init, 0, sizeof(init)); +@@ -1442,6 +1475,47 @@ static const char *const bcm2835_clock_vpu_parents[] = { + __VA_ARGS__) + + /* ++ * DSI parent clocks. The DSI byte/DDR/DDR2 clocks come from the DSI ++ * analog PHY. The _inv variants are generated internally to cprman, ++ * but we don't use them so they aren't hooked up. ++ */ ++static const char *const bcm2835_clock_dsi0_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "dsi0_ddr", ++ "dsi0_ddr_inv", ++ "dsi0_ddr2", ++ "dsi0_ddr2_inv", ++ "dsi0_byte", ++ "dsi0_byte_inv", ++}; ++ ++static const char *const bcm2835_clock_dsi1_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "dsi1_ddr", ++ "dsi1_ddr_inv", ++ "dsi1_ddr2", ++ "dsi1_ddr2_inv", ++ "dsi1_byte", ++ "dsi1_byte_inv", ++}; ++ ++#define REGISTER_DSI0_CLK(...) REGISTER_CLK( \ ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \ ++ .parents = bcm2835_clock_dsi0_parents, \ ++ __VA_ARGS__) ++ ++#define REGISTER_DSI1_CLK(...) REGISTER_CLK( \ ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \ ++ .parents = bcm2835_clock_dsi1_parents, \ ++ __VA_ARGS__) ++ ++/* + * the real definition of all the pll, pll_dividers and clocks + * these make use of the above REGISTER_* macros + */ +@@ -1904,6 +1978,18 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .div_reg = CM_DSI1EDIV, + .int_bits = 4, + .frac_bits = 8), ++ [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( ++ .name = "dsi0p", ++ .ctl_reg = CM_DSI0PCTL, ++ .div_reg = CM_DSI0PDIV, ++ .int_bits = 0, ++ .frac_bits = 0), ++ [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( ++ .name = "dsi1p", ++ .ctl_reg = CM_DSI1PCTL, ++ .div_reg = CM_DSI1PDIV, ++ .int_bits = 0, ++ .frac_bits = 0), + + /* the gates */ + +@@ -1962,8 +2048,19 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + if (IS_ERR(cprman->regs)) + return PTR_ERR(cprman->regs); + +- cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0); +- if (!cprman->osc_name) ++ memcpy(cprman->real_parent_names, cprman_parent_names, ++ sizeof(cprman_parent_names)); ++ of_clk_parent_fill(dev->of_node, cprman->real_parent_names, ++ ARRAY_SIZE(cprman_parent_names)); ++ ++ /* ++ * Make sure the external oscillator has been registered. ++ * ++ * The other (DSI) clocks are not present on older device ++ * trees, which we still need to support for backwards ++ * compatibility. ++ */ ++ if (!cprman->real_parent_names[0]) + return -ENODEV; + + platform_set_drvdata(pdev, cprman); +diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h +index 360e00cefd35679b49890234b5c369fb52b89e20..a0c812b0fa391d149b4f546db39bdc4bef207960 100644 +--- a/include/dt-bindings/clock/bcm2835.h ++++ b/include/dt-bindings/clock/bcm2835.h +@@ -64,3 +64,5 @@ + #define BCM2835_CLOCK_CAM1 46 + #define BCM2835_CLOCK_DSI0E 47 + #define BCM2835_CLOCK_DSI1E 48 ++#define BCM2835_CLOCK_DSI0P 49 ++#define BCM2835_CLOCK_DSI1P 50 + +From 8e9befa946ea6c9eff07a323d7710fb06f0d8422 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:57 +1100 +Subject: [PATCH 153/187] clk: bcm2835: Add leaf clock measurement support, + disabled by default + +This proved incredibly useful during debugging of the DSI driver, to +see if our clocks were running at rate we requested. Let's leave it +here for the next person interacting with clocks on the platform (and +so that hopefully we can just hook it up to debugfs some day). + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 3f9195811d8d829556c4cd88d3f9e56a80d5ba60) +--- + drivers/clk/bcm/clk-bcm2835.c | 144 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 119 insertions(+), 25 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index b2c277b378ee799a4f8e05ad076d1253e85cb392..136e5d28f9eaeaa10d45382a0f31da9f4adb91ef 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -98,7 +99,8 @@ + #define CM_SMIDIV 0x0b4 + /* no definition for 0x0b8 and 0x0bc */ + #define CM_TCNTCTL 0x0c0 +-#define CM_TCNTDIV 0x0c4 ++# define CM_TCNT_SRC1_SHIFT 12 ++#define CM_TCNTCNT 0x0c4 + #define CM_TECCTL 0x0c8 + #define CM_TECDIV 0x0cc + #define CM_TD0CTL 0x0d0 +@@ -338,6 +340,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) + return readl(cprman->regs + reg); + } + ++/* Does a cycle of measuring a clock through the TCNT clock, which may ++ * source from many other clocks in the system. ++ */ ++static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman, ++ u32 tcnt_mux) ++{ ++ u32 osccount = 19200; /* 1ms */ ++ u32 count; ++ ktime_t timeout; ++ ++ spin_lock(&cprman->regs_lock); ++ ++ cprman_write(cprman, CM_TCNTCTL, CM_KILL); ++ ++ cprman_write(cprman, CM_TCNTCTL, ++ (tcnt_mux & CM_SRC_MASK) | ++ (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT); ++ ++ cprman_write(cprman, CM_OSCCOUNT, osccount); ++ ++ /* do a kind delay at the start */ ++ mdelay(1); ++ ++ /* Finish off whatever is left of OSCCOUNT */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (cprman_read(cprman, CM_OSCCOUNT)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n"); ++ count = 0; ++ goto out; ++ } ++ cpu_relax(); ++ } ++ ++ /* Wait for BUSY to clear. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "timeout waiting for !BUSY\n"); ++ count = 0; ++ goto out; ++ } ++ cpu_relax(); ++ } ++ ++ count = cprman_read(cprman, CM_TCNTCNT); ++ ++ cprman_write(cprman, CM_TCNTCTL, 0); ++ ++out: ++ spin_unlock(&cprman->regs_lock); ++ ++ return count * 1000; ++} ++ + static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, + struct debugfs_reg32 *regs, size_t nregs, + struct dentry *dentry) +@@ -473,6 +530,8 @@ struct bcm2835_clock_data { + + bool is_vpu_clock; + bool is_mash_clock; ++ ++ u32 tcnt_mux; + }; + + struct bcm2835_gate_data { +@@ -1008,6 +1067,17 @@ static int bcm2835_clock_on(struct clk_hw *hw) + CM_GATE); + spin_unlock(&cprman->regs_lock); + ++ /* Debug code to measure the clock once it's turned on to see ++ * if it's ticking at the rate we expect. ++ */ ++ if (data->tcnt_mux && false) { ++ dev_info(cprman->dev, ++ "clk %s: rate %ld, measure %ld\n", ++ data->name, ++ clk_hw_get_rate(hw), ++ bcm2835_measure_tcnt_mux(cprman, data->tcnt_mux)); ++ } ++ + return 0; + } + +@@ -1774,7 +1844,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_OTPCTL, + .div_reg = CM_OTPDIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 6), + /* + * Used for a 1Mhz clock for the system clocksource, and also used + * bythe watchdog timer and the camera pulse generator. +@@ -1808,13 +1879,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_H264CTL, + .div_reg = CM_H264DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 1), + [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( + .name = "isp", + .ctl_reg = CM_ISPCTL, + .div_reg = CM_ISPDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 2), + + /* + * Secondary SDRAM clock. Used for low-voltage modes when the PLL +@@ -1825,13 +1898,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_SDCCTL, + .div_reg = CM_SDCDIV, + .int_bits = 6, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 3), + [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( + .name = "v3d", + .ctl_reg = CM_V3DCTL, + .div_reg = CM_V3DDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 4), + /* + * VPU clock. This doesn't have an enable bit, since it drives + * the bus for everything else, and is special so it doesn't need +@@ -1845,7 +1920,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .int_bits = 12, + .frac_bits = 8, + .flags = CLK_IS_CRITICAL, +- .is_vpu_clock = true), ++ .is_vpu_clock = true, ++ .tcnt_mux = 5), + + /* clocks with per parent mux */ + [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( +@@ -1853,19 +1929,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_AVEOCTL, + .div_reg = CM_AVEODIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 38), + [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( + .name = "cam0", + .ctl_reg = CM_CAM0CTL, + .div_reg = CM_CAM0DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 14), + [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( + .name = "cam1", + .ctl_reg = CM_CAM1CTL, + .div_reg = CM_CAM1DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 15), + [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( + .name = "dft", + .ctl_reg = CM_DFTCTL, +@@ -1877,7 +1956,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_DPICTL, + .div_reg = CM_DPIDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 17), + + /* Arasan EMMC clock */ + [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( +@@ -1885,7 +1965,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_EMMCCTL, + .div_reg = CM_EMMCDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 39), + + /* General purpose (GPIO) clocks */ + [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( +@@ -1894,7 +1975,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .div_reg = CM_GP0DIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 20), + [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( + .name = "gp1", + .ctl_reg = CM_GP1CTL, +@@ -1902,7 +1984,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .int_bits = 12, + .frac_bits = 12, + .flags = CLK_IS_CRITICAL, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 21), + [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( + .name = "gp2", + .ctl_reg = CM_GP2CTL, +@@ -1917,40 +2000,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_HSMCTL, + .div_reg = CM_HSMDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 22), + [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( + .name = "pcm", + .ctl_reg = CM_PCMCTL, + .div_reg = CM_PCMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 23), + [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( + .name = "pwm", + .ctl_reg = CM_PWMCTL, + .div_reg = CM_PWMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 24), + [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( + .name = "slim", + .ctl_reg = CM_SLIMCTL, + .div_reg = CM_SLIMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 25), + [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( + .name = "smi", + .ctl_reg = CM_SMICTL, + .div_reg = CM_SMIDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 27), + [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( + .name = "uart", + .ctl_reg = CM_UARTCTL, + .div_reg = CM_UARTDIV, + .int_bits = 10, +- .frac_bits = 12), ++ .frac_bits = 12, ++ .tcnt_mux = 28), + + /* TV encoder clock. Only operating frequency is 108Mhz. */ + [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( +@@ -1963,7 +2052,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + * Allow rate change propagation only on PLLH_AUX which is + * assigned index 7 in the parent array. + */ +- .set_rate_parent = BIT(7)), ++ .set_rate_parent = BIT(7), ++ .tcnt_mux = 29), + + /* dsi clocks */ + [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( +@@ -1971,25 +2061,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_DSI0ECTL, + .div_reg = CM_DSI0EDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 18), + [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( + .name = "dsi1e", + .ctl_reg = CM_DSI1ECTL, + .div_reg = CM_DSI1EDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 19), + [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( + .name = "dsi0p", + .ctl_reg = CM_DSI0PCTL, + .div_reg = CM_DSI0PDIV, + .int_bits = 0, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 12), + [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( + .name = "dsi1p", + .ctl_reg = CM_DSI1PCTL, + .div_reg = CM_DSI1PDIV, + .int_bits = 0, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 13), + + /* the gates */ + + +From c0d869fdcc5294882af65525e0b3cdfd7bb98ea4 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 26 Apr 2016 13:46:13 -0700 +Subject: [PATCH 154/187] drm/panel: Add support for the Raspberry Pi 7" + Touchscreen. + +This driver communicates with the Atmel microcontroller for sequencing +the poweron of the TC358762 DSI-DPI bridge and controlling the +backlight PWM. + +The following lines are required in config.txt, to keep the firmware +from trying to bash our I2C lines and steal the DSI interrupts: + + disable_touchscreen=1 + ignore_lcd=2 + mask_gpu_interrupt1=0x1000 + +This means that the firmware won't power on the panel at boot time (no +rainbow) and the touchscreen input won't work. The native input +driver for the touchscreen still needs to be written. + +v2: Set the same default orientation as the closed source firmware + used, which is the best for viewing angle. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/panel/Kconfig | 8 + + drivers/gpu/drm/panel/Makefile | 1 + + .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 514 +++++++++++++++++++++ + 3 files changed, 523 insertions(+) + create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c + +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 62aba976e744c146c26d7fedf44c54cdd480361e..de7a56ab758b8f043194391f9b9e43df65c06d0a 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -52,6 +52,14 @@ config DRM_PANEL_PANASONIC_VVX10F034N00 + WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some + Xperia Z2 tablets + ++config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN ++ tristate "Raspberry Pi 7-inch touchscreen panel" ++ depends on DRM_MIPI_DSI ++ help ++ Say Y here if you want to enable support for the Raspberry ++ Pi 7" Touchscreen. To compile this driver as a module, ++ choose M here. ++ + config DRM_PANEL_SAMSUNG_S6E8AA0 + tristate "Samsung S6E8AA0 DSI video mode panel" + depends on OF +diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile +index a5c7ec0236e0174079cce0f07d46372967e9cf3b..e8a7ed280fff907e5a730a13ae9a3e5e34cacce4 100644 +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -2,6 +2,7 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o + obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o + obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o + obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o ++obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o + obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o + obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o + obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o +diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +new file mode 100644 +index 0000000000000000000000000000000000000000..1a536fe4d040f5fafe324baee110a6225dd0be08 +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -0,0 +1,514 @@ ++/* ++ * Copyright © 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Portions of this file (derived from panel-simple.c) are: ++ * ++ * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++/** ++ * DOC: Raspberry Pi 7" touchscreen panel driver. ++ * ++ * The 7" touchscreen consists of a DPI LCD panel, a Toshiba ++ * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR ++ * controlling power management, the LCD PWM, and the touchscreen. ++ * ++ * This driver presents this device as a MIPI DSI panel to the DRM ++ * driver, and should expose the touchscreen as a HID device. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* I2C registers of the Atmel microcontroller. */ ++enum REG_ADDR { ++ REG_ID = 0x80, ++ REG_PORTA, // BIT(2) for horizontal flip, BIT(3) for vertical flip ++ REG_PORTB, ++ REG_PORTC, ++ REG_PORTD, ++ REG_POWERON, ++ REG_PWM, ++ REG_DDRA, ++ REG_DDRB, ++ REG_DDRC, ++ REG_DDRD, ++ REG_TEST, ++ REG_WR_ADDRL, ++ REG_WR_ADDRH, ++ REG_READH, ++ REG_READL, ++ REG_WRITEH, ++ REG_WRITEL, ++ REG_ID2, ++}; ++ ++/* We only turn the PWM on or off, without varying values. */ ++#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1 ++ ++/* DSI D-PHY Layer Registers */ ++#define D0W_DPHYCONTTX 0x0004 ++#define CLW_DPHYCONTRX 0x0020 ++#define D0W_DPHYCONTRX 0x0024 ++#define D1W_DPHYCONTRX 0x0028 ++#define COM_DPHYCONTRX 0x0038 ++#define CLW_CNTRL 0x0040 ++#define D0W_CNTRL 0x0044 ++#define D1W_CNTRL 0x0048 ++#define DFTMODE_CNTRL 0x0054 ++ ++/* DSI PPI Layer Registers */ ++#define PPI_STARTPPI 0x0104 ++#define PPI_BUSYPPI 0x0108 ++#define PPI_LINEINITCNT 0x0110 ++#define PPI_LPTXTIMECNT 0x0114 ++//#define PPI_LANEENABLE 0x0134 ++//#define PPI_TX_RX_TA 0x013C ++#define PPI_CLS_ATMR 0x0140 ++#define PPI_D0S_ATMR 0x0144 ++#define PPI_D1S_ATMR 0x0148 ++#define PPI_D0S_CLRSIPOCOUNT 0x0164 ++#define PPI_D1S_CLRSIPOCOUNT 0x0168 ++#define CLS_PRE 0x0180 ++#define D0S_PRE 0x0184 ++#define D1S_PRE 0x0188 ++#define CLS_PREP 0x01A0 ++#define D0S_PREP 0x01A4 ++#define D1S_PREP 0x01A8 ++#define CLS_ZERO 0x01C0 ++#define D0S_ZERO 0x01C4 ++#define D1S_ZERO 0x01C8 ++#define PPI_CLRFLG 0x01E0 ++#define PPI_CLRSIPO 0x01E4 ++#define HSTIMEOUT 0x01F0 ++#define HSTIMEOUTENABLE 0x01F4 ++ ++/* DSI Protocol Layer Registers */ ++#define DSI_STARTDSI 0x0204 ++#define DSI_BUSYDSI 0x0208 ++#define DSI_LANEENABLE 0x0210 ++# define DSI_LANEENABLE_CLOCK BIT(0) ++# define DSI_LANEENABLE_D0 BIT(1) ++# define DSI_LANEENABLE_D1 BIT(2) ++ ++#define DSI_LANESTATUS0 0x0214 ++#define DSI_LANESTATUS1 0x0218 ++#define DSI_INTSTATUS 0x0220 ++#define DSI_INTMASK 0x0224 ++#define DSI_INTCLR 0x0228 ++#define DSI_LPTXTO 0x0230 ++#define DSI_MODE 0x0260 ++#define DSI_PAYLOAD0 0x0268 ++#define DSI_PAYLOAD1 0x026C ++#define DSI_SHORTPKTDAT 0x0270 ++#define DSI_SHORTPKTREQ 0x0274 ++#define DSI_BTASTA 0x0278 ++#define DSI_BTACLR 0x027C ++ ++/* DSI General Registers */ ++#define DSIERRCNT 0x0300 ++#define DSISIGMOD 0x0304 ++ ++/* DSI Application Layer Registers */ ++#define APLCTRL 0x0400 ++#define APLSTAT 0x0404 ++#define APLERR 0x0408 ++#define PWRMOD 0x040C ++#define RDPKTLN 0x0410 ++#define PXLFMT 0x0414 ++#define MEMWRCMD 0x0418 ++ ++/* LCDC/DPI Host Registers */ ++#define LCDCTRL 0x0420 ++#define HSR 0x0424 ++#define HDISPR 0x0428 ++#define VSR 0x042C ++#define VDISPR 0x0430 ++#define VFUEN 0x0434 ++ ++/* DBI-B Host Registers */ ++#define DBIBCTRL 0x0440 ++ ++/* SPI Master Registers */ ++#define SPICMR 0x0450 ++#define SPITCR 0x0454 ++ ++/* System Controller Registers */ ++#define SYSSTAT 0x0460 ++#define SYSCTRL 0x0464 ++#define SYSPLL1 0x0468 ++#define SYSPLL2 0x046C ++#define SYSPLL3 0x0470 ++#define SYSPMCTRL 0x047C ++ ++/* GPIO Registers */ ++#define GPIOC 0x0480 ++#define GPIOO 0x0484 ++#define GPIOI 0x0488 ++ ++/* I2C Registers */ ++#define I2CCLKCTRL 0x0490 ++ ++/* Chip/Rev Registers */ ++#define IDREG 0x04A0 ++ ++/* Debug Registers */ ++#define WCMDQUEUE 0x0500 ++#define RCMDQUEUE 0x0504 ++ ++struct rpi_touchscreen { ++ struct drm_panel base; ++ struct mipi_dsi_device *dsi; ++ struct i2c_client *bridge_i2c; ++ ++ /* Version of the firmware on the bridge chip */ ++ int atmel_ver; ++}; ++ ++static const struct drm_display_mode rpi_touchscreen_modes[] = { ++ { ++ /* The DSI PLL can only integer divide from the 2Ghz ++ * PLLD, giving us few choices. We pick a divide by 3 ++ * as our DSI HS clock, giving us a pixel clock of ++ * that divided by 24 bits. Pad out HFP to get our ++ * panel to refresh at 60Hz, even if that doesn't ++ * match the datasheet. ++ */ ++#define PIXEL_CLOCK ((2000000000 / 3) / 24) ++#define VREFRESH 60 ++#define VTOTAL (480 + 7 + 2 + 21) ++#define HACT 800 ++#define HSW 2 ++#define HBP 46 ++#define HFP ((PIXEL_CLOCK / (VTOTAL * VREFRESH)) - (HACT + HSW + HBP)) ++ ++ .clock = PIXEL_CLOCK / 1000, ++ .hdisplay = HACT, ++ .hsync_start = HACT + HFP, ++ .hsync_end = HACT + HFP + HSW, ++ .htotal = HACT + HFP + HSW + HBP, ++ .vdisplay = 480, ++ .vsync_start = 480 + 7, ++ .vsync_end = 480 + 7 + 2, ++ .vtotal = VTOTAL, ++ .vrefresh = 60, ++ }, ++}; ++ ++static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) ++{ ++ return container_of(panel, struct rpi_touchscreen, base); ++} ++ ++static u8 rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) ++{ ++ return i2c_smbus_read_byte_data(ts->bridge_i2c, reg); ++} ++ ++static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, ++ u8 reg, u8 val) ++{ ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(ts->bridge_i2c, reg, val); ++ if (ret) ++ dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret); ++} ++ ++static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) ++{ ++#if 0 ++ /* The firmware uses LP DSI transactions like this to bring up ++ * the hardware, which should be faster than using I2C to then ++ * pass to the Toshiba. However, I was unable to get it to ++ * work. ++ */ ++ u8 msg[] = { ++ reg, ++ reg >> 8, ++ val, ++ val >> 8, ++ val >> 16, ++ val >> 24, ++ }; ++ ++ mipi_dsi_dcs_write_buffer(ts->dsi, msg, sizeof(msg)); ++#else ++ rpi_touchscreen_i2c_write(ts, REG_WR_ADDRH, reg >> 8); ++ rpi_touchscreen_i2c_write(ts, REG_WR_ADDRL, reg); ++ rpi_touchscreen_i2c_write(ts, REG_WRITEH, val >> 8); ++ rpi_touchscreen_i2c_write(ts, REG_WRITEL, val); ++#endif ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_disable(struct drm_panel *panel) ++{ ++ struct rpi_touchscreen *ts = panel_to_ts(panel); ++ ++ rpi_touchscreen_i2c_write(ts, REG_PWM, 0); ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ udelay(1); ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_noop(struct drm_panel *panel) ++{ ++ return 0; ++} ++ ++static int rpi_touchscreen_enable(struct drm_panel *panel) ++{ ++ struct rpi_touchscreen *ts = panel_to_ts(panel); ++ int i; ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 1); ++ /* Wait for nPWRDWN to go low to indicate poweron is done. */ ++ for (i = 0; i < 100; i++) { ++ if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1) ++ break; ++ } ++ ++ rpi_touchscreen_write(ts, DSI_LANEENABLE, ++ DSI_LANEENABLE_CLOCK | ++ DSI_LANEENABLE_D0 | ++ (ts->dsi->lanes > 1 ? DSI_LANEENABLE_D1 : 0)); ++ rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05); ++ rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05); ++ rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00); ++ rpi_touchscreen_write(ts, PPI_D1S_ATMR, 0x00); ++ rpi_touchscreen_write(ts, PPI_LPTXTIMECNT, 0x03); ++ ++ rpi_touchscreen_write(ts, SPICMR, 0x00); ++ rpi_touchscreen_write(ts, LCDCTRL, 0x00100150); ++ rpi_touchscreen_write(ts, SYSCTRL, 0x040f); ++ msleep(100); ++ ++ rpi_touchscreen_write(ts, PPI_STARTPPI, 0x01); ++ rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01); ++ msleep(100); ++ ++ /* Turn on the backlight. */ ++ rpi_touchscreen_i2c_write(ts, REG_PWM, 255); ++ ++ /* Default to the same orientation as the closed source ++ * firmware used for the panel. Runtime rotation ++ * configuration will be supported using VC4's plane ++ * orientation bits. ++ */ ++ rpi_touchscreen_i2c_write(ts, REG_PORTA, BIT(2)); ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_get_modes(struct drm_panel *panel) ++{ ++ struct drm_connector *connector = panel->connector; ++ struct drm_device *drm = panel->drm; ++ unsigned int i, num = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) { ++ const struct drm_display_mode *m = &rpi_touchscreen_modes[i]; ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(drm, m); ++ if (!mode) { ++ dev_err(drm->dev, "failed to add mode %ux%u@%u\n", ++ m->hdisplay, m->vdisplay, m->vrefresh); ++ continue; ++ } ++ ++ mode->type |= DRM_MODE_TYPE_DRIVER; ++ ++ if (i == 0) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ ++ drm_mode_probed_add(connector, mode); ++ num++; ++ } ++ ++ connector->display_info.bpc = 8; ++ connector->display_info.width_mm = 154; ++ connector->display_info.height_mm = 86; ++ ++ return num; ++} ++ ++static const struct drm_panel_funcs rpi_touchscreen_funcs = { ++ .disable = rpi_touchscreen_disable, ++ .unprepare = rpi_touchscreen_noop, ++ .prepare = rpi_touchscreen_noop, ++ .enable = rpi_touchscreen_enable, ++ .get_modes = rpi_touchscreen_get_modes, ++}; ++ ++static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev, ++ const char *name) ++{ ++ struct device_node *node; ++ struct i2c_client *client; ++ ++ node = of_parse_phandle(dev->of_node, name, 0); ++ if (!node) ++ return ERR_PTR(-ENODEV); ++ ++ client = of_find_i2c_device_by_node(node); ++ ++ of_node_put(node); ++ ++ return client; ++} ++ ++static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts; ++ int ret, ver; ++ ++ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, ts); ++ ++ ts->dsi = dsi; ++ dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_MODE_VIDEO_SYNC_PULSE | ++ MIPI_DSI_MODE_LPM); ++ dsi->format = MIPI_DSI_FMT_RGB888; ++ dsi->lanes = 1; ++ ++ ts->bridge_i2c = ++ rpi_touchscreen_get_i2c(dev, "raspberrypi,touchscreen-bridge"); ++ if (IS_ERR(ts->bridge_i2c)) { ++ ret = -EPROBE_DEFER; ++ return ret; ++ } ++ ++ ver = rpi_touchscreen_i2c_read(ts, REG_ID); ++ if (ver < 0) { ++ dev_err(dev, "Atmel I2C read failed: %d\n", ver); ++ return -ENODEV; ++ } ++ ++ switch (ver) { ++ case 0xde: ++ ts->atmel_ver = 1; ++ break; ++ case 0xc3: ++ ts->atmel_ver = 2; ++ break; ++ default: ++ dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver); ++ return -ENODEV; ++ } ++ ++ /* Turn off at boot, so we can cleanly sequence powering on. */ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ ++ drm_panel_init(&ts->base); ++ ts->base.dev = dev; ++ ts->base.funcs = &rpi_touchscreen_funcs; ++ ++ ret = drm_panel_add(&ts->base); ++ if (ret < 0) ++ goto err_release_bridge; ++ ++ return mipi_dsi_attach(dsi); ++ ++err_release_bridge: ++ put_device(&ts->bridge_i2c->dev); ++ return ret; ++} ++ ++static int rpi_touchscreen_dsi_remove(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = mipi_dsi_detach(dsi); ++ if (ret < 0) { ++ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); ++ return ret; ++ } ++ ++ drm_panel_detach(&ts->base); ++ drm_panel_remove(&ts->base); ++ ++ put_device(&ts->bridge_i2c->dev); ++ ++ return 0; ++} ++ ++static void rpi_touchscreen_dsi_shutdown(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts = dev_get_drvdata(dev); ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++} ++ ++static const struct of_device_id rpi_touchscreen_of_match[] = { ++ { .compatible = "raspberrypi,touchscreen" }, ++ { } /* sentinel */ ++}; ++MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_match); ++ ++static struct mipi_dsi_driver rpi_touchscreen_driver = { ++ .driver = { ++ .name = "raspberrypi-touchscreen", ++ .of_match_table = rpi_touchscreen_of_match, ++ }, ++ .probe = rpi_touchscreen_dsi_probe, ++ .remove = rpi_touchscreen_dsi_remove, ++ .shutdown = rpi_touchscreen_dsi_shutdown, ++}; ++module_mipi_dsi_driver(rpi_touchscreen_driver); ++ ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); ++MODULE_LICENSE("GPL v2"); + +From 3336948d2b15c1ad3623b87758bb1718259fcf03 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Jun 2016 12:29:45 -0700 +Subject: [PATCH 155/187] BCM270X: Add the DSI panel to the defconfig. + +Signed-off-by: Eric Anholt +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + arch/arm64/configs/bcmrpi3_defconfig | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 858143b9b68a9cf29714452394cb800e4f41198d..669edd7544d79838d9471fbe11b803c342f195df 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -833,6 +833,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index f0b87d15e959d88eb26e5a11244365dadb57a298..9a9cd1cdcb2f76d4408568681ec80885293bae48 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -827,6 +827,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y +diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig +index 8c4392344eb4495689c220d5d176ee8c189079fd..301611d2283f5f8800339271cea59aedcbc09130 100644 +--- a/arch/arm64/configs/bcmrpi3_defconfig ++++ b/arch/arm64/configs/bcmrpi3_defconfig +@@ -816,6 +816,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + +From ccc759f89499794d4088429377fd6e534b7177b5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 13 Dec 2016 15:15:10 -0800 +Subject: [PATCH 156/187] ARM: bcm2835: dt: Add the DSI module nodes and + clocks. + +The modules stay disabled by default, and if you want to enable DSI +you'll need an overlay that connects a panel to it. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 8 +++++++ + arch/arm/boot/dts/bcm283x.dtsi | 49 +++++++++++++++++++++++++++++++++++--- + 2 files changed, 54 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index e9b47b2bbc3390edc2541f251ae5167640a445d9..365648898f3acc4f82dc6cb58e4bbebbe249be94 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -84,3 +84,11 @@ + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; + }; ++ ++&dsi0 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI0>; ++}; ++ ++&dsi1 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI1>; ++}; +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 51cdefbf5eb265f49bd05e0aa91dfbeee3fbfdcc..41776b97b4b6b1c053d07fd357fac4ba4787ac53 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -93,10 +93,13 @@ + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + +- /* CPRMAN derives everything from the platform's +- * oscillator. ++ /* CPRMAN derives almost everything from the ++ * platform's oscillator. However, the DSI ++ * pixel clocks come from the DSI analog PHY. + */ +- clocks = <&clk_osc>; ++ clocks = <&clk_osc>, ++ <&dsi0 0>, <&dsi0 1>, <&dsi0 2>, ++ <&dsi1 0>, <&dsi1 1>, <&dsi1 2>; + }; + + rng@7e104000 { +@@ -188,6 +191,26 @@ + interrupts = <2 14>; /* pwa1 */ + }; + ++ dsi0: dsi@7e209000 { ++ compatible = "brcm,bcm2835-dsi0"; ++ reg = <0x7e209000 0x78>; ++ interrupts = <2 4>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ ++ clocks = <&clocks BCM2835_PLLA_DSI0>, ++ <&clocks BCM2835_CLOCK_DSI0E>, ++ <&clocks BCM2835_CLOCK_DSI0P>; ++ clock-names = "phy", "escape", "pixel"; ++ ++ clock-output-names = "dsi0_byte", ++ "dsi0_ddr2", ++ "dsi0_ddr"; ++ ++ status = "disabled"; ++ }; ++ + aux: aux@0x7e215000 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; +@@ -247,6 +270,26 @@ + interrupts = <2 1>; + }; + ++ dsi1: dsi@7e700000 { ++ compatible = "brcm,bcm2835-dsi1"; ++ reg = <0x7e700000 0x8c>; ++ interrupts = <2 12>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ ++ clocks = <&clocks BCM2835_PLLD_DSI1>, ++ <&clocks BCM2835_CLOCK_DSI1E>, ++ <&clocks BCM2835_CLOCK_DSI1P>; ++ clock-names = "phy", "escape", "pixel"; ++ ++ clock-output-names = "dsi1_byte", ++ "dsi1_ddr2", ++ "dsi1_ddr"; ++ ++ status = "disabled"; ++ }; ++ + i2c1: i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; + +From 54cce9bcc058fdfd75b67ba1504a7adeaa708fc8 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Jun 2016 15:09:35 -0700 +Subject: [PATCH 157/187] BCM270X: Enable the DSI panel node in the VC4 + overlay. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 5 ++++ + arch/arm/boot/dts/bcm2708-rpi-b.dts | 5 ++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 5 ++++ + arch/arm/boot/dts/bcm270x.dtsi | 27 ++++++++++++++++++++++ + arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 5 ++++ + arch/arm/boot/dts/bcm2710.dtsi | 1 - + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 22 ++++++++++++++++++ + 7 files changed, 69 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index 360da5c928dc5599b0d2a9055728087604c6b189..51f575e5d201fdfc1632e9bc8ed3bbd3e55dddcb 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -154,3 +154,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 28 0 ++ &gpio 29 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 9c49659ab246bce0656f3514f3b924bc4826b421..028ef91a6c4f5d6573204635a03b912284505baa 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -144,3 +144,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 2 0 ++ &gpio 3 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 19c83823420fc3cc20a01d07091100cb8720ff4d..a4ffeff9fda62da830e674ff06c3a5394bd9d8cf 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -154,3 +154,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 28 0 ++ &gpio 29 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi +index 36d853715f2379e1952ce3d3be58dd670e305159..caa66393518603529d284f360b2000b0ed4852ef 100644 +--- a/arch/arm/boot/dts/bcm270x.dtsi ++++ b/arch/arm/boot/dts/bcm270x.dtsi +@@ -137,6 +137,29 @@ + /* Add alias */ + status = "disabled"; + }; ++ ++ i2c_dsi: i2cdsi { ++ /* We have to use i2c-gpio because the ++ * firmware is also polling another device ++ * using the only hardware I2C bus that could ++ * connect to these pins. ++ */ ++ compatible = "i2c-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ pitouchscreen_bridge: bridge@45 { ++ compatible = "raspberrypi,touchscreen-bridge-i2c"; ++ reg = <0x45>; ++ }; ++ ++ pitouchscreen_touch: bridge@38 { ++ compatible = "raspberrypi,touchscreen-ts-i2c"; ++ reg = <0x38>; ++ }; ++ }; ++ + }; + + vdd_5v0_reg: fixedregulator_5v0 { +@@ -155,3 +178,7 @@ + regulator-always-on; + }; + }; ++ ++&dsi1 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI1>; ++}; +diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +index 12764a3495b2372ffaf47e32ea0d21326ca83686..d29ba72de727fe26b5a586e0bd0a41181c68ae04 100644 +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +@@ -201,3 +201,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 44 0 ++ &gpio 45 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2710.dtsi b/arch/arm/boot/dts/bcm2710.dtsi +index 3e134a1208610b90e2d0fc22f03c6e9f372bfcd7..3fabac6a93e846f678d846637c4f9a5f5b8e7922 100644 +--- a/arch/arm/boot/dts/bcm2710.dtsi ++++ b/arch/arm/boot/dts/bcm2710.dtsi +@@ -145,4 +145,3 @@ + interrupt-parent = <&local_intc>; + interrupts = <8>; + }; +- +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index 4f1cc20f90dc6780f74e08ebee00e5a1a6062c85..f25cd9a3936861920b0d518ff2d773ee467e2f49 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -126,6 +126,28 @@ + }; + }; + ++ fragment@16 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pitouchscreen: panel@0 { ++ compatible = "raspberrypi,touchscreen"; ++ reg = <0>; ++ raspberrypi,touchscreen-bridge = <&pitouchscreen_bridge>; ++ }; ++ }; ++ }; ++ ++ fragment@17 { ++ target = <&i2c_dsi>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; + +From 85e5a07c8adcf8733695d5da48e4bee22a019b3d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 20 Oct 2016 16:48:12 -0700 +Subject: [PATCH 158/187] drm/vc4: Fix termination of the initial scan for + branch targets. + +The loop is scanning until the original max_ip (size of the BO), but +we want to not examine any code after the PROG_END's delay slots. +There was a block trying to do that, except that we had some early +continue statements if the signal wasn't a PROG_END or a BRANCH. + +The failure mode would be that a valid shader is rejected because some +undefined memory after the PROG_END slots is parsed as a branch and +the rest of its setup is illegal. I haven't seen this in the wild, +but valgrind was complaining when about this up in the userland +simulator mode. + +Signed-off-by: Eric Anholt +(cherry picked from commit 457e67a728696c4f8e6423c64e93def50530db9a) +--- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +index 2543cf5b8b51869d51b72a5db5017dded38761be..917321ce832ffda9d3e8ca20d987437eea9a1765 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -608,9 +608,7 @@ static bool + vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + { + uint32_t max_branch_target = 0; +- bool found_shader_end = false; + int ip; +- int shader_end_ip = 0; + int last_branch = -2; + + for (ip = 0; ip < validation_state->max_ip; ip++) { +@@ -621,8 +619,13 @@ vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + uint32_t branch_target_ip; + + if (sig == QPU_SIG_PROG_END) { +- shader_end_ip = ip; +- found_shader_end = true; ++ /* There are two delay slots after program end is ++ * signaled that are still executed, then we're ++ * finished. validation_state->max_ip is the ++ * instruction after the last valid instruction in the ++ * program. ++ */ ++ validation_state->max_ip = ip + 3; + continue; + } + +@@ -676,15 +679,9 @@ vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + } + set_bit(after_delay_ip, validation_state->branch_targets); + max_branch_target = max(max_branch_target, after_delay_ip); +- +- /* There are two delay slots after program end is signaled +- * that are still executed, then we're finished. +- */ +- if (found_shader_end && ip == shader_end_ip + 2) +- break; + } + +- if (max_branch_target > shader_end_ip) { ++ if (max_branch_target > validation_state->max_ip - 3) { + DRM_ERROR("Branch landed after QPU_SIG_PROG_END"); + return false; + } + +From dcd3dff96e0737a1a0c68fb608dd898a6374a445 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 3 Nov 2016 18:53:10 -0700 +Subject: [PATCH 159/187] drm/vc4: Add support for rendering with ETC1 + textures. + +The validation for it ends up being quite simple, but I hadn't got +around to it before merging the driver. For backwards compatibility, +we also need to add a flag so that the userspace GL driver can easily +tell if the kernel will allow ETC1 textures (on an old kernel, it will +continue to convert to RGBA8) + +Signed-off-by: Eric Anholt +(cherry picked from commit 7154d76fedf549607afbc0d13db9aaf02da5cebf) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_validate.c | 7 +++++++ + include/uapi/drm/vc4_drm.h | 1 + + 3 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 6c4a4fbc86d0a30a6977b2081bca4372e693b817..157e08ab27771854ffbad101f61ce81e27001e1a 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -78,6 +78,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + pm_runtime_put(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: ++ case DRM_VC4_PARAM_SUPPORTS_ETC1: + args->value = true; + break; + default: +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 26503e307438a34fe526222c8c15be158eb332a2..e18f88203d32f828b7256a05c653586c14095ef3 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -644,6 +644,13 @@ reloc_tex(struct vc4_exec_info *exec, + cpp = 1; + break; + case VC4_TEXTURE_TYPE_ETC1: ++ /* ETC1 is arranged as 64-bit blocks, where each block is 4x4 ++ * pixels. ++ */ ++ cpp = 8; ++ width = (width + 3) >> 2; ++ height = (height + 3) >> 2; ++ break; + case VC4_TEXTURE_TYPE_BW1: + case VC4_TEXTURE_TYPE_A4: + case VC4_TEXTURE_TYPE_A1: +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +index ad7edc3edf7ca1d653a0bc025a5eda6692b74370..69caa21f0cb23c9439238f6239c0041b178d5669 100644 +--- a/include/uapi/drm/vc4_drm.h ++++ b/include/uapi/drm/vc4_drm.h +@@ -286,6 +286,7 @@ struct drm_vc4_get_hang_state { + #define DRM_VC4_PARAM_V3D_IDENT1 1 + #define DRM_VC4_PARAM_V3D_IDENT2 2 + #define DRM_VC4_PARAM_SUPPORTS_BRANCHES 3 ++#define DRM_VC4_PARAM_SUPPORTS_ETC1 4 + + struct drm_vc4_get_param { + __u32 param; + +From a77bc0452ea8328a2bc0a2ddd6ede17db035bfe9 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 4 Nov 2016 15:58:38 -0700 +Subject: [PATCH 160/187] drm/vc4: Use runtime autosuspend to avoid thrashing + V3D power state. + +The pm_runtime_put() we were using immediately released power on the +device, which meant that we were generally turning the device off and +on once per frame. In many profiles I've looked at, that added up to +about 1% of CPU time, but this could get worse in the case of frequent +rendering and readback (as may happen in X rendering). By keeping the +device on until we've been idle for a couple of frames, we drop the +overhead of runtime PM down to sub-.1%. + +Signed-off-by: Eric Anholt +(cherry picked from commit 3a62234680d86efa0239665ed8a0e908f1aef147) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 9 ++++++--- + drivers/gpu/drm/vc4/vc4_gem.c | 6 ++++-- + drivers/gpu/drm/vc4/vc4_v3d.c | 2 ++ + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 157e08ab27771854ffbad101f61ce81e27001e1a..8302bd788be470fd61a7382b8c3ef16e26f6861d 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -61,21 +61,24 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT0); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_V3D_IDENT1: + ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT1); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_V3D_IDENT2: + ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT2); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: + case DRM_VC4_PARAM_SUPPORTS_ETC1: +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 18e37171e9c8e2f0729ca1c582af98ccb4647e06..ab3016982466c3ca35ba479050ee107d26eb50ac 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -711,8 +711,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + } + + mutex_lock(&vc4->power_lock); +- if (--vc4->power_refcount == 0) +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ if (--vc4->power_refcount == 0) { ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); ++ } + mutex_unlock(&vc4->power_lock); + + kfree(exec); +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index e6d3c6028341e447df293cab525713ac10d8ee5e..7cc346ad9b0baed63701d1fae8f0306aa7713129 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -222,6 +222,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + return ret; + } + ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */ + pm_runtime_enable(dev); + + return 0; + +From ebacea179c3f19693c33cf30a304a75fb5fc2689 Mon Sep 17 00:00:00 2001 +From: Jonas Pfeil +Date: Tue, 8 Nov 2016 00:18:39 +0100 +Subject: [PATCH 161/187] drm/vc4: Add fragment shader threading support + +FS threading brings performance improvements of 0-20% in glmark2. + +The validation code checks for thread switch signals and ensures that +the registers of the other thread are not touched, and that our clamps +are not live across thread switches. It also checks that the +threading and branching instructions do not interfere. + +(Original patch by Jonas, changes by anholt for style cleanup, +removing validation the kernel doesn't need to do, and adding the flag +for userspace). + +v2: Minor style fixes from checkpatch. + +Signed-off-by: Jonas Pfeil +Signed-off-by: Eric Anholt +(cherry picked from commit c778cc5df944291dcdb1ca7a6bb781fbc22550c5) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 2 + + drivers/gpu/drm/vc4/vc4_validate.c | 17 +++++--- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 63 ++++++++++++++++++++++++++++++ + include/uapi/drm/vc4_drm.h | 1 + + 5 files changed, 79 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 8302bd788be470fd61a7382b8c3ef16e26f6861d..3abaa0f85da194016c65f46509d4c64f8e2c8de2 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -82,6 +82,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: + case DRM_VC4_PARAM_SUPPORTS_ETC1: ++ case DRM_VC4_PARAM_SUPPORTS_THREADED_FS: + args->value = true; + break; + default: +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index e1f6ab747f36dd412e00a1e7ea772f13c2fc32d5..e15eb37ca6191e0eae3d4947751437d2646c996d 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -384,6 +384,8 @@ struct vc4_validated_shader_info { + + uint32_t num_uniform_addr_offsets; + uint32_t *uniform_addr_offsets; ++ ++ bool is_threaded; + }; + + /** +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index e18f88203d32f828b7256a05c653586c14095ef3..9fd171c361c23b52a4d507919ec7e26fd1e87aac 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -789,11 +789,6 @@ validate_gl_shader_rec(struct drm_device *dev, + exec->shader_rec_v += roundup(packet_size, 16); + exec->shader_rec_size -= packet_size; + +- if (!(*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD)) { +- DRM_ERROR("Multi-threaded fragment shaders not supported.\n"); +- return -EINVAL; +- } +- + for (i = 0; i < shader_reloc_count; i++) { + if (src_handles[i] > exec->bo_count) { + DRM_ERROR("Shader handle %d too big\n", src_handles[i]); +@@ -810,6 +805,18 @@ validate_gl_shader_rec(struct drm_device *dev, + return -EINVAL; + } + ++ if (((*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD) == 0) != ++ to_vc4_bo(&bo[0]->base)->validated_shader->is_threaded) { ++ DRM_ERROR("Thread mode of CL and FS do not match\n"); ++ return -EINVAL; ++ } ++ ++ if (to_vc4_bo(&bo[1]->base)->validated_shader->is_threaded || ++ to_vc4_bo(&bo[2]->base)->validated_shader->is_threaded) { ++ DRM_ERROR("cs and vs cannot be threaded\n"); ++ return -EINVAL; ++ } ++ + for (i = 0; i < shader_reloc_count; i++) { + struct vc4_validated_shader_info *validated_shader; + uint32_t o = shader_reloc_offsets[i]; +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +index 917321ce832ffda9d3e8ca20d987437eea9a1765..5dba13dd1e9b600b43a769d086d6eb428547ab66 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -83,6 +83,13 @@ struct vc4_shader_validation_state { + * basic blocks. + */ + bool needs_uniform_address_for_loop; ++ ++ /* Set when we find an instruction writing the top half of the ++ * register files. If we allowed writing the unusable regs in ++ * a threaded shader, then the other shader running on our ++ * QPU's clamp validation would be invalid. ++ */ ++ bool all_registers_used; + }; + + static uint32_t +@@ -119,6 +126,13 @@ raddr_add_a_to_live_reg_index(uint64_t inst) + } + + static bool ++live_reg_is_upper_half(uint32_t lri) ++{ ++ return (lri >= 16 && lri < 32) || ++ (lri >= 32 + 16 && lri < 32 + 32); ++} ++ ++static bool + is_tmu_submit(uint32_t waddr) + { + return (waddr == QPU_W_TMU0_S || +@@ -390,6 +404,9 @@ check_reg_write(struct vc4_validated_shader_info *validated_shader, + } else { + validation_state->live_immediates[lri] = ~0; + } ++ ++ if (live_reg_is_upper_half(lri)) ++ validation_state->all_registers_used = true; + } + + switch (waddr) { +@@ -598,6 +615,11 @@ check_instruction_reads(struct vc4_validated_shader_info *validated_shader, + } + } + ++ if ((raddr_a >= 16 && raddr_a < 32) || ++ (raddr_b >= 16 && raddr_b < 32 && sig != QPU_SIG_SMALL_IMM)) { ++ validation_state->all_registers_used = true; ++ } ++ + return true; + } + +@@ -753,6 +775,7 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + { + bool found_shader_end = false; + int shader_end_ip = 0; ++ uint32_t last_thread_switch_ip = -3; + uint32_t ip; + struct vc4_validated_shader_info *validated_shader = NULL; + struct vc4_shader_validation_state validation_state; +@@ -785,6 +808,17 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + if (!vc4_handle_branch_target(&validation_state)) + goto fail; + ++ if (ip == last_thread_switch_ip + 3) { ++ /* Reset r0-r3 live clamp data */ ++ int i; ++ ++ for (i = 64; i < LIVE_REG_COUNT; i++) { ++ validation_state.live_min_clamp_offsets[i] = ~0; ++ validation_state.live_max_clamp_regs[i] = false; ++ validation_state.live_immediates[i] = ~0; ++ } ++ } ++ + switch (sig) { + case QPU_SIG_NONE: + case QPU_SIG_WAIT_FOR_SCOREBOARD: +@@ -794,6 +828,8 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + case QPU_SIG_LOAD_TMU1: + case QPU_SIG_PROG_END: + case QPU_SIG_SMALL_IMM: ++ case QPU_SIG_THREAD_SWITCH: ++ case QPU_SIG_LAST_THREAD_SWITCH: + if (!check_instruction_writes(validated_shader, + &validation_state)) { + DRM_ERROR("Bad write at ip %d\n", ip); +@@ -809,6 +845,18 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + shader_end_ip = ip; + } + ++ if (sig == QPU_SIG_THREAD_SWITCH || ++ sig == QPU_SIG_LAST_THREAD_SWITCH) { ++ validated_shader->is_threaded = true; ++ ++ if (ip < last_thread_switch_ip + 3) { ++ DRM_ERROR("Thread switch too soon after " ++ "last switch at ip %d\n", ip); ++ goto fail; ++ } ++ last_thread_switch_ip = ip; ++ } ++ + break; + + case QPU_SIG_LOAD_IMM: +@@ -823,6 +871,13 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + if (!check_branch(inst, validated_shader, + &validation_state, ip)) + goto fail; ++ ++ if (ip < last_thread_switch_ip + 3) { ++ DRM_ERROR("Branch in thread switch at ip %d", ++ ip); ++ goto fail; ++ } ++ + break; + default: + DRM_ERROR("Unsupported QPU signal %d at " +@@ -844,6 +899,14 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + goto fail; + } + ++ /* Might corrupt other thread */ ++ if (validated_shader->is_threaded && ++ validation_state.all_registers_used) { ++ DRM_ERROR("Shader uses threading, but uses the upper " ++ "half of the registers, too\n"); ++ goto fail; ++ } ++ + /* If we did a backwards branch and we haven't emitted a uniforms + * reset since then, we still need the uniforms stream to have the + * uniforms address available so that the backwards branch can do its +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +index 69caa21f0cb23c9439238f6239c0041b178d5669..f07a090167261131076438960c1dec175d7d376e 100644 +--- a/include/uapi/drm/vc4_drm.h ++++ b/include/uapi/drm/vc4_drm.h +@@ -287,6 +287,7 @@ struct drm_vc4_get_hang_state { + #define DRM_VC4_PARAM_V3D_IDENT2 2 + #define DRM_VC4_PARAM_SUPPORTS_BRANCHES 3 + #define DRM_VC4_PARAM_SUPPORTS_ETC1 4 ++#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5 + + struct drm_vc4_get_param { + __u32 param; + +From 19878dd3b492a48437e32a8c5cb908a441e13ef2 Mon Sep 17 00:00:00 2001 +From: Derek Foreman +Date: Thu, 24 Nov 2016 12:11:55 -0600 +Subject: [PATCH 162/187] drm/vc4: Fix race between page flip completion event + and clean-up + +There was a small window where a userspace program could submit +a pageflip after receiving a pageflip completion event yet still +receive EBUSY. + +Signed-off-by: Derek Foreman +Signed-off-by: Eric Anholt +Reviewed-by: Eric Anholt +Reviewed-by: Daniel Stone +(cherry picked from commit 26fc78f6fef39b9d7a15def5e7e9826ff68303f4) +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 8 ++++++++ + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_kms.c | 33 +++++++++++++++++++++++++-------- + 3 files changed, 34 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index 13212788eef0e4b77c1e92e6bf3a56c817c50322..61d64c9c4b0cd1aafc6451b0838cb203c1374a5a 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -682,6 +682,14 @@ void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id) + CRTC_WRITE(PV_INTEN, 0); + } + ++/* Must be called with the event lock held */ ++bool vc4_event_pending(struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ ++ return !!vc4_crtc->event; ++} ++ + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + { + struct drm_crtc *crtc = &vc4_crtc->base; +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index e15eb37ca6191e0eae3d4947751437d2646c996d..47fa2987909642b244615ff6c642adb278bcd784 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -445,6 +445,7 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); + extern struct platform_driver vc4_crtc_driver; + int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); + void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); ++bool vc4_event_pending(struct drm_crtc *crtc); + int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); + int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, + unsigned int flags, int *vpos, int *hpos, +diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c +index c1f65c6c8e601e9331768ca040a5609cad686b2e..67af2af70af091bf4b13ac03eb1078f867bc6cea 100644 +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -119,17 +119,34 @@ static int vc4_atomic_commit(struct drm_device *dev, + + /* Make sure that any outstanding modesets have finished. */ + if (nonblock) { +- ret = down_trylock(&vc4->async_modeset); +- if (ret) { ++ struct drm_crtc *crtc; ++ struct drm_crtc_state *crtc_state; ++ unsigned long flags; ++ bool busy = false; ++ ++ /* ++ * If there's an undispatched event to send then we're ++ * obviously still busy. If there isn't, then we can ++ * unconditionally wait for the semaphore because it ++ * shouldn't be contended (for long). ++ * ++ * This is to prevent a race where queuing a new flip ++ * from userspace immediately on receipt of an event ++ * beats our clean-up and returns EBUSY. ++ */ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ for_each_crtc_in_state(state, crtc, crtc_state, i) ++ busy |= vc4_event_pending(crtc); ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ if (busy) { + kfree(c); + return -EBUSY; + } +- } else { +- ret = down_interruptible(&vc4->async_modeset); +- if (ret) { +- kfree(c); +- return ret; +- } ++ } ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(c); ++ return ret; + } + + ret = drm_atomic_helper_prepare_planes(dev, state); + +From e4b2cf7a156944353c7d08328fe38c1b879d3317 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:07 +0100 +Subject: [PATCH 163/187] drm/vc4: Fix ->clock_select setting for the VEC + encoder + +PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and +rework the vc4_set_crtc_possible_masks() to cover the full range of the +PV_CONTROL_CLK_SELECT field. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit ab8df60e3a3b68420d0d4477c5f07c00fbfb078b) +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++--------------- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_regs.h | 3 ++- + 3 files changed, 26 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index 61d64c9c4b0cd1aafc6451b0838cb203c1374a5a..bdf32c572fc2c46932daca934dfb002d05493883 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -83,8 +83,7 @@ struct vc4_crtc_data { + /* Which channel of the HVS this pixelvalve sources from. */ + int hvs_channel; + +- enum vc4_encoder_type encoder0_type; +- enum vc4_encoder_type encoder1_type; ++ enum vc4_encoder_type encoder_types[4]; + }; + + #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) +@@ -880,20 +879,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { + + static const struct vc4_crtc_data pv0_data = { + .hvs_channel = 0, +- .encoder0_type = VC4_ENCODER_TYPE_DSI0, +- .encoder1_type = VC4_ENCODER_TYPE_DPI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI, ++ }, + }; + + static const struct vc4_crtc_data pv1_data = { + .hvs_channel = 2, +- .encoder0_type = VC4_ENCODER_TYPE_DSI1, +- .encoder1_type = VC4_ENCODER_TYPE_SMI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI, ++ }, + }; + + static const struct vc4_crtc_data pv2_data = { + .hvs_channel = 1, +- .encoder0_type = VC4_ENCODER_TYPE_VEC, +- .encoder1_type = VC4_ENCODER_TYPE_HDMI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, ++ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, ++ }, + }; + + static const struct of_device_id vc4_crtc_dt_match[] = { +@@ -907,17 +912,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, + struct drm_crtc *crtc) + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ const struct vc4_crtc_data *crtc_data = vc4_crtc->data; ++ const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types; + struct drm_encoder *encoder; + + drm_for_each_encoder(encoder, drm) { + struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); +- +- if (vc4_encoder->type == vc4_crtc->data->encoder0_type) { +- vc4_encoder->clock_select = 0; +- encoder->possible_crtcs |= drm_crtc_mask(crtc); +- } else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) { +- vc4_encoder->clock_select = 1; +- encoder->possible_crtcs |= drm_crtc_mask(crtc); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) { ++ if (vc4_encoder->type == encoder_types[i]) { ++ vc4_encoder->clock_select = i; ++ encoder->possible_crtcs |= drm_crtc_mask(crtc); ++ break; ++ } + } + } + } +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 47fa2987909642b244615ff6c642adb278bcd784..6d0688056aa2c75cc6b5bf9a6c50cc62e1b398e2 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -197,6 +197,7 @@ to_vc4_plane(struct drm_plane *plane) + } + + enum vc4_encoder_type { ++ VC4_ENCODER_TYPE_NONE, + VC4_ENCODER_TYPE_HDMI, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI0, +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 1aa44c2db5565ba126d2ceb65495a6c98c555860..39f6886b24100c43b590e47e0c7bc44846721d65 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -177,8 +177,9 @@ + # define PV_CONTROL_WAIT_HSTART BIT(12) + # define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4) + # define PV_CONTROL_PIXEL_REP_SHIFT 4 +-# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 ++# define PV_CONTROL_CLK_SELECT_DSI 0 + # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 ++# define PV_CONTROL_CLK_SELECT_VEC 2 + # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) + # define PV_CONTROL_CLK_SELECT_SHIFT 2 + # define PV_CONTROL_FIFO_CLR BIT(1) + +From c5802ef9279c71a69d2e07d537b7d9fbc8e05cd6 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:09 +0100 +Subject: [PATCH 164/187] drm: Add TV connector states to drm_connector_state + +Some generic TV connector properties are exposed in drm_mode_config, but +they are currently handled independently in each DRM encoder driver. + +Extend the drm_connector_state to store TV related states, and modify the +drm_atomic_connector_{set,get}_property() helpers to fill the connector +state accordingly. + +Each driver is then responsible for checking and applying the new config +in its ->atomic_mode_{check,set}() operations. + +Signed-off-by: Boris Brezillon +Reviewed-by: Daniel Vetter +Signed-off-by: Eric Anholt +(cherry picked from commit 299a16b163c95fbe1e3b1e142ba9c6ce9dab2c23) +--- + drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ + include/drm/drm_connector.h | 32 ++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c +index 4e19bde4bbffac08e700460b69db882f42d5463b..846da4f6416435221cb8d08a8c124f05852e93ca 100644 +--- a/drivers/gpu/drm/drm_atomic.c ++++ b/drivers/gpu/drm/drm_atomic.c +@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, + * now?) atomic writes to DPMS property: + */ + return -EINVAL; ++ } else if (property == config->tv_select_subconnector_property) { ++ state->tv.subconnector = val; ++ } else if (property == config->tv_left_margin_property) { ++ state->tv.margins.left = val; ++ } else if (property == config->tv_right_margin_property) { ++ state->tv.margins.right = val; ++ } else if (property == config->tv_top_margin_property) { ++ state->tv.margins.top = val; ++ } else if (property == config->tv_bottom_margin_property) { ++ state->tv.margins.bottom = val; ++ } else if (property == config->tv_mode_property) { ++ state->tv.mode = val; ++ } else if (property == config->tv_brightness_property) { ++ state->tv.brightness = val; ++ } else if (property == config->tv_contrast_property) { ++ state->tv.contrast = val; ++ } else if (property == config->tv_flicker_reduction_property) { ++ state->tv.flicker_reduction = val; ++ } else if (property == config->tv_overscan_property) { ++ state->tv.overscan = val; ++ } else if (property == config->tv_saturation_property) { ++ state->tv.saturation = val; ++ } else if (property == config->tv_hue_property) { ++ state->tv.hue = val; + } else if (connector->funcs->atomic_set_property) { + return connector->funcs->atomic_set_property(connector, + state, property, val); + } else { + return -EINVAL; + } ++ ++ return 0; + } + EXPORT_SYMBOL(drm_atomic_connector_set_property); + +@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector, + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->dpms_property) { + *val = connector->dpms; ++ } else if (property == config->tv_select_subconnector_property) { ++ *val = state->tv.subconnector; ++ } else if (property == config->tv_left_margin_property) { ++ *val = state->tv.margins.left; ++ } else if (property == config->tv_right_margin_property) { ++ *val = state->tv.margins.right; ++ } else if (property == config->tv_top_margin_property) { ++ *val = state->tv.margins.top; ++ } else if (property == config->tv_bottom_margin_property) { ++ *val = state->tv.margins.bottom; ++ } else if (property == config->tv_mode_property) { ++ *val = state->tv.mode; ++ } else if (property == config->tv_brightness_property) { ++ *val = state->tv.brightness; ++ } else if (property == config->tv_contrast_property) { ++ *val = state->tv.contrast; ++ } else if (property == config->tv_flicker_reduction_property) { ++ *val = state->tv.flicker_reduction; ++ } else if (property == config->tv_overscan_property) { ++ *val = state->tv.overscan; ++ } else if (property == config->tv_saturation_property) { ++ *val = state->tv.saturation; ++ } else if (property == config->tv_hue_property) { ++ *val = state->tv.hue; + } else if (connector->funcs->atomic_get_property) { + return connector->funcs->atomic_get_property(connector, + state, property, val); +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index ac9d7d8e0e43a807e9fc9a0b66de5f26b49d3348..2645e803857253ff98eb94aa1bacc8257f37ae76 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, + unsigned int num_formats); + + /** ++ * struct drm_tv_connector_state - TV connector related states ++ * @subconnector: selected subconnector ++ * @margins: left/right/top/bottom margins ++ * @mode: TV mode ++ * @brightness: brightness in percent ++ * @contrast: contrast in percent ++ * @flicker_reduction: flicker reduction in percent ++ * @overscan: overscan in percent ++ * @saturation: saturation in percent ++ * @hue: hue in percent ++ */ ++struct drm_tv_connector_state { ++ enum drm_mode_subconnector subconnector; ++ struct { ++ unsigned int left; ++ unsigned int right; ++ unsigned int top; ++ unsigned int bottom; ++ } margins; ++ unsigned int mode; ++ unsigned int brightness; ++ unsigned int contrast; ++ unsigned int flicker_reduction; ++ unsigned int overscan; ++ unsigned int saturation; ++ unsigned int hue; ++}; ++ ++/** + * struct drm_connector_state - mutable connector state + * @connector: backpointer to the connector + * @best_encoder: can be used by helpers and drivers to select the encoder + * @state: backpointer to global drm_atomic_state ++ * @tv: TV connector state + */ + struct drm_connector_state { + struct drm_connector *connector; +@@ -213,6 +243,8 @@ struct drm_connector_state { + struct drm_encoder *best_encoder; + + struct drm_atomic_state *state; ++ ++ struct drm_tv_connector_state tv; + }; + + /** + +From 30f28713c9444d1f2737718a3921f2bd1409e2b1 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:08 +0100 +Subject: [PATCH 165/187] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into + an enum + +List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better +represented with enums. + +Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum. + +Signed-off-by: Boris Brezillon +Suggested-by: Daniel Vetter +Reviewed-by: Daniel Vetter +Signed-off-by: Eric Anholt +(cherry picked from commit dee7a4fee730ca8908f335b6b66174cba4598ecd) +--- + include/uapi/drm/drm_mode.h | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h +index df0e3504c349a950bf41540fbcd6cd944cf11d2f..970bfc0d7107451e5bc4e29c524a764cbd10b39b 100644 +--- a/include/uapi/drm/drm_mode.h ++++ b/include/uapi/drm/drm_mode.h +@@ -220,14 +220,16 @@ struct drm_mode_get_encoder { + + /* This is for connectors with multiple signal types. */ + /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +-#define DRM_MODE_SUBCONNECTOR_Automatic 0 +-#define DRM_MODE_SUBCONNECTOR_Unknown 0 +-#define DRM_MODE_SUBCONNECTOR_DVID 3 +-#define DRM_MODE_SUBCONNECTOR_DVIA 4 +-#define DRM_MODE_SUBCONNECTOR_Composite 5 +-#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +-#define DRM_MODE_SUBCONNECTOR_Component 8 +-#define DRM_MODE_SUBCONNECTOR_SCART 9 ++enum drm_mode_subconnector { ++ DRM_MODE_SUBCONNECTOR_Automatic = 0, ++ DRM_MODE_SUBCONNECTOR_Unknown = 0, ++ DRM_MODE_SUBCONNECTOR_DVID = 3, ++ DRM_MODE_SUBCONNECTOR_DVIA = 4, ++ DRM_MODE_SUBCONNECTOR_Composite = 5, ++ DRM_MODE_SUBCONNECTOR_SVIDEO = 6, ++ DRM_MODE_SUBCONNECTOR_Component = 8, ++ DRM_MODE_SUBCONNECTOR_SCART = 9, ++}; + + #define DRM_MODE_CONNECTOR_Unknown 0 + #define DRM_MODE_CONNECTOR_VGA 1 + +From 9231fe3ff1b89ea5a3dce92b657ef9f6e8f064cc Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:10 +0100 +Subject: [PATCH 166/187] drm/vc4: Add support for the VEC (Video Encoder) IP + +The VEC IP is a TV DAC, providing support for PAL and NTSC standards. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit e4b81f8c74c82dbc0cb0e5ceb5ef9b713b325fc9) +--- + drivers/gpu/drm/vc4/Makefile | 1 + + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 5 + + drivers/gpu/drm/vc4/vc4_vec.c | 657 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 665 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c + +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +index c6dd06cca9830018c39b3b16afe4045e44d1ddf4..3358ec8775cf6e8738ea8cdb2246dad57bd29139 100644 +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -12,6 +12,7 @@ vc4-y := \ + vc4_kms.o \ + vc4_gem.o \ + vc4_hdmi.o \ ++ vc4_vec.o \ + vc4_hvs.o \ + vc4_irq.o \ + vc4_plane.o \ +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index 245115d49c46a1244ef3e460a03fde397f763de8..caf817bac8852c82f0d6a34b676a649c10e6e6cd 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, + {"dpi_regs", vc4_dpi_debugfs_regs, 0}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, ++ {"vec_regs", vc4_vec_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, + {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, + {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 3abaa0f85da194016c65f46509d4c64f8e2c8de2..281609353063435f9da33f81bdc09dbc3ebc89e9 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -294,6 +294,7 @@ static const struct component_master_ops vc4_drm_ops = { + + static struct platform_driver *const component_drivers[] = { + &vc4_hdmi_driver, ++ &vc4_vec_driver, + &vc4_dpi_driver, + &vc4_hvs_driver, + &vc4_crtc_driver, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 6d0688056aa2c75cc6b5bf9a6c50cc62e1b398e2..61a9b3e81823a3c96f36f710329844cc032e2628 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -20,6 +20,7 @@ struct vc4_dev { + struct vc4_crtc *crtc[3]; + struct vc4_v3d *v3d; + struct vc4_dpi *dpi; ++ struct vc4_vec *vec; + + struct drm_fbdev_cma *fbdev; + +@@ -494,6 +495,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev, + extern struct platform_driver vc4_hdmi_driver; + int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused); + ++/* vc4_hdmi.c */ ++extern struct platform_driver vc4_vec_driver; ++int vc4_vec_debugfs_regs(struct seq_file *m, void *unused); ++ + /* vc4_irq.c */ + irqreturn_t vc4_irq(int irq, void *arg); + void vc4_irq_preinstall(struct drm_device *dev); +diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c +new file mode 100644 +index 0000000000000000000000000000000000000000..32bb8ef985fbc6f39f9e5f459846bb779b80c9e8 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_vec.c +@@ -0,0 +1,657 @@ ++/* ++ * Copyright (C) 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++/** ++ * DOC: VC4 SDTV module ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++/* WSE Registers */ ++#define VEC_WSE_RESET 0xc0 ++ ++#define VEC_WSE_CONTROL 0xc4 ++#define VEC_WSE_WSS_ENABLE BIT(7) ++ ++#define VEC_WSE_WSS_DATA 0xc8 ++#define VEC_WSE_VPS_DATA1 0xcc ++#define VEC_WSE_VPS_CONTROL 0xd0 ++ ++/* VEC Registers */ ++#define VEC_REVID 0x100 ++ ++#define VEC_CONFIG0 0x104 ++#define VEC_CONFIG0_YDEL_MASK GENMASK(28, 26) ++#define VEC_CONFIG0_YDEL(x) ((x) << 26) ++#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24) ++#define VEC_CONFIG0_CDEL(x) ((x) << 24) ++#define VEC_CONFIG0_PBPR_FIL BIT(18) ++#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16) ++#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_32 (1 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_16 (2 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_8 (3 << 16) ++#define VEC_CONFIG0_CBURST_GAIN_MASK GENMASK(14, 13) ++#define VEC_CONFIG0_CBURST_GAIN_UNITY (0 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_128 (1 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_64 (2 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_32 (3 << 13) ++#define VEC_CONFIG0_CHRBW1 BIT(11) ++#define VEC_CONFIG0_CHRBW0 BIT(10) ++#define VEC_CONFIG0_SYNCDIS BIT(9) ++#define VEC_CONFIG0_BURDIS BIT(8) ++#define VEC_CONFIG0_CHRDIS BIT(7) ++#define VEC_CONFIG0_PDEN BIT(6) ++#define VEC_CONFIG0_YCDELAY BIT(4) ++#define VEC_CONFIG0_RAMPEN BIT(2) ++#define VEC_CONFIG0_YCDIS BIT(2) ++#define VEC_CONFIG0_STD_MASK GENMASK(1, 0) ++#define VEC_CONFIG0_NTSC_STD 0 ++#define VEC_CONFIG0_PAL_BDGHI_STD 1 ++#define VEC_CONFIG0_PAL_N_STD 3 ++ ++#define VEC_SCHPH 0x108 ++#define VEC_SOFT_RESET 0x10c ++#define VEC_CLMP0_START 0x144 ++#define VEC_CLMP0_END 0x148 ++#define VEC_FREQ3_2 0x180 ++#define VEC_FREQ1_0 0x184 ++ ++#define VEC_CONFIG1 0x188 ++#define VEC_CONFIG_VEC_RESYNC_OFF BIT(18) ++#define VEC_CONFIG_RGB219 BIT(17) ++#define VEC_CONFIG_CBAR_EN BIT(16) ++#define VEC_CONFIG_TC_OBB BIT(15) ++#define VEC_CONFIG1_OUTPUT_MODE_MASK GENMASK(12, 10) ++#define VEC_CONFIG1_C_Y_CVBS (0 << 10) ++#define VEC_CONFIG1_CVBS_Y_C (1 << 10) ++#define VEC_CONFIG1_PR_Y_PB (2 << 10) ++#define VEC_CONFIG1_RGB (4 << 10) ++#define VEC_CONFIG1_Y_C_CVBS (5 << 10) ++#define VEC_CONFIG1_C_CVBS_Y (6 << 10) ++#define VEC_CONFIG1_C_CVBS_CVBS (7 << 10) ++#define VEC_CONFIG1_DIS_CHR BIT(9) ++#define VEC_CONFIG1_DIS_LUMA BIT(8) ++#define VEC_CONFIG1_YCBCR_IN BIT(6) ++#define VEC_CONFIG1_DITHER_TYPE_LFSR 0 ++#define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5) ++#define VEC_CONFIG1_DITHER_EN BIT(4) ++#define VEC_CONFIG1_CYDELAY BIT(3) ++#define VEC_CONFIG1_LUMADIS BIT(2) ++#define VEC_CONFIG1_COMPDIS BIT(1) ++#define VEC_CONFIG1_CUSTOM_FREQ BIT(0) ++ ++#define VEC_CONFIG2 0x18c ++#define VEC_CONFIG2_PROG_SCAN BIT(15) ++#define VEC_CONFIG2_SYNC_ADJ_MASK GENMASK(14, 12) ++#define VEC_CONFIG2_SYNC_ADJ(x) (((x) / 2) << 12) ++#define VEC_CONFIG2_PBPR_EN BIT(10) ++#define VEC_CONFIG2_UV_DIG_DIS BIT(6) ++#define VEC_CONFIG2_RGB_DIG_DIS BIT(5) ++#define VEC_CONFIG2_TMUX_MASK GENMASK(3, 2) ++#define VEC_CONFIG2_TMUX_DRIVE0 (0 << 2) ++#define VEC_CONFIG2_TMUX_RG_COMP (1 << 2) ++#define VEC_CONFIG2_TMUX_UV_YC (2 << 2) ++#define VEC_CONFIG2_TMUX_SYNC_YC (3 << 2) ++ ++#define VEC_INTERRUPT_CONTROL 0x190 ++#define VEC_INTERRUPT_STATUS 0x194 ++#define VEC_FCW_SECAM_B 0x198 ++#define VEC_SECAM_GAIN_VAL 0x19c ++ ++#define VEC_CONFIG3 0x1a0 ++#define VEC_CONFIG3_HORIZ_LEN_STD (0 << 0) ++#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0) ++#define VEC_CONFIG3_SHAPE_NON_LINEAR BIT(1) ++ ++#define VEC_STATUS0 0x200 ++#define VEC_MASK0 0x204 ++ ++#define VEC_CFG 0x208 ++#define VEC_CFG_SG_MODE_MASK GENMASK(6, 5) ++#define VEC_CFG_SG_MODE(x) ((x) << 5) ++#define VEC_CFG_SG_EN BIT(4) ++#define VEC_CFG_VEC_EN BIT(3) ++#define VEC_CFG_MB_EN BIT(2) ++#define VEC_CFG_ENABLE BIT(1) ++#define VEC_CFG_TB_EN BIT(0) ++ ++#define VEC_DAC_TEST 0x20c ++ ++#define VEC_DAC_CONFIG 0x210 ++#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24) ++#define VEC_DAC_CONFIG_DRIVER_CTRL(x) ((x) << 16) ++#define VEC_DAC_CONFIG_DAC_CTRL(x) (x) ++ ++#define VEC_DAC_MISC 0x214 ++#define VEC_DAC_MISC_VCD_CTRL_MASK GENMASK(31, 16) ++#define VEC_DAC_MISC_VCD_CTRL(x) ((x) << 16) ++#define VEC_DAC_MISC_VID_ACT BIT(8) ++#define VEC_DAC_MISC_VCD_PWRDN BIT(6) ++#define VEC_DAC_MISC_BIAS_PWRDN BIT(5) ++#define VEC_DAC_MISC_DAC_PWRDN BIT(2) ++#define VEC_DAC_MISC_LDO_PWRDN BIT(1) ++#define VEC_DAC_MISC_DAC_RST_N BIT(0) ++ ++ ++/* General VEC hardware state. */ ++struct vc4_vec { ++ struct platform_device *pdev; ++ ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ ++ void __iomem *regs; ++ ++ struct clk *clock; ++ ++ const struct vc4_vec_tv_mode *tv_mode; ++}; ++ ++#define VEC_READ(offset) readl(vec->regs + (offset)) ++#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset)) ++ ++/* VC4 VEC encoder KMS struct */ ++struct vc4_vec_encoder { ++ struct vc4_encoder base; ++ struct vc4_vec *vec; ++}; ++ ++static inline struct vc4_vec_encoder * ++to_vc4_vec_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_vec_encoder, base.base); ++} ++ ++/* VC4 VEC connector KMS struct */ ++struct vc4_vec_connector { ++ struct drm_connector base; ++ struct vc4_vec *vec; ++ ++ /* Since the connector is attached to just the one encoder, ++ * this is the reference to it so we can do the best_encoder() ++ * hook. ++ */ ++ struct drm_encoder *encoder; ++}; ++ ++static inline struct vc4_vec_connector * ++to_vc4_vec_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_vec_connector, base); ++} ++ ++enum vc4_vec_tv_mode_id { ++ VC4_VEC_TV_MODE_NTSC, ++ VC4_VEC_TV_MODE_NTSC_J, ++ VC4_VEC_TV_MODE_PAL, ++ VC4_VEC_TV_MODE_PAL_M, ++}; ++ ++struct vc4_vec_tv_mode { ++ const struct drm_display_mode *mode; ++ void (*mode_set)(struct vc4_vec *vec); ++}; ++ ++#define VEC_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} vec_regs[] = { ++ VEC_REG(VEC_WSE_CONTROL), ++ VEC_REG(VEC_WSE_WSS_DATA), ++ VEC_REG(VEC_WSE_VPS_DATA1), ++ VEC_REG(VEC_WSE_VPS_CONTROL), ++ VEC_REG(VEC_REVID), ++ VEC_REG(VEC_CONFIG0), ++ VEC_REG(VEC_SCHPH), ++ VEC_REG(VEC_CLMP0_START), ++ VEC_REG(VEC_CLMP0_END), ++ VEC_REG(VEC_FREQ3_2), ++ VEC_REG(VEC_FREQ1_0), ++ VEC_REG(VEC_CONFIG1), ++ VEC_REG(VEC_CONFIG2), ++ VEC_REG(VEC_INTERRUPT_CONTROL), ++ VEC_REG(VEC_INTERRUPT_STATUS), ++ VEC_REG(VEC_FCW_SECAM_B), ++ VEC_REG(VEC_SECAM_GAIN_VAL), ++ VEC_REG(VEC_CONFIG3), ++ VEC_REG(VEC_STATUS0), ++ VEC_REG(VEC_MASK0), ++ VEC_REG(VEC_CFG), ++ VEC_REG(VEC_DAC_TEST), ++ VEC_REG(VEC_DAC_CONFIG), ++ VEC_REG(VEC_DAC_MISC), ++}; ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_vec_debugfs_regs(struct seq_file *m, void *unused) ++{ ++ struct drm_info_node *node = (struct drm_info_node *)m->private; ++ struct drm_device *dev = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_vec *vec = vc4->vec; ++ int i; ++ ++ if (!vec) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(vec_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ vec_regs[i].name, vec_regs[i].reg, ++ VEC_READ(vec_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static const struct drm_display_mode ntsc_mode = { ++ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, ++ 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0, ++ DRM_MODE_FLAG_INTERLACE) ++}; ++ ++static void vc4_vec_pal_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); ++ VEC_WRITE(VEC_CONFIG1, ++ VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ); ++ VEC_WRITE(VEC_FREQ3_2, 0x223b); ++ VEC_WRITE(VEC_FREQ1_0, 0x61d1); ++} ++ ++static const struct drm_display_mode pal_mode = { ++ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, ++ 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0, ++ DRM_MODE_FLAG_INTERLACE) ++}; ++ ++static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { ++ [VC4_VEC_TV_MODE_NTSC] = { ++ .mode = &ntsc_mode, ++ .mode_set = vc4_vec_ntsc_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_NTSC_J] = { ++ .mode = &ntsc_mode, ++ .mode_set = vc4_vec_ntsc_j_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_PAL] = { ++ .mode = &pal_mode, ++ .mode_set = vc4_vec_pal_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_PAL_M] = { ++ .mode = &pal_mode, ++ .mode_set = vc4_vec_pal_m_mode_set, ++ }, ++}; ++ ++static enum drm_connector_status ++vc4_vec_connector_detect(struct drm_connector *connector, bool force) ++{ ++ return connector_status_unknown; ++} ++ ++static void vc4_vec_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_vec_connector_get_modes(struct drm_connector *connector) ++{ ++ struct drm_connector_state *state = connector->state; ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, ++ vc4_vec_tv_modes[state->tv.mode].mode); ++ if (!mode) { ++ DRM_ERROR("Failed to create a new display mode\n"); ++ return -ENOMEM; ++ } ++ ++ drm_mode_probed_add(connector, mode); ++ ++ return 1; ++} ++ ++static const struct drm_connector_funcs vc4_vec_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_vec_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .set_property = drm_atomic_helper_connector_set_property, ++ .destroy = vc4_vec_connector_destroy, ++ .reset = drm_atomic_helper_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = { ++ .get_modes = vc4_vec_connector_get_modes, ++}; ++ ++static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, ++ struct vc4_vec *vec) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_vec_connector *vec_connector; ++ ++ vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector), ++ GFP_KERNEL); ++ if (!vec_connector) ++ return ERR_PTR(-ENOMEM); ++ ++ connector = &vec_connector->base; ++ connector->interlace_allowed = true; ++ ++ vec_connector->encoder = vec->encoder; ++ vec_connector->vec = vec; ++ ++ drm_connector_init(dev, connector, &vc4_vec_connector_funcs, ++ DRM_MODE_CONNECTOR_Composite); ++ drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs); ++ ++ drm_object_attach_property(&connector->base, ++ dev->mode_config.tv_mode_property, ++ VC4_VEC_TV_MODE_NTSC); ++ vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC]; ++ ++ drm_mode_connector_attach_encoder(connector, vec->encoder); ++ ++ return connector; ++} ++ ++static const struct drm_encoder_funcs vc4_vec_encoder_funcs = { ++ .destroy = drm_encoder_cleanup, ++}; ++ ++static void vc4_vec_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ int ret; ++ ++ VEC_WRITE(VEC_CFG, 0); ++ VEC_WRITE(VEC_DAC_MISC, ++ VEC_DAC_MISC_VCD_PWRDN | ++ VEC_DAC_MISC_BIAS_PWRDN | ++ VEC_DAC_MISC_DAC_PWRDN | ++ VEC_DAC_MISC_LDO_PWRDN); ++ ++ clk_disable_unprepare(vec->clock); ++ ++ ret = pm_runtime_put(&vec->pdev->dev); ++ if (ret < 0) { ++ DRM_ERROR("Failed to release power domain: %d\n", ret); ++ return; ++ } ++} ++ ++static void vc4_vec_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ int ret; ++ ++ ret = pm_runtime_get_sync(&vec->pdev->dev); ++ if (ret < 0) { ++ DRM_ERROR("Failed to retain power domain: %d\n", ret); ++ return; ++ } ++ ++ /* ++ * We need to set the clock rate each time we enable the encoder ++ * because there's a chance we share the same parent with the HDMI ++ * clock, and both drivers are requesting different rates. ++ * The good news is, these 2 encoders cannot be enabled at the same ++ * time, thus preventing incompatible rate requests. ++ */ ++ ret = clk_set_rate(vec->clock, 108000000); ++ if (ret) { ++ DRM_ERROR("Failed to set clock rate: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(vec->clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on core clock: %d\n", ret); ++ return; ++ } ++ ++ /* Reset the different blocks */ ++ VEC_WRITE(VEC_WSE_RESET, 1); ++ VEC_WRITE(VEC_SOFT_RESET, 1); ++ ++ /* Disable the CGSM-A and WSE blocks */ ++ VEC_WRITE(VEC_WSE_CONTROL, 0); ++ ++ /* Write config common to all modes. */ ++ ++ /* ++ * Color subcarrier phase: phase = 360 * SCHPH / 256. ++ * 0x28 <=> 39.375 deg. ++ */ ++ VEC_WRITE(VEC_SCHPH, 0x28); ++ ++ /* ++ * Reset to default values. ++ */ ++ VEC_WRITE(VEC_CLMP0_START, 0xac); ++ VEC_WRITE(VEC_CLMP0_END, 0xec); ++ VEC_WRITE(VEC_CONFIG2, ++ VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); ++ VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD); ++ VEC_WRITE(VEC_DAC_CONFIG, ++ VEC_DAC_CONFIG_DAC_CTRL(0xc) | ++ VEC_DAC_CONFIG_DRIVER_CTRL(0xc) | ++ VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46)); ++ ++ /* Mask all interrupts. */ ++ VEC_WRITE(VEC_MASK0, 0); ++ ++ vec->tv_mode->mode_set(vec); ++ ++ VEC_WRITE(VEC_DAC_MISC, ++ VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N); ++ VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN); ++} ++ ++ ++static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder, ++ const struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ ++ vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode]; ++} ++ ++static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ const struct vc4_vec_tv_mode *vec_mode; ++ ++ vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode]; ++ ++ if (conn_state->crtc && ++ !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = { ++ .disable = vc4_vec_encoder_disable, ++ .enable = vc4_vec_encoder_enable, ++ .mode_fixup = vc4_vec_encoder_mode_fixup, ++ .atomic_check = vc4_vec_encoder_atomic_check, ++ .atomic_mode_set = vc4_vec_encoder_atomic_mode_set, ++}; ++ ++static const struct of_device_id vc4_vec_dt_match[] = { ++ { .compatible = "brcm,bcm2835-vec", .data = NULL }, ++ { /* sentinel */ }, ++}; ++ ++static const char * const tv_mode_names[] = { ++ [VC4_VEC_TV_MODE_NTSC] = "NTSC", ++ [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J", ++ [VC4_VEC_TV_MODE_PAL] = "PAL", ++ [VC4_VEC_TV_MODE_PAL_M] = "PAL-M", ++}; ++ ++static int vc4_vec_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_vec *vec; ++ struct vc4_vec_encoder *vc4_vec_encoder; ++ int ret; ++ ++ ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names), ++ tv_mode_names); ++ if (ret) ++ return ret; ++ ++ vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL); ++ if (!vec) ++ return -ENOMEM; ++ ++ vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder), ++ GFP_KERNEL); ++ if (!vc4_vec_encoder) ++ return -ENOMEM; ++ vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC; ++ vc4_vec_encoder->vec = vec; ++ vec->encoder = &vc4_vec_encoder->base.base; ++ ++ vec->pdev = pdev; ++ vec->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(vec->regs)) ++ return PTR_ERR(vec->regs); ++ ++ vec->clock = devm_clk_get(dev, NULL); ++ if (IS_ERR(vec->clock)) { ++ ret = PTR_ERR(vec->clock); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Failed to get clock: %d\n", ret); ++ return ret; ++ } ++ ++ pm_runtime_enable(dev); ++ ++ drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs, ++ DRM_MODE_ENCODER_TVDAC, NULL); ++ drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs); ++ ++ vec->connector = vc4_vec_connector_init(drm, vec); ++ if (IS_ERR(vec->connector)) { ++ ret = PTR_ERR(vec->connector); ++ goto err_destroy_encoder; ++ } ++ ++ dev_set_drvdata(dev, vec); ++ ++ vc4->vec = vec; ++ ++ return 0; ++ ++err_destroy_encoder: ++ drm_encoder_cleanup(vec->encoder); ++ pm_runtime_disable(dev); ++ ++ return ret; ++} ++ ++static void vc4_vec_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_vec *vec = dev_get_drvdata(dev); ++ ++ vc4_vec_connector_destroy(vec->connector); ++ drm_encoder_cleanup(vec->encoder); ++ pm_runtime_disable(dev); ++ ++ vc4->vec = NULL; ++} ++ ++static const struct component_ops vc4_vec_ops = { ++ .bind = vc4_vec_bind, ++ .unbind = vc4_vec_unbind, ++}; ++ ++static int vc4_vec_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_vec_ops); ++} ++ ++static int vc4_vec_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_vec_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_vec_driver = { ++ .probe = vc4_vec_dev_probe, ++ .remove = vc4_vec_dev_remove, ++ .driver = { ++ .name = "vc4_vec", ++ .of_match_table = vc4_vec_dt_match, ++ }, ++}; + +From 5452c0c33ec0cf1a54fc06ae1cee9ec796755abc Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 15 Sep 2016 15:25:23 +0100 +Subject: [PATCH 167/187] drm/vc4: Set up SCALER_DISPCTRL at boot. + +We want the HVS on, obviously, and we also want DSP3 (PV1's source) to +be muxed from HVS channel 2 like we expect in vc4_crtc.c. The +firmware wasn't setting the DSP3 mux up when both the LCD and HDMI +were disabled. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++++++++ + drivers/gpu/drm/vc4/vc4_regs.h | 3 +++ + 2 files changed, 17 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c +index 6fbab1c82cb1089bde0834f3e0bf1fdf99f54221..fc68b1b4da5249ce3181d7eabb0a08bf8e4908cf 100644 +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -170,6 +170,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hvs *hvs = NULL; + int ret; ++ u32 dispctrl; + + hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); + if (!hvs) +@@ -211,6 +212,19 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + return ret; + + vc4->hvs = hvs; ++ ++ dispctrl = HVS_READ(SCALER_DISPCTRL); ++ ++ dispctrl |= SCALER_DISPCTRL_ENABLE; ++ ++ /* Set DSP3 (PV1) to use HVS channel 2, which would otherwise ++ * be unused. ++ */ ++ dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK; ++ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl); ++ + return 0; + } + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 39f6886b24100c43b590e47e0c7bc44846721d65..b3b297fba7097bc495fa8916292c547925720199 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -244,6 +244,9 @@ + # define SCALER_DISPCTRL_ENABLE BIT(31) + # define SCALER_DISPCTRL_DSP2EISLUR BIT(15) + # define SCALER_DISPCTRL_DSP1EISLUR BIT(14) ++# define SCALER_DISPCTRL_DSP3_MUX_MASK VC4_MASK(19, 18) ++# define SCALER_DISPCTRL_DSP3_MUX_SHIFT 18 ++ + /* Enables Display 0 short line and underrun contribution to + * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are + * always enabled. + +From 9d2402dc77e1f6e54af937611ddefb06b1abcaeb Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 10 Feb 2016 16:17:29 -0800 +Subject: [PATCH 168/187] drm/vc4: Add support for feeding DSI encoders from + the pixel valve. + +We have to set a different pixel format, which tells the hardware to +use the pix_width field that's fed in sideband from the DSI encoder to +divide the "pixel" clock. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 33 +++++++++++++++++++-------------- + drivers/gpu/drm/vc4/vc4_regs.h | 2 ++ + 2 files changed, 21 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index bdf32c572fc2c46932daca934dfb002d05493883..0a861158740586836d2d47cccae4109ad4ec968d 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -352,38 +352,40 @@ static u32 vc4_get_fifo_full_level(u32 format) + } + + /* +- * Returns the clock select bit for the connector attached to the +- * CRTC. ++ * Returns the encoder attached to the CRTC. ++ * ++ * VC4 can only scan out to one encoder at a time, while the DRM core ++ * allows drivers to push pixels to more than one encoder from the ++ * same CRTC. + */ +-static int vc4_get_clock_select(struct drm_crtc *crtc) ++static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc) + { + struct drm_connector *connector; + + drm_for_each_connector(connector, crtc->dev) { + if (connector->state->crtc == crtc) { +- struct drm_encoder *encoder = connector->encoder; +- struct vc4_encoder *vc4_encoder = +- to_vc4_encoder(encoder); +- +- return vc4_encoder->clock_select; ++ return connector->encoder; + } + } + +- return -1; ++ return NULL; + } + + static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + { + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc); ++ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_crtc_state *state = crtc->state; + struct drm_display_mode *mode = &state->adjusted_mode; + bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; + u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; +- u32 format = PV_CONTROL_FORMAT_24; ++ bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || ++ vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); ++ u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; + bool debug_dump_regs = false; +- int clock_select = vc4_get_clock_select(crtc); + + if (debug_dump_regs) { + DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); +@@ -439,17 +441,19 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (is_dsi ? PV_VCONTROL_DSI : 0) | + PV_VCONTROL_INTERLACE | + VC4_SET_FIELD(mode->htotal * pixel_rep / 2, + PV_VCONTROL_ODD_DELAY)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } else { +- CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS); ++ CRTC_WRITE(PV_V_CONTROL, ++ PV_VCONTROL_CONTINUOUS | ++ (is_dsi ? PV_VCONTROL_DSI : 0)); + } + + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + +- + CRTC_WRITE(PV_CONTROL, + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | + VC4_SET_FIELD(vc4_get_fifo_full_level(format), +@@ -458,7 +462,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + PV_CONTROL_CLR_AT_START | + PV_CONTROL_TRIGGER_UNDERFLOW | + PV_CONTROL_WAIT_HSTART | +- VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | ++ VC4_SET_FIELD(vc4_encoder->clock_select, ++ PV_CONTROL_CLK_SELECT) | + PV_CONTROL_FIFO_CLR | + PV_CONTROL_EN); + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index b3b297fba7097bc495fa8916292c547925720199..385405a2df05eb3dd86d4f687aa8205331bec3cc 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -190,6 +190,8 @@ + # define PV_VCONTROL_ODD_DELAY_SHIFT 6 + # define PV_VCONTROL_ODD_FIRST BIT(5) + # define PV_VCONTROL_INTERLACE BIT(4) ++# define PV_VCONTROL_DSI BIT(3) ++# define PV_VCONTROL_COMMAND BIT(2) + # define PV_VCONTROL_CONTINUOUS BIT(1) + # define PV_VCONTROL_VIDEN BIT(0) + + +From 959631c073334693d310cef939854fa6dea82cd0 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 10 Feb 2016 11:42:32 -0800 +Subject: [PATCH 169/187] drm/vc4: Add DSI driver + +The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. +Some registers move around, and the featureset is slightly different, +as DSI1 (the 4-lane DSI) is a later version of the hardware block. +This driver doesn't yet enable DSI0, since we don't have any hardware +to test against, but it does put a lot of the register definitions and +code in place. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/Kconfig | 2 + + drivers/gpu/drm/vc4/Makefile | 1 + + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 5 + + drivers/gpu/drm/vc4/vc4_dsi.c | 1725 +++++++++++++++++++++++++++++++++++++ + 6 files changed, 1735 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/vc4_dsi.c + +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +index e53df59cb139f25f8e6ae916bca93abf0c49e063..e1517d07cb7d22776ca164a5d2d9b87e55a5563a 100644 +--- a/drivers/gpu/drm/vc4/Kconfig ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -2,10 +2,12 @@ config DRM_VC4 + tristate "Broadcom VC4 Graphics" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on DRM ++ depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select DRM_PANEL ++ select DRM_MIPI_DSI + help + Choose this option if you have a system that has a Broadcom + VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +index 3358ec8775cf6e8738ea8cdb2246dad57bd29139..897f658bee287f84f7dde8dca43090ad5541495b 100644 +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -8,6 +8,7 @@ vc4-y := \ + vc4_crtc.o \ + vc4_drv.o \ + vc4_dpi.o \ ++ vc4_dsi.o \ + vc4_firmware_kms.o \ + vc4_kms.o \ + vc4_gem.o \ +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index caf817bac8852c82f0d6a34b676a649c10e6e6cd..3ca476c6e0578e5fbe60d4fd623b09f8f937c0b7 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -18,6 +18,7 @@ + static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, + {"dpi_regs", vc4_dpi_debugfs_regs, 0}, ++ {"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, + {"vec_regs", vc4_vec_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 281609353063435f9da33f81bdc09dbc3ebc89e9..457e5e79ec8dc863fc66759662232c7160592f6e 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -296,6 +296,7 @@ static struct platform_driver *const component_drivers[] = { + &vc4_hdmi_driver, + &vc4_vec_driver, + &vc4_dpi_driver, ++ &vc4_dsi_driver, + &vc4_hvs_driver, + &vc4_crtc_driver, + &vc4_firmware_kms_driver, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 61a9b3e81823a3c96f36f710329844cc032e2628..44a8e6fda2b576fed63d93ef34e076cebf90d64c 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -20,6 +20,7 @@ struct vc4_dev { + struct vc4_crtc *crtc[3]; + struct vc4_v3d *v3d; + struct vc4_dpi *dpi; ++ struct vc4_dsi *dsi1; + struct vc4_vec *vec; + + struct drm_fbdev_cma *fbdev; +@@ -468,6 +469,10 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); + extern struct platform_driver vc4_dpi_driver; + int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); + ++/* vc4_dsi.c */ ++extern struct platform_driver vc4_dsi_driver; ++int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); ++ + /* vc4_firmware_kms.c */ + extern struct platform_driver vc4_firmware_kms_driver; + void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); +diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c +new file mode 100644 +index 0000000000000000000000000000000000000000..17fcac381dbb37cd9a5ff210ad8578f480177039 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_dsi.c +@@ -0,0 +1,1725 @@ ++/* ++ * Copyright (C) 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++/** ++ * DOC: VC4 DSI0/DSI1 module ++ * ++ * BCM2835 contains two DSI modules, DSI0 and DSI1. DSI0 is a ++ * single-lane DSI controller, while DSI1 is a more modern 4-lane DSI ++ * controller. ++ * ++ * Most Raspberry Pi boards expose DSI1 as their "DISPLAY" connector, ++ * while the compute module brings both DSI0 and DSI1 out. ++ * ++ * This driver has been tested for DSI1 video-mode display only ++ * currently, with most of the information necessary for DSI0 ++ * hopefully present. ++ */ ++ ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_edid.h" ++#include "drm_mipi_dsi.h" ++#include "drm_panel.h" ++#include "linux/clk.h" ++#include "linux/clk-provider.h" ++#include "linux/completion.h" ++#include "linux/component.h" ++#include "linux/dmaengine.h" ++#include "linux/i2c.h" ++#include "linux/of_address.h" ++#include "linux/of_platform.h" ++#include "linux/pm_runtime.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define DSI_CMD_FIFO_DEPTH 16 ++#define DSI_PIX_FIFO_DEPTH 256 ++#define DSI_PIX_FIFO_WIDTH 4 ++ ++#define DSI0_CTRL 0x00 ++ ++/* Command packet control. */ ++#define DSI0_TXPKT1C 0x04 /* AKA PKTC */ ++#define DSI1_TXPKT1C 0x04 ++# define DSI_TXPKT1C_TRIG_CMD_MASK VC4_MASK(31, 24) ++# define DSI_TXPKT1C_TRIG_CMD_SHIFT 24 ++# define DSI_TXPKT1C_CMD_REPEAT_MASK VC4_MASK(23, 10) ++# define DSI_TXPKT1C_CMD_REPEAT_SHIFT 10 ++ ++# define DSI_TXPKT1C_DISPLAY_NO_MASK VC4_MASK(9, 8) ++# define DSI_TXPKT1C_DISPLAY_NO_SHIFT 8 ++/* Short, trigger, BTA, or a long packet that fits all in CMDFIFO. */ ++# define DSI_TXPKT1C_DISPLAY_NO_SHORT 0 ++/* Primary display where cmdfifo provides part of the payload and ++ * pixelvalve the rest. ++ */ ++# define DSI_TXPKT1C_DISPLAY_NO_PRIMARY 1 ++/* Secondary display where cmdfifo provides part of the payload and ++ * pixfifo the rest. ++ */ ++# define DSI_TXPKT1C_DISPLAY_NO_SECONDARY 2 ++ ++# define DSI_TXPKT1C_CMD_TX_TIME_MASK VC4_MASK(7, 6) ++# define DSI_TXPKT1C_CMD_TX_TIME_SHIFT 6 ++ ++# define DSI_TXPKT1C_CMD_CTRL_MASK VC4_MASK(5, 4) ++# define DSI_TXPKT1C_CMD_CTRL_SHIFT 4 ++/* Command only. Uses TXPKT1H and DISPLAY_NO */ ++# define DSI_TXPKT1C_CMD_CTRL_TX 0 ++/* Command with BTA for either ack or read data. */ ++# define DSI_TXPKT1C_CMD_CTRL_RX 1 ++/* Trigger according to TRIG_CMD */ ++# define DSI_TXPKT1C_CMD_CTRL_TRIG 2 ++/* BTA alone for getting error status after a command, or a TE trigger ++ * without a previous command. ++ */ ++# define DSI_TXPKT1C_CMD_CTRL_BTA 3 ++ ++# define DSI_TXPKT1C_CMD_MODE_LP BIT(3) ++# define DSI_TXPKT1C_CMD_TYPE_LONG BIT(2) ++# define DSI_TXPKT1C_CMD_TE_EN BIT(1) ++# define DSI_TXPKT1C_CMD_EN BIT(0) ++ ++/* Command packet header. */ ++#define DSI0_TXPKT1H 0x08 /* AKA PKTH */ ++#define DSI1_TXPKT1H 0x08 ++# define DSI_TXPKT1H_BC_CMDFIFO_MASK VC4_MASK(31, 24) ++# define DSI_TXPKT1H_BC_CMDFIFO_SHIFT 24 ++# define DSI_TXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_TXPKT1H_BC_PARAM_SHIFT 8 ++# define DSI_TXPKT1H_BC_DT_MASK VC4_MASK(7, 0) ++# define DSI_TXPKT1H_BC_DT_SHIFT 0 ++ ++#define DSI0_RXPKT1H 0x0c /* AKA RX1_PKTH */ ++#define DSI1_RXPKT1H 0x14 ++# define DSI_RXPKT1H_CRC_ERR BIT(31) ++# define DSI_RXPKT1H_DET_ERR BIT(30) ++# define DSI_RXPKT1H_ECC_ERR BIT(29) ++# define DSI_RXPKT1H_COR_ERR BIT(28) ++# define DSI_RXPKT1H_INCOMP_PKT BIT(25) ++# define DSI_RXPKT1H_PKT_TYPE_LONG BIT(24) ++/* Byte count if DSI_RXPKT1H_PKT_TYPE_LONG */ ++# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 ++/* Short return bytes if !DSI_RXPKT1H_PKT_TYPE_LONG */ ++# define DSI_RXPKT1H_SHORT_1_MASK VC4_MASK(23, 16) ++# define DSI_RXPKT1H_SHORT_1_SHIFT 16 ++# define DSI_RXPKT1H_SHORT_0_MASK VC4_MASK(15, 8) ++# define DSI_RXPKT1H_SHORT_0_SHIFT 8 ++# define DSI_RXPKT1H_DT_LP_CMD_MASK VC4_MASK(7, 0) ++# define DSI_RXPKT1H_DT_LP_CMD_SHIFT 0 ++ ++#define DSI0_RXPKT2H 0x10 /* AKA RX2_PKTH */ ++#define DSI1_RXPKT2H 0x18 ++# define DSI_RXPKT1H_DET_ERR BIT(30) ++# define DSI_RXPKT1H_ECC_ERR BIT(29) ++# define DSI_RXPKT1H_COR_ERR BIT(28) ++# define DSI_RXPKT1H_INCOMP_PKT BIT(25) ++# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 ++# define DSI_RXPKT1H_DT_MASK VC4_MASK(7, 0) ++# define DSI_RXPKT1H_DT_SHIFT 0 ++ ++#define DSI0_TXPKT_CMD_FIFO 0x14 /* AKA CMD_DATAF */ ++#define DSI1_TXPKT_CMD_FIFO 0x1c ++ ++#define DSI0_DISP0_CTRL 0x18 ++# define DSI_DISP0_PIX_CLK_DIV_MASK VC4_MASK(21, 13) ++# define DSI_DISP0_PIX_CLK_DIV_SHIFT 13 ++# define DSI_DISP0_LP_STOP_CTRL_MASK VC4_MASK(12, 11) ++# define DSI_DISP0_LP_STOP_CTRL_SHIFT 11 ++# define DSI_DISP0_LP_STOP_DISABLE 0 ++# define DSI_DISP0_LP_STOP_PERLINE 1 ++# define DSI_DISP0_LP_STOP_PERFRAME 2 ++ ++/* Transmit RGB pixels and null packets only during HACTIVE, instead ++ * of going to LP-STOP. ++ */ ++# define DSI_DISP_HACTIVE_NULL BIT(10) ++/* Transmit blanking packet only during vblank, instead of allowing LP-STOP. */ ++# define DSI_DISP_VBLP_CTRL BIT(9) ++/* Transmit blanking packet only during HFP, instead of allowing LP-STOP. */ ++# define DSI_DISP_HFP_CTRL BIT(8) ++/* Transmit blanking packet only during HBP, instead of allowing LP-STOP. */ ++# define DSI_DISP_HBP_CTRL BIT(7) ++# define DSI_DISP0_CHANNEL_MASK VC4_MASK(6, 5) ++# define DSI_DISP0_CHANNEL_SHIFT 5 ++/* Enables end events for HSYNC/VSYNC, not just start events. */ ++# define DSI_DISP0_ST_END BIT(4) ++# define DSI_DISP0_PFORMAT_MASK VC4_MASK(3, 2) ++# define DSI_DISP0_PFORMAT_SHIFT 2 ++# define DSI_PFORMAT_RGB565 0 ++# define DSI_PFORMAT_RGB666_PACKED 1 ++# define DSI_PFORMAT_RGB666 2 ++# define DSI_PFORMAT_RGB888 3 ++/* Default is VIDEO mode. */ ++# define DSI_DISP0_COMMAND_MODE BIT(1) ++# define DSI_DISP0_ENABLE BIT(0) ++ ++#define DSI0_DISP1_CTRL 0x1c ++#define DSI1_DISP1_CTRL 0x2c ++/* Format of the data written to TXPKT_PIX_FIFO. */ ++# define DSI_DISP1_PFORMAT_MASK VC4_MASK(2, 1) ++# define DSI_DISP1_PFORMAT_SHIFT 1 ++# define DSI_DISP1_PFORMAT_16BIT 0 ++# define DSI_DISP1_PFORMAT_24BIT 1 ++# define DSI_DISP1_PFORMAT_32BIT_LE 2 ++# define DSI_DISP1_PFORMAT_32BIT_BE 3 ++ ++/* DISP1 is always command mode. */ ++# define DSI_DISP1_ENABLE BIT(0) ++ ++#define DSI0_TXPKT_PIX_FIFO 0x20 /* AKA PIX_FIFO */ ++ ++#define DSI0_INT_STAT 0x24 ++#define DSI0_INT_EN 0x28 ++# define DSI1_INT_PHY_D3_ULPS BIT(30) ++# define DSI1_INT_PHY_D3_STOP BIT(29) ++# define DSI1_INT_PHY_D2_ULPS BIT(28) ++# define DSI1_INT_PHY_D2_STOP BIT(27) ++# define DSI1_INT_PHY_D1_ULPS BIT(26) ++# define DSI1_INT_PHY_D1_STOP BIT(25) ++# define DSI1_INT_PHY_D0_ULPS BIT(24) ++# define DSI1_INT_PHY_D0_STOP BIT(23) ++# define DSI1_INT_FIFO_ERR BIT(22) ++# define DSI1_INT_PHY_DIR_RTF BIT(21) ++# define DSI1_INT_PHY_RXLPDT BIT(20) ++# define DSI1_INT_PHY_RXTRIG BIT(19) ++# define DSI1_INT_PHY_D0_LPDT BIT(18) ++# define DSI1_INT_PHY_DIR_FTR BIT(17) ++ ++/* Signaled when the clock lane enters the given state. */ ++# define DSI1_INT_PHY_CLOCK_ULPS BIT(16) ++# define DSI1_INT_PHY_CLOCK_HS BIT(15) ++# define DSI1_INT_PHY_CLOCK_STOP BIT(14) ++ ++/* Signaled on timeouts */ ++# define DSI1_INT_PR_TO BIT(13) ++# define DSI1_INT_TA_TO BIT(12) ++# define DSI1_INT_LPRX_TO BIT(11) ++# define DSI1_INT_HSTX_TO BIT(10) ++ ++/* Contention on a line when trying to drive the line low */ ++# define DSI1_INT_ERR_CONT_LP1 BIT(9) ++# define DSI1_INT_ERR_CONT_LP0 BIT(8) ++ ++/* Control error: incorrect line state sequence on data lane 0. */ ++# define DSI1_INT_ERR_CONTROL BIT(7) ++/* LPDT synchronization error (bits received not a multiple of 8. */ ++ ++# define DSI1_INT_ERR_SYNC_ESC BIT(6) ++/* Signaled after receiving an error packet from the display in ++ * response to a read. ++ */ ++# define DSI1_INT_RXPKT2 BIT(5) ++/* Signaled after receiving a packet. The header and optional short ++ * response will be in RXPKT1H, and a long response will be in the ++ * RXPKT_FIFO. ++ */ ++# define DSI1_INT_RXPKT1 BIT(4) ++# define DSI1_INT_TXPKT2_DONE BIT(3) ++# define DSI1_INT_TXPKT2_END BIT(2) ++/* Signaled after all repeats of TXPKT1 are transferred. */ ++# define DSI1_INT_TXPKT1_DONE BIT(1) ++/* Signaled after each TXPKT1 repeat is scheduled. */ ++# define DSI1_INT_TXPKT1_END BIT(0) ++ ++#define DSI1_INTERRUPTS_ALWAYS_ENABLED (DSI1_INT_ERR_SYNC_ESC | \ ++ DSI1_INT_ERR_CONTROL | \ ++ DSI1_INT_ERR_CONT_LP0 | \ ++ DSI1_INT_ERR_CONT_LP1 | \ ++ DSI1_INT_HSTX_TO | \ ++ DSI1_INT_LPRX_TO | \ ++ DSI1_INT_TA_TO | \ ++ DSI1_INT_PR_TO) ++ ++#define DSI0_STAT 0x2c ++#define DSI0_HSTX_TO_CNT 0x30 ++#define DSI0_LPRX_TO_CNT 0x34 ++#define DSI0_TA_TO_CNT 0x38 ++#define DSI0_PR_TO_CNT 0x3c ++#define DSI0_PHYC 0x40 ++# define DSI1_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(25, 20) ++# define DSI1_PHYC_ESC_CLK_LPDT_SHIFT 20 ++# define DSI1_PHYC_HS_CLK_CONTINUOUS BIT(18) ++# define DSI0_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(17, 12) ++# define DSI0_PHYC_ESC_CLK_LPDT_SHIFT 12 ++# define DSI1_PHYC_CLANE_ULPS BIT(17) ++# define DSI1_PHYC_CLANE_ENABLE BIT(16) ++# define DSI_PHYC_DLANE3_ULPS BIT(13) ++# define DSI_PHYC_DLANE3_ENABLE BIT(12) ++# define DSI0_PHYC_HS_CLK_CONTINUOUS BIT(10) ++# define DSI0_PHYC_CLANE_ULPS BIT(9) ++# define DSI_PHYC_DLANE2_ULPS BIT(9) ++# define DSI0_PHYC_CLANE_ENABLE BIT(8) ++# define DSI_PHYC_DLANE2_ENABLE BIT(8) ++# define DSI_PHYC_DLANE1_ULPS BIT(5) ++# define DSI_PHYC_DLANE1_ENABLE BIT(4) ++# define DSI_PHYC_DLANE0_FORCE_STOP BIT(2) ++# define DSI_PHYC_DLANE0_ULPS BIT(1) ++# define DSI_PHYC_DLANE0_ENABLE BIT(0) ++ ++#define DSI0_HS_CLT0 0x44 ++#define DSI0_HS_CLT1 0x48 ++#define DSI0_HS_CLT2 0x4c ++#define DSI0_HS_DLT3 0x50 ++#define DSI0_HS_DLT4 0x54 ++#define DSI0_HS_DLT5 0x58 ++#define DSI0_HS_DLT6 0x5c ++#define DSI0_HS_DLT7 0x60 ++ ++#define DSI0_PHY_AFEC0 0x64 ++# define DSI0_PHY_AFEC0_DDR2CLK_EN BIT(26) ++# define DSI0_PHY_AFEC0_DDRCLK_EN BIT(25) ++# define DSI0_PHY_AFEC0_LATCH_ULPS BIT(24) ++# define DSI1_PHY_AFEC0_IDR_DLANE3_MASK VC4_MASK(31, 29) ++# define DSI1_PHY_AFEC0_IDR_DLANE3_SHIFT 29 ++# define DSI1_PHY_AFEC0_IDR_DLANE2_MASK VC4_MASK(28, 26) ++# define DSI1_PHY_AFEC0_IDR_DLANE2_SHIFT 26 ++# define DSI1_PHY_AFEC0_IDR_DLANE1_MASK VC4_MASK(27, 23) ++# define DSI1_PHY_AFEC0_IDR_DLANE1_SHIFT 23 ++# define DSI1_PHY_AFEC0_IDR_DLANE0_MASK VC4_MASK(22, 20) ++# define DSI1_PHY_AFEC0_IDR_DLANE0_SHIFT 20 ++# define DSI1_PHY_AFEC0_IDR_CLANE_MASK VC4_MASK(19, 17) ++# define DSI1_PHY_AFEC0_IDR_CLANE_SHIFT 17 ++# define DSI0_PHY_AFEC0_ACTRL_DLANE1_MASK VC4_MASK(23, 20) ++# define DSI0_PHY_AFEC0_ACTRL_DLANE1_SHIFT 20 ++# define DSI0_PHY_AFEC0_ACTRL_DLANE0_MASK VC4_MASK(19, 16) ++# define DSI0_PHY_AFEC0_ACTRL_DLANE0_SHIFT 16 ++# define DSI0_PHY_AFEC0_ACTRL_CLANE_MASK VC4_MASK(15, 12) ++# define DSI0_PHY_AFEC0_ACTRL_CLANE_SHIFT 12 ++# define DSI1_PHY_AFEC0_DDR2CLK_EN BIT(16) ++# define DSI1_PHY_AFEC0_DDRCLK_EN BIT(15) ++# define DSI1_PHY_AFEC0_LATCH_ULPS BIT(14) ++# define DSI1_PHY_AFEC0_RESET BIT(13) ++# define DSI1_PHY_AFEC0_PD BIT(12) ++# define DSI0_PHY_AFEC0_RESET BIT(11) ++# define DSI1_PHY_AFEC0_PD_BG BIT(11) ++# define DSI0_PHY_AFEC0_PD BIT(10) ++# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(10) ++# define DSI0_PHY_AFEC0_PD_BG BIT(9) ++# define DSI1_PHY_AFEC0_PD_DLANE2 BIT(9) ++# define DSI0_PHY_AFEC0_PD_DLANE1 BIT(8) ++# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(8) ++# define DSI_PHY_AFEC0_PTATADJ_MASK VC4_MASK(7, 4) ++# define DSI_PHY_AFEC0_PTATADJ_SHIFT 4 ++# define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) ++# define DSI_PHY_AFEC0_CTATADJ_SHIFT 0 ++ ++#define DSI0_PHY_AFEC1 0x68 ++# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8) ++# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8 ++# define DSI0_PHY_AFEC1_IDR_DLANE0_MASK VC4_MASK(6, 4) ++# define DSI0_PHY_AFEC1_IDR_DLANE0_SHIFT 4 ++# define DSI0_PHY_AFEC1_IDR_CLANE_MASK VC4_MASK(2, 0) ++# define DSI0_PHY_AFEC1_IDR_CLANE_SHIFT 0 ++ ++#define DSI0_TST_SEL 0x6c ++#define DSI0_TST_MON 0x70 ++#define DSI0_ID 0x74 ++# define DSI_ID_VALUE 0x00647369 ++ ++#define DSI1_CTRL 0x00 ++# define DSI_CTRL_HS_CLKC_MASK VC4_MASK(15, 14) ++# define DSI_CTRL_HS_CLKC_SHIFT 14 ++# define DSI_CTRL_HS_CLKC_BYTE 0 ++# define DSI_CTRL_HS_CLKC_DDR2 1 ++# define DSI_CTRL_HS_CLKC_DDR 2 ++ ++# define DSI_CTRL_RX_LPDT_EOT_DISABLE BIT(13) ++# define DSI_CTRL_LPDT_EOT_DISABLE BIT(12) ++# define DSI_CTRL_HSDT_EOT_DISABLE BIT(11) ++# define DSI_CTRL_SOFT_RESET_CFG BIT(10) ++# define DSI_CTRL_CAL_BYTE BIT(9) ++# define DSI_CTRL_INV_BYTE BIT(8) ++# define DSI_CTRL_CLR_LDF BIT(7) ++# define DSI0_CTRL_CLR_PBCF BIT(6) ++# define DSI1_CTRL_CLR_RXF BIT(6) ++# define DSI0_CTRL_CLR_CPBCF BIT(5) ++# define DSI1_CTRL_CLR_PDF BIT(5) ++# define DSI0_CTRL_CLR_PDF BIT(4) ++# define DSI1_CTRL_CLR_CDF BIT(4) ++# define DSI0_CTRL_CLR_CDF BIT(3) ++# define DSI0_CTRL_CTRL2 BIT(2) ++# define DSI1_CTRL_DISABLE_DISP_CRCC BIT(2) ++# define DSI0_CTRL_CTRL1 BIT(1) ++# define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1) ++# define DSI0_CTRL_CTRL0 BIT(0) ++# define DSI1_CTRL_EN BIT(0) ++# define DSI0_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ ++ DSI0_CTRL_CLR_PBCF | \ ++ DSI0_CTRL_CLR_CPBCF | \ ++ DSI0_CTRL_CLR_PDF | \ ++ DSI0_CTRL_CLR_CDF) ++# define DSI1_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ ++ DSI1_CTRL_CLR_RXF | \ ++ DSI1_CTRL_CLR_PDF | \ ++ DSI1_CTRL_CLR_CDF) ++ ++#define DSI1_TXPKT2C 0x0c ++#define DSI1_TXPKT2H 0x10 ++#define DSI1_TXPKT_PIX_FIFO 0x20 ++#define DSI1_RXPKT_FIFO 0x24 ++#define DSI1_DISP0_CTRL 0x28 ++#define DSI1_INT_STAT 0x30 ++#define DSI1_INT_EN 0x34 ++/* State reporting bits. These mostly behave like INT_STAT, where ++ * writing a 1 clears the bit. ++ */ ++#define DSI1_STAT 0x38 ++# define DSI1_STAT_PHY_D3_ULPS BIT(31) ++# define DSI1_STAT_PHY_D3_STOP BIT(30) ++# define DSI1_STAT_PHY_D2_ULPS BIT(29) ++# define DSI1_STAT_PHY_D2_STOP BIT(28) ++# define DSI1_STAT_PHY_D1_ULPS BIT(27) ++# define DSI1_STAT_PHY_D1_STOP BIT(26) ++# define DSI1_STAT_PHY_D0_ULPS BIT(25) ++# define DSI1_STAT_PHY_D0_STOP BIT(24) ++# define DSI1_STAT_FIFO_ERR BIT(23) ++# define DSI1_STAT_PHY_RXLPDT BIT(22) ++# define DSI1_STAT_PHY_RXTRIG BIT(21) ++# define DSI1_STAT_PHY_D0_LPDT BIT(20) ++/* Set when in forward direction */ ++# define DSI1_STAT_PHY_DIR BIT(19) ++# define DSI1_STAT_PHY_CLOCK_ULPS BIT(18) ++# define DSI1_STAT_PHY_CLOCK_HS BIT(17) ++# define DSI1_STAT_PHY_CLOCK_STOP BIT(16) ++# define DSI1_STAT_PR_TO BIT(15) ++# define DSI1_STAT_TA_TO BIT(14) ++# define DSI1_STAT_LPRX_TO BIT(13) ++# define DSI1_STAT_HSTX_TO BIT(12) ++# define DSI1_STAT_ERR_CONT_LP1 BIT(11) ++# define DSI1_STAT_ERR_CONT_LP0 BIT(10) ++# define DSI1_STAT_ERR_CONTROL BIT(9) ++# define DSI1_STAT_ERR_SYNC_ESC BIT(8) ++# define DSI1_STAT_RXPKT2 BIT(7) ++# define DSI1_STAT_RXPKT1 BIT(6) ++# define DSI1_STAT_TXPKT2_BUSY BIT(5) ++# define DSI1_STAT_TXPKT2_DONE BIT(4) ++# define DSI1_STAT_TXPKT2_END BIT(3) ++# define DSI1_STAT_TXPKT1_BUSY BIT(2) ++# define DSI1_STAT_TXPKT1_DONE BIT(1) ++# define DSI1_STAT_TXPKT1_END BIT(0) ++ ++#define DSI1_HSTX_TO_CNT 0x3c ++#define DSI1_LPRX_TO_CNT 0x40 ++#define DSI1_TA_TO_CNT 0x44 ++#define DSI1_PR_TO_CNT 0x48 ++#define DSI1_PHYC 0x4c ++ ++#define DSI1_HS_CLT0 0x50 ++# define DSI_HS_CLT0_CZERO_MASK VC4_MASK(26, 18) ++# define DSI_HS_CLT0_CZERO_SHIFT 18 ++# define DSI_HS_CLT0_CPRE_MASK VC4_MASK(17, 9) ++# define DSI_HS_CLT0_CPRE_SHIFT 9 ++# define DSI_HS_CLT0_CPREP_MASK VC4_MASK(8, 0) ++# define DSI_HS_CLT0_CPREP_SHIFT 0 ++ ++#define DSI1_HS_CLT1 0x54 ++# define DSI_HS_CLT1_CTRAIL_MASK VC4_MASK(17, 9) ++# define DSI_HS_CLT1_CTRAIL_SHIFT 9 ++# define DSI_HS_CLT1_CPOST_MASK VC4_MASK(8, 0) ++# define DSI_HS_CLT1_CPOST_SHIFT 0 ++ ++#define DSI1_HS_CLT2 0x58 ++# define DSI_HS_CLT2_WUP_MASK VC4_MASK(23, 0) ++# define DSI_HS_CLT2_WUP_SHIFT 0 ++ ++#define DSI1_HS_DLT3 0x5c ++# define DSI_HS_DLT3_EXIT_MASK VC4_MASK(26, 18) ++# define DSI_HS_DLT3_EXIT_SHIFT 18 ++# define DSI_HS_DLT3_ZERO_MASK VC4_MASK(17, 9) ++# define DSI_HS_DLT3_ZERO_SHIFT 9 ++# define DSI_HS_DLT3_PRE_MASK VC4_MASK(8, 0) ++# define DSI_HS_DLT3_PRE_SHIFT 0 ++ ++#define DSI1_HS_DLT4 0x60 ++# define DSI_HS_DLT4_ANLAT_MASK VC4_MASK(22, 18) ++# define DSI_HS_DLT4_ANLAT_SHIFT 18 ++# define DSI_HS_DLT4_TRAIL_MASK VC4_MASK(17, 9) ++# define DSI_HS_DLT4_TRAIL_SHIFT 9 ++# define DSI_HS_DLT4_LPX_MASK VC4_MASK(8, 0) ++# define DSI_HS_DLT4_LPX_SHIFT 0 ++ ++#define DSI1_HS_DLT5 0x64 ++# define DSI_HS_DLT5_INIT_MASK VC4_MASK(23, 0) ++# define DSI_HS_DLT5_INIT_SHIFT 0 ++ ++#define DSI1_HS_DLT6 0x68 ++# define DSI_HS_DLT6_TA_GET_MASK VC4_MASK(31, 24) ++# define DSI_HS_DLT6_TA_GET_SHIFT 24 ++# define DSI_HS_DLT6_TA_SURE_MASK VC4_MASK(23, 16) ++# define DSI_HS_DLT6_TA_SURE_SHIFT 16 ++# define DSI_HS_DLT6_TA_GO_MASK VC4_MASK(15, 8) ++# define DSI_HS_DLT6_TA_GO_SHIFT 8 ++# define DSI_HS_DLT6_LP_LPX_MASK VC4_MASK(7, 0) ++# define DSI_HS_DLT6_LP_LPX_SHIFT 0 ++ ++#define DSI1_HS_DLT7 0x6c ++# define DSI_HS_DLT7_LP_WUP_MASK VC4_MASK(23, 0) ++# define DSI_HS_DLT7_LP_WUP_SHIFT 0 ++ ++#define DSI1_PHY_AFEC0 0x70 ++ ++#define DSI1_PHY_AFEC1 0x74 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE3_MASK VC4_MASK(19, 16) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE3_SHIFT 16 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE2_MASK VC4_MASK(15, 12) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE2_SHIFT 12 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE1_MASK VC4_MASK(11, 8) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE1_SHIFT 8 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE0_MASK VC4_MASK(7, 4) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE0_SHIFT 4 ++# define DSI1_PHY_AFEC1_ACTRL_CLANE_MASK VC4_MASK(3, 0) ++# define DSI1_PHY_AFEC1_ACTRL_CLANE_SHIFT 0 ++ ++#define DSI1_TST_SEL 0x78 ++#define DSI1_TST_MON 0x7c ++#define DSI1_PHY_TST1 0x80 ++#define DSI1_PHY_TST2 0x84 ++#define DSI1_PHY_FIFO_STAT 0x88 ++/* Actually, all registers in the range that aren't otherwise claimed ++ * will return the ID. ++ */ ++#define DSI1_ID 0x8c ++ ++/* General DSI hardware state. */ ++struct vc4_dsi { ++ struct platform_device *pdev; ++ ++ struct mipi_dsi_host dsi_host; ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ struct drm_panel *panel; ++ ++ void __iomem *regs; ++ ++ struct dma_chan *reg_dma_chan; ++ dma_addr_t reg_dma_paddr; ++ u32 *reg_dma_mem; ++ dma_addr_t reg_paddr; ++ ++ /* Whether we're on bcm2835's DSI0 or DSI1. */ ++ int port; ++ ++ /* DSI channel for the panel we're connected to. */ ++ u32 channel; ++ u32 lanes; ++ enum mipi_dsi_pixel_format format; ++ u32 mode_flags; ++ ++ /* Input clock from CPRMAN to the digital PHY, for the DSI ++ * escape clock. ++ */ ++ struct clk *escape_clock; ++ ++ /* Input clock to the analog PHY, used to generate the DSI bit ++ * clock. ++ */ ++ struct clk *pll_phy_clock; ++ ++ /* HS Clocks generated within the DSI analog PHY. */ ++ struct clk_fixed_factor phy_clocks[3]; ++ ++ struct clk_onecell_data clk_onecell; ++ ++ /* Pixel clock output to the pixelvalve, generated from the HS ++ * clock. ++ */ ++ struct clk *pixel_clock; ++ ++ struct completion xfer_completion; ++ int xfer_result; ++}; ++ ++#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) ++ ++static inline void ++dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) ++{ ++ struct dma_chan *chan = dsi->reg_dma_chan; ++ struct dma_async_tx_descriptor *tx; ++ dma_cookie_t cookie; ++ int ret; ++ ++ /* DSI0 should be able to write normally. */ ++ if (!chan) { ++ writel(val, dsi->regs + offset); ++ return; ++ } ++ ++ *dsi->reg_dma_mem = val; ++ ++ tx = chan->device->device_prep_dma_memcpy(chan, ++ dsi->reg_paddr + offset, ++ dsi->reg_dma_paddr, ++ 4, 0); ++ if (!tx) { ++ DRM_ERROR("Failed to set up DMA register write\n"); ++ return; ++ } ++ ++ cookie = tx->tx_submit(tx); ++ ret = dma_submit_error(cookie); ++ if (ret) { ++ DRM_ERROR("Failed to submit DMA: %d\n", ret); ++ return; ++ } ++ ret = dma_sync_wait(chan, cookie); ++ if (ret) ++ DRM_ERROR("Failed to wait for DMA: %d\n", ret); ++} ++ ++#define DSI_READ(offset) readl(dsi->regs + (offset)) ++#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) ++#define DSI_PORT_READ(offset) \ ++ DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset) ++#define DSI_PORT_WRITE(offset, val) \ ++ DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) ++#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) ++ ++/* VC4 DSI encoder KMS struct */ ++struct vc4_dsi_encoder { ++ struct vc4_encoder base; ++ struct vc4_dsi *dsi; ++}; ++ ++static inline struct vc4_dsi_encoder * ++to_vc4_dsi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_dsi_encoder, base.base); ++} ++ ++/* VC4 DSI connector KMS struct */ ++struct vc4_dsi_connector { ++ struct drm_connector base; ++ struct vc4_dsi *dsi; ++}; ++ ++static inline struct vc4_dsi_connector * ++to_vc4_dsi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_dsi_connector, base); ++} ++ ++#define DSI_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} dsi0_regs[] = { ++ DSI_REG(DSI0_CTRL), ++ DSI_REG(DSI0_STAT), ++ DSI_REG(DSI0_HSTX_TO_CNT), ++ DSI_REG(DSI0_LPRX_TO_CNT), ++ DSI_REG(DSI0_TA_TO_CNT), ++ DSI_REG(DSI0_PR_TO_CNT), ++ DSI_REG(DSI0_DISP0_CTRL), ++ DSI_REG(DSI0_DISP1_CTRL), ++ DSI_REG(DSI0_INT_STAT), ++ DSI_REG(DSI0_INT_EN), ++ DSI_REG(DSI0_PHYC), ++ DSI_REG(DSI0_HS_CLT0), ++ DSI_REG(DSI0_HS_CLT1), ++ DSI_REG(DSI0_HS_CLT2), ++ DSI_REG(DSI0_HS_DLT3), ++ DSI_REG(DSI0_HS_DLT4), ++ DSI_REG(DSI0_HS_DLT5), ++ DSI_REG(DSI0_HS_DLT6), ++ DSI_REG(DSI0_HS_DLT7), ++ DSI_REG(DSI0_PHY_AFEC0), ++ DSI_REG(DSI0_PHY_AFEC1), ++ DSI_REG(DSI0_ID), ++}; ++ ++static const struct { ++ u32 reg; ++ const char *name; ++} dsi1_regs[] = { ++ DSI_REG(DSI1_CTRL), ++ DSI_REG(DSI1_STAT), ++ DSI_REG(DSI1_HSTX_TO_CNT), ++ DSI_REG(DSI1_LPRX_TO_CNT), ++ DSI_REG(DSI1_TA_TO_CNT), ++ DSI_REG(DSI1_PR_TO_CNT), ++ DSI_REG(DSI1_DISP0_CTRL), ++ DSI_REG(DSI1_DISP1_CTRL), ++ DSI_REG(DSI1_INT_STAT), ++ DSI_REG(DSI1_INT_EN), ++ DSI_REG(DSI1_PHYC), ++ DSI_REG(DSI1_HS_CLT0), ++ DSI_REG(DSI1_HS_CLT1), ++ DSI_REG(DSI1_HS_CLT2), ++ DSI_REG(DSI1_HS_DLT3), ++ DSI_REG(DSI1_HS_DLT4), ++ DSI_REG(DSI1_HS_DLT5), ++ DSI_REG(DSI1_HS_DLT6), ++ DSI_REG(DSI1_HS_DLT7), ++ DSI_REG(DSI1_PHY_AFEC0), ++ DSI_REG(DSI1_PHY_AFEC1), ++ DSI_REG(DSI1_ID), ++}; ++ ++static void vc4_dsi_dump_regs(struct vc4_dsi *dsi) ++{ ++ int i; ++ ++ if (dsi->port == 0) { ++ for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ dsi0_regs[i].reg, dsi0_regs[i].name, ++ DSI_READ(dsi0_regs[i].reg)); ++ } ++ } else { ++ for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ dsi1_regs[i].reg, dsi1_regs[i].name, ++ DSI_READ(dsi1_regs[i].reg)); ++ } ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused) ++{ ++ struct drm_info_node *node = (struct drm_info_node *)m->private; ++ struct drm_device *drm = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ int dsi_index = (uintptr_t)node->info_ent->data; ++ struct vc4_dsi *dsi = (dsi_index == 1 ? vc4->dsi1 : NULL); ++ int i; ++ ++ if (!dsi) ++ return 0; ++ ++ if (dsi->port == 0) { ++ for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { ++ seq_printf(m, "0x%04x (%s): 0x%08x\n", ++ dsi0_regs[i].reg, dsi0_regs[i].name, ++ DSI_READ(dsi0_regs[i].reg)); ++ } ++ } else { ++ for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { ++ seq_printf(m, "0x%04x (%s): 0x%08x\n", ++ dsi1_regs[i].reg, dsi1_regs[i].name, ++ DSI_READ(dsi1_regs[i].reg)); ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static enum drm_connector_status ++vc4_dsi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct vc4_dsi_connector *vc4_connector = ++ to_vc4_dsi_connector(connector); ++ struct vc4_dsi *dsi = vc4_connector->dsi; ++ ++ if (dsi->panel) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++} ++ ++static void vc4_dsi_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_dsi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct vc4_dsi_connector *vc4_connector = ++ to_vc4_dsi_connector(connector); ++ struct vc4_dsi *dsi = vc4_connector->dsi; ++ ++ if (dsi->panel) ++ return drm_panel_get_modes(dsi->panel); ++ ++ return 0; ++} ++ ++static const struct drm_connector_funcs vc4_dsi_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_dsi_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = vc4_dsi_connector_destroy, ++ .reset = drm_atomic_helper_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_connector_helper_funcs vc4_dsi_connector_helper_funcs = { ++ .get_modes = vc4_dsi_connector_get_modes, ++}; ++ ++static struct drm_connector *vc4_dsi_connector_init(struct drm_device *dev, ++ struct vc4_dsi *dsi) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_dsi_connector *dsi_connector; ++ int ret = 0; ++ ++ dsi_connector = devm_kzalloc(dev->dev, sizeof(*dsi_connector), ++ GFP_KERNEL); ++ if (!dsi_connector) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ connector = &dsi_connector->base; ++ ++ dsi_connector->dsi = dsi; ++ ++ drm_connector_init(dev, connector, &vc4_dsi_connector_funcs, ++ DRM_MODE_CONNECTOR_DSI); ++ drm_connector_helper_add(connector, &vc4_dsi_connector_helper_funcs); ++ ++ connector->polled = 0; ++ connector->interlace_allowed = 0; ++ connector->doublescan_allowed = 0; ++ ++ drm_mode_connector_attach_encoder(connector, dsi->encoder); ++ ++ return connector; ++ ++fail: ++ if (connector) ++ vc4_dsi_connector_destroy(connector); ++ ++ return ERR_PTR(ret); ++} ++ ++static void vc4_dsi_encoder_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++} ++ ++static const struct drm_encoder_funcs vc4_dsi_encoder_funcs = { ++ .destroy = vc4_dsi_encoder_destroy, ++}; ++ ++static void vc4_dsi_latch_ulps(struct vc4_dsi *dsi, bool latch) ++{ ++ u32 afec0 = DSI_PORT_READ(PHY_AFEC0); ++ ++ if (latch) ++ afec0 |= DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); ++ else ++ afec0 &= ~DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++} ++ ++/* Enters or exits Ultra Low Power State. */ ++static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) ++{ ++ bool continuous = dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS; ++ u32 phyc_ulps = ((continuous ? DSI_PORT_BIT(PHYC_CLANE_ULPS) : 0) | ++ DSI_PHYC_DLANE0_ULPS | ++ (dsi->lanes > 1 ? DSI_PHYC_DLANE1_ULPS : 0) | ++ (dsi->lanes > 2 ? DSI_PHYC_DLANE2_ULPS : 0) | ++ (dsi->lanes > 3 ? DSI_PHYC_DLANE3_ULPS : 0)); ++ u32 stat_ulps = ((continuous ? DSI1_STAT_PHY_CLOCK_ULPS : 0) | ++ DSI1_STAT_PHY_D0_ULPS | ++ (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_ULPS : 0) | ++ (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_ULPS : 0) | ++ (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_ULPS : 0)); ++ u32 stat_stop = ((continuous ? DSI1_STAT_PHY_CLOCK_STOP : 0) | ++ DSI1_STAT_PHY_D0_STOP | ++ (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) | ++ (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) | ++ (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0)); ++ int ret; ++ ++ DSI_PORT_WRITE(STAT, stat_ulps); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) | phyc_ulps); ++ ret = wait_for((DSI_PORT_READ(STAT) & stat_ulps) == stat_ulps, 200); ++ if (ret) { ++ dev_warn(&dsi->pdev->dev, ++ "Timeout waiting for DSI ULPS entry: STAT 0x%08x", ++ DSI_PORT_READ(STAT)); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ vc4_dsi_latch_ulps(dsi, false); ++ return; ++ } ++ ++ /* The DSI module can't be disabled while the module is ++ * generating ULPS state. So, to be able to disable the ++ * module, we have the AFE latch the ULPS state and continue ++ * on to having the module enter STOP. ++ */ ++ vc4_dsi_latch_ulps(dsi, ulps); ++ ++ DSI_PORT_WRITE(STAT, stat_stop); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200); ++ if (ret) { ++ dev_warn(&dsi->pdev->dev, ++ "Timeout waiting for DSI STOP entry: STAT 0x%08x", ++ DSI_PORT_READ(STAT)); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ return; ++ } ++} ++ ++static u32 ++dsi_hs_timing(u32 ui_ns, u32 ns, u32 ui) ++{ ++ /* The HS timings have to be rounded up to a multiple of 8 ++ * because we're using the byte clock. ++ */ ++ return roundup(ui + DIV_ROUND_UP(ns, ui_ns), 8); ++} ++ ++/* ESC always runs at 100Mhz. */ ++#define ESC_TIME_NS 10 ++ ++static u32 ++dsi_esc_timing(u32 ns) ++{ ++ return DIV_ROUND_UP(ns, ESC_TIME_NS); ++} ++ ++static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); ++ struct vc4_dsi *dsi = vc4_encoder->dsi; ++ struct device *dev = &dsi->pdev->dev; ++ ++ drm_panel_disable(dsi->panel); ++ ++ vc4_dsi_ulps(dsi, true); ++ ++ drm_panel_unprepare(dsi->panel); ++ ++ clk_disable_unprepare(dsi->pll_phy_clock); ++ clk_disable_unprepare(dsi->escape_clock); ++ clk_disable_unprepare(dsi->pixel_clock); ++ ++ pm_runtime_put(dev); ++} ++ ++static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct drm_display_mode *mode = &encoder->crtc->mode; ++ struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); ++ struct vc4_dsi *dsi = vc4_encoder->dsi; ++ struct device *dev = &dsi->pdev->dev; ++ u32 format = 0, divider = 0; ++ bool debug_dump_regs = false; ++ unsigned long hs_clock; ++ u32 ui_ns; ++ /* Minimum LP state duration in escape clock cycles. */ ++ u32 lpx = dsi_esc_timing(60); ++ unsigned long pixel_clock_hz = mode->clock * 1000; ++ unsigned long dsip_clock; ++ unsigned long phy_clock; ++ int ret; ++ ++ ret = pm_runtime_get_sync(dev); ++ if (ret) { ++ DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port); ++ return; ++ } ++ ++ ret = drm_panel_prepare(dsi->panel); ++ if (ret) { ++ DRM_ERROR("Panel failed to prepare\n"); ++ return; ++ } ++ ++ if (debug_dump_regs) { ++ DRM_INFO("DSI regs before:\n"); ++ vc4_dsi_dump_regs(dsi); ++ } ++ ++ switch (dsi->format) { ++ case MIPI_DSI_FMT_RGB888: ++ format = DSI_PFORMAT_RGB888; ++ divider = 24 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB666: ++ format = DSI_PFORMAT_RGB666; ++ divider = 24 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ format = DSI_PFORMAT_RGB666_PACKED; ++ divider = 18 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB565: ++ format = DSI_PFORMAT_RGB565; ++ divider = 16 / dsi->lanes; ++ break; ++ } ++ ++ phy_clock = pixel_clock_hz * divider; ++ ret = clk_set_rate(dsi->pll_phy_clock, phy_clock); ++ if (ret) { ++ dev_err(&dsi->pdev->dev, ++ "Failed to set phy clock to %ld: %d\n", phy_clock, ret); ++ } ++ ++ /* Reset the DSI and all its fifos. */ ++ DSI_PORT_WRITE(CTRL, ++ DSI_CTRL_SOFT_RESET_CFG | ++ DSI_PORT_BIT(CTRL_RESET_FIFOS)); ++ ++ DSI_PORT_WRITE(CTRL, ++ DSI_CTRL_HSDT_EOT_DISABLE | ++ DSI_CTRL_RX_LPDT_EOT_DISABLE); ++ ++ /* Clear all stat bits so we see what has happened during enable. */ ++ DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); ++ ++ /* Set AFE CTR00/CTR1 to release powerdown of analog. */ ++ if (dsi->port == 0) { ++ u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | ++ VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); ++ ++ if (dsi->lanes < 2) ++ afec0 |= DSI0_PHY_AFEC0_PD_DLANE1; ++ ++ if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) ++ afec0 |= DSI0_PHY_AFEC0_RESET; ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++ ++ DSI_PORT_WRITE(PHY_AFEC1, ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE1) | ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE0) | ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_CLANE)); ++ } else { ++ u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | ++ VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_CLANE) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE0) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE1) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE2) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE3)); ++ ++ if (dsi->lanes < 4) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE3; ++ if (dsi->lanes < 3) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE2; ++ if (dsi->lanes < 2) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE1; ++ ++ afec0 |= DSI1_PHY_AFEC0_RESET; ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++ ++ DSI_PORT_WRITE(PHY_AFEC1, 0); ++ ++ /* AFEC reset hold time */ ++ mdelay(1); ++ } ++ ++ ret = clk_prepare_enable(dsi->escape_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(dsi->pll_phy_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret); ++ return; ++ } ++ ++ hs_clock = clk_get_rate(dsi->pll_phy_clock); ++ ++ /* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate, ++ * not the pixel clock rate. DSIxP take from the APHY's byte, ++ * DDR2, or DDR4 clock (we use byte) and feed into the PV at ++ * that rate. Separately, a value derived from PIX_CLK_DIV ++ * and HS_CLKC is fed into the PV to divide down to the actual ++ * pixel clock for pushing pixels into DSI. ++ */ ++ dsip_clock = phy_clock / 8; ++ ret = clk_set_rate(dsi->pixel_clock, dsip_clock); ++ if (ret) { ++ dev_err(dev, "Failed to set pixel clock to %ldHz: %d\n", ++ dsip_clock, ret); ++ } ++ ++ ret = clk_prepare_enable(dsi->pixel_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI pixel clock: %d\n", ret); ++ return; ++ } ++ ++ /* How many ns one DSI unit interval is. Note that the clock ++ * is DDR, so there's an extra divide by 2. ++ */ ++ ui_ns = DIV_ROUND_UP(500000000, hs_clock); ++ ++ DSI_PORT_WRITE(HS_CLT0, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 262, 0), ++ DSI_HS_CLT0_CZERO) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 0, 8), ++ DSI_HS_CLT0_CPRE) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 38, 0), ++ DSI_HS_CLT0_CPREP)); ++ ++ DSI_PORT_WRITE(HS_CLT1, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 0), ++ DSI_HS_CLT1_CTRAIL) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 52), ++ DSI_HS_CLT1_CPOST)); ++ ++ DSI_PORT_WRITE(HS_CLT2, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000000, 0), ++ DSI_HS_CLT2_WUP)); ++ ++ DSI_PORT_WRITE(HS_DLT3, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 100, 0), ++ DSI_HS_DLT3_EXIT) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 105, 6), ++ DSI_HS_DLT3_ZERO) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 40, 4), ++ DSI_HS_DLT3_PRE)); ++ ++ DSI_PORT_WRITE(HS_DLT4, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, lpx * ESC_TIME_NS, 0), ++ DSI_HS_DLT4_LPX) | ++ VC4_SET_FIELD(max(dsi_hs_timing(ui_ns, 0, 8), ++ dsi_hs_timing(ui_ns, 60, 4)), ++ DSI_HS_DLT4_TRAIL) | ++ VC4_SET_FIELD(0, DSI_HS_DLT4_ANLAT)); ++ ++ DSI_PORT_WRITE(HS_DLT5, VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000, 5000), ++ DSI_HS_DLT5_INIT)); ++ ++ DSI_PORT_WRITE(HS_DLT6, ++ VC4_SET_FIELD(lpx * 5, DSI_HS_DLT6_TA_GET) | ++ VC4_SET_FIELD(lpx, DSI_HS_DLT6_TA_SURE) | ++ VC4_SET_FIELD(lpx * 4, DSI_HS_DLT6_TA_GO) | ++ VC4_SET_FIELD(lpx, DSI_HS_DLT6_LP_LPX)); ++ ++ DSI_PORT_WRITE(HS_DLT7, ++ VC4_SET_FIELD(dsi_esc_timing(1000000), ++ DSI_HS_DLT7_LP_WUP)); ++ ++ DSI_PORT_WRITE(PHYC, ++ DSI_PHYC_DLANE0_ENABLE | ++ (dsi->lanes >= 2 ? DSI_PHYC_DLANE1_ENABLE : 0) | ++ (dsi->lanes >= 3 ? DSI_PHYC_DLANE2_ENABLE : 0) | ++ (dsi->lanes >= 4 ? DSI_PHYC_DLANE3_ENABLE : 0) | ++ DSI_PORT_BIT(PHYC_CLANE_ENABLE) | ++ ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? ++ 0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) | ++ (dsi->port == 0 ? ++ VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) : ++ VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); ++ ++ DSI_PORT_WRITE(CTRL, ++ DSI_PORT_READ(CTRL) | ++ DSI_CTRL_CAL_BYTE); ++ ++ /* HS timeout in HS clock cycles: disabled. */ ++ DSI_PORT_WRITE(HSTX_TO_CNT, 0); ++ /* LP receive timeout in HS clocks. */ ++ DSI_PORT_WRITE(LPRX_TO_CNT, 0xffffff); ++ /* Bus turnaround timeout */ ++ DSI_PORT_WRITE(TA_TO_CNT, 100000); ++ /* Display reset sequence timeout */ ++ DSI_PORT_WRITE(PR_TO_CNT, 100000); ++ ++ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { ++ DSI_PORT_WRITE(DISP0_CTRL, ++ VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) | ++ VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) | ++ VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, ++ DSI_DISP0_LP_STOP_CTRL) | ++ DSI_DISP0_ST_END | ++ DSI_DISP0_ENABLE); ++ } else { ++ DSI_PORT_WRITE(DISP0_CTRL, ++ DSI_DISP0_COMMAND_MODE | ++ DSI_DISP0_ENABLE); ++ } ++ ++ /* Set up DISP1 for transferring long command payloads through ++ * the pixfifo. ++ */ ++ DSI_PORT_WRITE(DISP1_CTRL, ++ VC4_SET_FIELD(DSI_DISP1_PFORMAT_32BIT_LE, ++ DSI_DISP1_PFORMAT) | ++ DSI_DISP1_ENABLE); ++ ++ /* Ungate the block. */ ++ if (dsi->port == 0) ++ DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); ++ else ++ DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); ++ ++ /* Bring AFE out of reset. */ ++ if (dsi->port == 0) { ++ } else { ++ DSI_PORT_WRITE(PHY_AFEC0, ++ DSI_PORT_READ(PHY_AFEC0) & ++ ~DSI1_PHY_AFEC0_RESET); ++ } ++ ++ vc4_dsi_ulps(dsi, false); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("DSI regs after:\n"); ++ vc4_dsi_dump_regs(dsi); ++ } ++ ++ ret = drm_panel_enable(dsi->panel); ++ if (ret) { ++ DRM_ERROR("Panel failed to enable\n"); ++ drm_panel_unprepare(dsi->panel); ++ return; ++ } ++} ++ ++static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, ++ const struct mipi_dsi_msg *msg) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ struct mipi_dsi_packet packet; ++ u32 pkth = 0, pktc = 0; ++ int i, ret; ++ bool is_long = mipi_dsi_packet_format_is_long(msg->type); ++ u32 cmd_fifo_len = 0, pix_fifo_len = 0; ++ ++ mipi_dsi_create_packet(&packet, msg); ++ ++ pkth |= VC4_SET_FIELD(packet.header[0], DSI_TXPKT1H_BC_DT); ++ pkth |= VC4_SET_FIELD(packet.header[1] | ++ (packet.header[2] << 8), ++ DSI_TXPKT1H_BC_PARAM); ++ if (is_long) { ++ /* Divide data across the various FIFOs we have available. ++ * The command FIFO takes byte-oriented data, but is of ++ * limited size. The pixel FIFO (never actually used for ++ * pixel data in reality) is word oriented, and substantially ++ * larger. So, we use the pixel FIFO for most of the data, ++ * sending the residual bytes in the command FIFO at the start. ++ * ++ * With this arrangement, the command FIFO will never get full. ++ */ ++ if (packet.payload_length <= 16) { ++ cmd_fifo_len = packet.payload_length; ++ pix_fifo_len = 0; ++ } else { ++ cmd_fifo_len = (packet.payload_length % ++ DSI_PIX_FIFO_WIDTH); ++ pix_fifo_len = ((packet.payload_length - cmd_fifo_len) / ++ DSI_PIX_FIFO_WIDTH); ++ } ++ ++ WARN_ON_ONCE(pix_fifo_len >= DSI_PIX_FIFO_DEPTH); ++ ++ pkth |= VC4_SET_FIELD(cmd_fifo_len, DSI_TXPKT1H_BC_CMDFIFO); ++ } ++ ++ if (msg->rx_len) { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_RX, ++ DSI_TXPKT1C_CMD_CTRL); ++ } else { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_TX, ++ DSI_TXPKT1C_CMD_CTRL); ++ } ++ ++ for (i = 0; i < cmd_fifo_len; i++) ++ DSI_PORT_WRITE(TXPKT_CMD_FIFO, packet.payload[i]); ++ for (i = 0; i < pix_fifo_len; i++) { ++ const u8 *pix = packet.payload + cmd_fifo_len + i * 4; ++ ++ DSI_PORT_WRITE(TXPKT_PIX_FIFO, ++ pix[0] | ++ pix[1] << 8 | ++ pix[2] << 16 | ++ pix[3] << 24); ++ } ++ ++ if (msg->flags & MIPI_DSI_MSG_USE_LPM) ++ pktc |= DSI_TXPKT1C_CMD_MODE_LP; ++ if (is_long) ++ pktc |= DSI_TXPKT1C_CMD_TYPE_LONG; ++ ++ /* Send one copy of the packet. Larger repeats are used for pixel ++ * data in command mode. ++ */ ++ pktc |= VC4_SET_FIELD(1, DSI_TXPKT1C_CMD_REPEAT); ++ ++ pktc |= DSI_TXPKT1C_CMD_EN; ++ if (pix_fifo_len) { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SECONDARY, ++ DSI_TXPKT1C_DISPLAY_NO); ++ } else { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SHORT, ++ DSI_TXPKT1C_DISPLAY_NO); ++ } ++ ++ /* Enable the appropriate interrupt for the transfer completion. */ ++ dsi->xfer_result = 0; ++ reinit_completion(&dsi->xfer_completion); ++ DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF); ++ if (msg->rx_len) { ++ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | ++ DSI1_INT_PHY_DIR_RTF)); ++ } else { ++ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | ++ DSI1_INT_TXPKT1_DONE)); ++ } ++ ++ /* Send the packet. */ ++ DSI_PORT_WRITE(TXPKT1H, pkth); ++ DSI_PORT_WRITE(TXPKT1C, pktc); ++ ++ if (!wait_for_completion_timeout(&dsi->xfer_completion, ++ msecs_to_jiffies(1000))) { ++ dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); ++ dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", ++ DSI_PORT_READ(INT_STAT)); ++ ret = -ETIMEDOUT; ++ } else { ++ ret = dsi->xfer_result; ++ } ++ ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ ++ if (ret) ++ goto reset_fifo_and_return; ++ ++ if (ret == 0 && msg->rx_len) { ++ u32 rxpkt1h = DSI_PORT_READ(RXPKT1H); ++ u8 *msg_rx = msg->rx_buf; ++ ++ if (rxpkt1h & DSI_RXPKT1H_PKT_TYPE_LONG) { ++ u32 rxlen = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_BC_PARAM); ++ ++ if (rxlen != msg->rx_len) { ++ DRM_ERROR("DSI returned %db, expecting %db\n", ++ rxlen, (int)msg->rx_len); ++ ret = -ENXIO; ++ goto reset_fifo_and_return; ++ } ++ ++ for (i = 0; i < msg->rx_len; i++) ++ msg_rx[i] = DSI_READ(DSI1_RXPKT_FIFO); ++ } else { ++ /* FINISHME: Handle AWER */ ++ ++ msg_rx[0] = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_SHORT_0); ++ if (msg->rx_len > 1) { ++ msg_rx[1] = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_SHORT_1); ++ } ++ } ++ } ++ ++ return ret; ++ ++reset_fifo_and_return: ++ DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); ++ ++ DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); ++ udelay(1); ++ DSI_PORT_WRITE(CTRL, ++ DSI_PORT_READ(CTRL) | ++ DSI_PORT_BIT(CTRL_RESET_FIFOS)); ++ ++ DSI_PORT_WRITE(TXPKT1C, 0); ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ return ret; ++} ++ ++static int vc4_dsi_host_attach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ int ret = 0; ++ ++ dsi->lanes = device->lanes; ++ dsi->channel = device->channel; ++ dsi->format = device->format; ++ dsi->mode_flags = device->mode_flags; ++ ++ if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { ++ dev_err(&dsi->pdev->dev, ++ "Only VIDEO mode panels supported currently.\n"); ++ return 0; ++ } ++ ++ dsi->panel = of_drm_find_panel(device->dev.of_node); ++ if (!dsi->panel) ++ return 0; ++ ++ ret = drm_panel_attach(dsi->panel, dsi->connector); ++ if (ret != 0) ++ return ret; ++ ++ drm_helper_hpd_irq_event(dsi->connector->dev); ++ ++ return 0; ++} ++ ++static int vc4_dsi_host_detach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ ++ if (dsi->panel) { ++ int ret = drm_panel_detach(dsi->panel); ++ ++ if (ret) ++ return ret; ++ ++ dsi->panel = NULL; ++ ++ drm_helper_hpd_irq_event(dsi->connector->dev); ++ } ++ ++ return 0; ++} ++ ++static const struct mipi_dsi_host_ops vc4_dsi_host_ops = { ++ .attach = vc4_dsi_host_attach, ++ .detach = vc4_dsi_host_detach, ++ .transfer = vc4_dsi_host_transfer, ++}; ++ ++static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { ++ .disable = vc4_dsi_encoder_disable, ++ .enable = vc4_dsi_encoder_enable, ++}; ++ ++static const struct of_device_id vc4_dsi_dt_match[] = { ++ { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 }, ++ {} ++}; ++ ++static void dsi_handle_error(struct vc4_dsi *dsi, ++ irqreturn_t *ret, u32 stat, u32 bit, ++ const char *type) ++{ ++ if (!(stat & bit)) ++ return; ++ ++ DRM_ERROR("DSI%d: %s error\n", dsi->port, type); ++ *ret = IRQ_HANDLED; ++} ++ ++static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) ++{ ++ struct vc4_dsi *dsi = data; ++ u32 stat = DSI_PORT_READ(INT_STAT); ++ irqreturn_t ret = IRQ_NONE; ++ ++ DSI_PORT_WRITE(INT_STAT, stat); ++ ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_SYNC_ESC, "LPDT sync"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONTROL, "data lane 0 sequence"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONT_LP0, "LP0 contention"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONT_LP1, "LP1 contention"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_HSTX_TO, "HSTX timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_LPRX_TO, "LPRX timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_TA_TO, "turnaround timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_PR_TO, "peripheral reset timeout"); ++ ++ if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) { ++ complete(&dsi->xfer_completion); ++ ret = IRQ_HANDLED; ++ } else if (stat & DSI1_INT_HSTX_TO) { ++ complete(&dsi->xfer_completion); ++ dsi->xfer_result = -ETIMEDOUT; ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++/** ++ * Exposes clocks generated by the analog PHY that are consumed by ++ * CPRMAN (clk-bcm2835.c). ++ */ ++static int ++vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) ++{ ++ struct device *dev = &dsi->pdev->dev; ++ const char *parent_name = __clk_get_name(dsi->pll_phy_clock); ++ static const struct { ++ const char *dsi0_name, *dsi1_name; ++ int div; ++ } phy_clocks[] = { ++ { "dsi0_byte", "dsi1_byte", 8 }, ++ { "dsi0_ddr2", "dsi1_ddr2", 4 }, ++ { "dsi0_ddr", "dsi1_ddr", 2 }, ++ }; ++ int i; ++ ++ dsi->clk_onecell.clk_num = ARRAY_SIZE(phy_clocks); ++ dsi->clk_onecell.clks = devm_kcalloc(dev, ++ dsi->clk_onecell.clk_num, ++ sizeof(*dsi->clk_onecell.clks), ++ GFP_KERNEL); ++ if (!dsi->clk_onecell.clks) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { ++ struct clk_fixed_factor *fix = &dsi->phy_clocks[i]; ++ struct clk_init_data init; ++ struct clk *clk; ++ ++ /* We just use core fixed factor clock ops for the PHY ++ * clocks. The clocks are actually gated by the ++ * PHY_AFEC0_DDRCLK_EN bits, which we should be ++ * setting if we use the DDR/DDR2 clocks. However, ++ * vc4_dsi_encoder_enable() is setting up both AFEC0, ++ * setting both our parent DSI PLL's rate and this ++ * clock's rate, so it knows if DDR/DDR2 are going to ++ * be used and could enable the gates itself. ++ */ ++ fix->mult = 1; ++ fix->div = phy_clocks[i].div; ++ fix->hw.init = &init; ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &parent_name; ++ init.num_parents = 1; ++ if (dsi->port == 1) ++ init.name = phy_clocks[i].dsi1_name; ++ else ++ init.name = phy_clocks[i].dsi0_name; ++ init.ops = &clk_fixed_factor_ops; ++ init.flags = CLK_IS_BASIC; ++ ++ clk = devm_clk_register(dev, &fix->hw); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ dsi->clk_onecell.clks[i] = clk; ++ } ++ ++ return of_clk_add_provider(dev->of_node, ++ of_clk_src_onecell_get, ++ &dsi->clk_onecell); ++} ++ ++static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_dsi *dsi; ++ struct vc4_dsi_encoder *vc4_dsi_encoder; ++ const struct of_device_id *match; ++ dma_cap_mask_t dma_mask; ++ int ret; ++ ++ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); ++ if (!dsi) ++ return -ENOMEM; ++ ++ match = of_match_device(vc4_dsi_dt_match, dev); ++ if (!match) ++ return -ENODEV; ++ ++ dsi->port = (uintptr_t)match->data; ++ ++ vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), ++ GFP_KERNEL); ++ if (!vc4_dsi_encoder) ++ return -ENOMEM; ++ vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1; ++ vc4_dsi_encoder->dsi = dsi; ++ dsi->encoder = &vc4_dsi_encoder->base.base; ++ ++ dsi->pdev = pdev; ++ dsi->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(dsi->regs)) ++ return PTR_ERR(dsi->regs); ++ ++ if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { ++ dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", ++ DSI_PORT_READ(ID), DSI_ID_VALUE); ++ return -ENODEV; ++ } ++ ++ /* DSI1 has a broken AXI slave that doesn't respond to writes ++ * from the ARM. It does handle writes from the DMA engine, ++ * so set up a channel for talking to it. ++ */ ++ if (dsi->port == 1) { ++ dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, ++ &dsi->reg_dma_paddr, ++ GFP_KERNEL); ++ if (!dsi->reg_dma_mem) { ++ DRM_ERROR("Failed to get DMA memory\n"); ++ return -ENOMEM; ++ } ++ ++ dma_cap_zero(dma_mask); ++ dma_cap_set(DMA_MEMCPY, dma_mask); ++ dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask); ++ if (IS_ERR(dsi->reg_dma_chan)) { ++ ret = PTR_ERR(dsi->reg_dma_chan); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Failed to get DMA channel: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Get the physical address of the device's registers. The ++ * struct resource for the regs gives us the bus address ++ * instead. ++ */ ++ dsi->reg_paddr = be32_to_cpup(of_get_address(dev->of_node, ++ 0, NULL, NULL)); ++ } ++ ++ init_completion(&dsi->xfer_completion); ++ /* At startup enable error-reporting interrupts and nothing else. */ ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ /* Clear any existing interrupt state. */ ++ DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT)); ++ ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_dsi_irq_handler, 0, "vc4 dsi", dsi); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get interrupt: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->escape_clock = devm_clk_get(dev, "escape"); ++ if (IS_ERR(dsi->escape_clock)) { ++ ret = PTR_ERR(dsi->escape_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get escape clock: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->pll_phy_clock = devm_clk_get(dev, "phy"); ++ if (IS_ERR(dsi->pll_phy_clock)) { ++ ret = PTR_ERR(dsi->pll_phy_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get phy clock: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->pixel_clock = devm_clk_get(dev, "pixel"); ++ if (IS_ERR(dsi->pixel_clock)) { ++ ret = PTR_ERR(dsi->pixel_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get pixel clock: %d\n", ret); ++ return ret; ++ } ++ ++ /* The esc clock rate is supposed to always be 100Mhz. */ ++ ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); ++ if (ret) { ++ dev_err(dev, "Failed to set esc clock: %d\n", ret); ++ return ret; ++ } ++ ++ ret = vc4_dsi_init_phy_clocks(dsi); ++ if (ret) ++ return ret; ++ ++ if (dsi->port == 1) ++ vc4->dsi1 = dsi; ++ ++ drm_encoder_init(drm, dsi->encoder, &vc4_dsi_encoder_funcs, ++ DRM_MODE_ENCODER_DSI, NULL); ++ drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); ++ ++ dsi->connector = vc4_dsi_connector_init(drm, dsi); ++ if (IS_ERR(dsi->connector)) { ++ ret = PTR_ERR(dsi->connector); ++ goto err_destroy_encoder; ++ } ++ ++ dsi->dsi_host.ops = &vc4_dsi_host_ops; ++ dsi->dsi_host.dev = dev; ++ ++ mipi_dsi_host_register(&dsi->dsi_host); ++ ++ dev_set_drvdata(dev, dsi); ++ ++ pm_runtime_enable(dev); ++ ++ return 0; ++ ++err_destroy_encoder: ++ vc4_dsi_encoder_destroy(dsi->encoder); ++ ++ return ret; ++} ++ ++static void vc4_dsi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_dsi *dsi = dev_get_drvdata(dev); ++ ++ pm_runtime_disable(dev); ++ ++ vc4_dsi_connector_destroy(dsi->connector); ++ vc4_dsi_encoder_destroy(dsi->encoder); ++ ++ mipi_dsi_host_unregister(&dsi->dsi_host); ++ ++ clk_disable_unprepare(dsi->pll_phy_clock); ++ clk_disable_unprepare(dsi->escape_clock); ++ ++ if (dsi->port == 1) ++ vc4->dsi1 = NULL; ++} ++ ++static const struct component_ops vc4_dsi_ops = { ++ .bind = vc4_dsi_bind, ++ .unbind = vc4_dsi_unbind, ++}; ++ ++static int vc4_dsi_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_dsi_ops); ++} ++ ++static int vc4_dsi_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_dsi_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_dsi_driver = { ++ .probe = vc4_dsi_dev_probe, ++ .remove = vc4_dsi_dev_remove, ++ .driver = { ++ .name = "vc4_dsi", ++ .of_match_table = vc4_dsi_dt_match, ++ }, ++}; + +From 58727f518ad71b875066c26f68e82c3c521f1337 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:12 +0100 +Subject: [PATCH 170/187] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi + +Add the VEC (Video EnCoder) node definition in bcm283x.dtsi. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit b899c45208d6f204a6da9a1132577993eeecf0fb) +--- + arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 41776b97b4b6b1c053d07fd357fac4ba4787ac53..d3cc586661f903e67a840189c0446aa80e16a44e 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -310,6 +310,14 @@ + status = "disabled"; + }; + ++ vec: vec@7e806000 { ++ compatible = "brcm,bcm2835-vec"; ++ reg = <0x7e806000 0x1000>; ++ clocks = <&clocks BCM2835_CLOCK_VEC>; ++ interrupts = <2 27>; ++ status = "disabled"; ++ }; ++ + pixelvalve@7e807000 { + compatible = "brcm,bcm2835-pixelvalve2"; + reg = <0x7e807000 0x100>; + +From 8142ae28587b1f8ec8ea0297a6e51445642bbba6 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:13 +0100 +Subject: [PATCH 171/187] ARM: dts: bcm283x: Enable the VEC IP on all + RaspberryPi boards + +Enable the VEC IP on all RaspberryPi boards. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit 5ab1a37c6027c114a87a1ae32cfc5ef303d643c5) +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index 365648898f3acc4f82dc6cb58e4bbebbe249be94..d4577a51e678cb600b475d3d3395ca4e67593cf6 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -92,3 +92,8 @@ + &dsi1 { + power-domains = <&power RPI_POWER_DOMAIN_DSI1>; + }; ++ ++&vec { ++ power-domains = <&power RPI_POWER_DOMAIN_VEC>; ++ status = "okay"; ++}; + +From d04e3ecbc1e8605d4a165b25abdeb7a6dec4f541 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 23 Jan 2017 11:41:54 -0800 +Subject: [PATCH 172/187] BCM270X: Disable VEC unless vc4-kms-v3d is present. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708-rpi.dtsi | 4 ++++ + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 7 +++++++ + 2 files changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi.dtsi b/arch/arm/boot/dts/bcm2708-rpi.dtsi +index 46cf8602c3b96e477b05b57dbfe5e349930c9d9a..1f5f40b9c7cbd574f12a42d8c3fa5344138d155e 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi +@@ -107,3 +107,7 @@ + &usb { + power-domains = <&power RPI_POWER_DOMAIN_USB>; + }; ++ ++&vec { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index f25cd9a3936861920b0d518ff2d773ee467e2f49..a8ef8c9051668a7477dea30aa262568c8e7f221c 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -148,6 +148,13 @@ + }; + }; + ++ fragment@18 { ++ target = <&vec>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; + +From 8491a96b1dcd7a0e838560cd1cbf5eb28866ddf2 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 1 Feb 2017 17:09:18 -0800 +Subject: [PATCH 173/187] drm/vc4: Name the primary and cursor planes in fkms. + +This makes debugging nicer, compared to trying to remember what the +IDs are. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index d18a1dae51a2275846c9826b5bf1ba57ae97b55c..e49ce68b607a7ffc2329e3235362f3bc21ed5cbb 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -267,7 +267,7 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, + primary ? &xrgb8888 : &argb8888, 1, +- type, NULL); ++ type, primary ? "primary" : "cursor"); + + if (type == DRM_PLANE_TYPE_PRIMARY) { + vc4_plane->fbinfo = + +From 5f1bdfa494cedc463f8fb2666986ff175afa9ec4 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 1 Feb 2017 17:10:09 -0800 +Subject: [PATCH 174/187] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of + fkms. + +Trying to debug weston on fkms involved figuring out what calls I was +making to the firmware. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index e49ce68b607a7ffc2329e3235362f3bc21ed5cbb..dbf065677202fbebf8e3a0cffbe880aa42daef3f 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -102,6 +102,11 @@ static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank) + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + + u32 packet = blank; ++ ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s", ++ plane->base.id, plane->name, ++ blank ? "blank" : "unblank"); ++ + return rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_FRAMEBUFFER_BLANK, + &packet, sizeof(packet)); +@@ -149,6 +154,16 @@ static void vc4_primary_plane_atomic_update(struct drm_plane *plane, + WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); + } + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n", ++ plane->base.id, plane->name, ++ state->crtc_w, ++ state->crtc_h, ++ bpp, ++ state->crtc_x, ++ state->crtc_y, ++ bo->paddr + fb->offsets[0], ++ fb->pitches[0]); ++ + ret = rpi_firmware_transaction(vc4->firmware, + RPI_FIRMWARE_CHAN_FB, + vc4_plane->fbinfo_bus_addr); +@@ -178,6 +193,15 @@ static void vc4_cursor_plane_atomic_update(struct drm_plane *plane, + WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); + WARN_ON_ONCE(fb->bits_per_pixel != 32); + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)", ++ plane->base.id, plane->name, ++ state->crtc_w, ++ state->crtc_h, ++ state->crtc_x, ++ state->crtc_y, ++ bo->paddr + fb->offsets[0], ++ fb->pitches[0]); ++ + ret = rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_SET_CURSOR_STATE, + &packet_state, +@@ -200,6 +224,8 @@ static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane, + u32 packet_state[] = { false, 0, 0, 0 }; + int ret; + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name); ++ + ret = rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_SET_CURSOR_STATE, + &packet_state, + +From d464fabeba2314b595ee9ff7fde7f65d03b747ca Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Feb 2017 09:42:18 -0800 +Subject: [PATCH 175/187] drm/vc4: Fix sending of page flip completion events + in FKMS mode. + +In the rewrite of vc4_crtc.c for fkms, I dropped the part of the +CRTC's atomic flush handler that moved the completion event from the +proposed atomic state change to the CRTC's current state. That meant +that when full screen pageflipping happened (glxgears -fullscreen in +X, compton, por weston), the app would end up blocked firever waiting +to draw its next frame. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index dbf065677202fbebf8e3a0cffbe880aa42daef3f..da818a207bfa639b8cea48d94bcf4566f97db816 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -338,6 +338,21 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, + static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) + { ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ ++ if (crtc->state->event) { ++ unsigned long flags; ++ ++ crtc->state->event->pipe = drm_crtc_index(crtc); ++ ++ WARN_ON(drm_crtc_vblank_get(crtc) != 0); ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ vc4_crtc->event = crtc->state->event; ++ crtc->state->event = NULL; ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } + } + + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + +From 7e9e22730f563aabfd467d2fda9b89be3b0fd496 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 8 Feb 2017 15:00:54 -0800 +Subject: [PATCH 176/187] drm/vc4: Fulfill user BO creation requests from the + kernel BO cache. + +The from_cache flag was actually "the BO is invisible to userspace", +so we can repurpose to just zero out a cached BO and return it to +userspace. + +Improves wall time for a loop of 5 glsl-algebraic-add-add-1 by +-1.44989% +/- 0.862891% (n=28, 1 outlier removed from each that +appeared to be other system noise) + +Note that there's an intel-gpu-tools test to check for the proper +zeroing behavior here, which we continue to pass. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_bo.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 3f6704cf6608d7be47637c6aa585de087b7f74ee..5ec14f25625dde6fd61e10415092fa25527cc151 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -208,21 +208,22 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) + } + + struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, +- bool from_cache) ++ bool allow_unzeroed) + { + size_t size = roundup(unaligned_size, PAGE_SIZE); + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_gem_cma_object *cma_obj; ++ struct vc4_bo *bo; + + if (size == 0) + return ERR_PTR(-EINVAL); + + /* First, try to get a vc4_bo from the kernel BO cache. */ +- if (from_cache) { +- struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size); +- +- if (bo) +- return bo; ++ bo = vc4_bo_get_from_cache(dev, size); ++ if (bo) { ++ if (!allow_unzeroed) ++ memset(bo->base.vaddr, 0, bo->base.base.size); ++ return bo; + } + + cma_obj = drm_gem_cma_create(dev, size); + +From 8c1a0bfae9ef4725fb4e794cd40eeb6a0c45cbe6 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 9 Feb 2017 09:23:34 -0800 +Subject: [PATCH 177/187] drm/vc4: Fix OOPSes from trying to cache a partially + constructed BO. + +If a CMA allocation failed, the partially constructed BO would be +unreferenced through the normal path, and we might choose to put it in +the BO cache. If we then reused it before it expired from the cache, +the kernel would OOPS. + +Signed-off-by: Eric Anholt +Fixes: c826a6e10644 ("drm/vc4: Add a BO cache.") +--- + drivers/gpu/drm/vc4/vc4_bo.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 5ec14f25625dde6fd61e10415092fa25527cc151..fd83a28076564b9ea5cf0f2ba29b884ee3c5af43 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -314,6 +314,14 @@ void vc4_free_object(struct drm_gem_object *gem_bo) + goto out; + } + ++ /* If this object was partially constructed but CMA allocation ++ * had failed, just free it. ++ */ ++ if (!bo->base.vaddr) { ++ vc4_bo_destroy(bo); ++ goto out; ++ } ++ + cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size); + if (!cache_list) { + vc4_bo_destroy(bo); + +From 0111b8ac9e24f072185d6789f16fe96687b599bd Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 12 Oct 2015 08:58:08 -0700 +Subject: [PATCH 178/187] drm/vc4: Verify at boot that CMA doesn't cross a + 256MB boundary. + +I've seen lots of users cranking CMA up higher, so throw an error if +they do. + +Signed-off-by: Eric Anholt +--- + drivers/base/dma-contiguous.c | 1 + + drivers/gpu/drm/vc4/vc4_v3d.c | 18 ++++++++++++++++++ + mm/cma.c | 2 ++ + 3 files changed, 21 insertions(+) + +diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c +index e167a1e1bccb062efef2595fcd5299301a97df80..60f5c2591ccdb0202461458eab4035cfba731b8b 100644 +--- a/drivers/base/dma-contiguous.c ++++ b/drivers/base/dma-contiguous.c +@@ -35,6 +35,7 @@ + #endif + + struct cma *dma_contiguous_default_area; ++EXPORT_SYMBOL(dma_contiguous_default_area); + + /* + * Default global CMA area size can be defined in kernel's .config. +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index 7cc346ad9b0baed63701d1fae8f0306aa7713129..1d9e5a6edd22c29ce8b2990c9c35627aa1af2bd8 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -16,7 +16,10 @@ + * this program. If not, see . + */ + ++#include "linux/init.h" ++#include "linux/cma.h" + #include "linux/component.h" ++#include "linux/dma-contiguous.h" + #include "linux/pm_runtime.h" + #include "vc4_drv.h" + #include "vc4_regs.h" +@@ -185,8 +188,23 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_v3d *v3d = NULL; ++ struct cma *cma; + int ret; + ++ cma = dev_get_cma_area(dev); ++ if (!cma) ++ return -EINVAL; ++ ++ if ((cma_get_base(cma) & 0xf0000000) != ++ ((cma_get_base(cma) + cma_get_size(cma) - 1) & 0xf0000000)) { ++ DRM_ERROR("V3D requires that the CMA area (0x%08lx - 0x%08lx) " ++ "not span a 256MB boundary, or memory corruption " ++ "would happen.\n", ++ (long)cma_get_base(cma), ++ cma_get_base(cma) + cma_get_size(cma)); ++ return -EINVAL; ++ } ++ + v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); + if (!v3d) + return -ENOMEM; +diff --git a/mm/cma.c b/mm/cma.c +index c960459eda7e640ea55be1d4ed80c6a9125a8877..b50245282a18bc790da0f901944c2e670ffac2d2 100644 +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -47,11 +47,13 @@ phys_addr_t cma_get_base(const struct cma *cma) + { + return PFN_PHYS(cma->base_pfn); + } ++EXPORT_SYMBOL(cma_get_base); + + unsigned long cma_get_size(const struct cma *cma) + { + return cma->count << PAGE_SHIFT; + } ++EXPORT_SYMBOL(cma_get_size); + + static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, + int align_order) + +From cae9a83b6256c761439d161f0525a4a8d3536003 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Feb 2017 09:47:11 +0000 +Subject: [PATCH 179/187] BCM270X_DT: Add SMSC ethernet controller to DT + +With an ethernet node in the DT, a suitable firmware can populate the +local-mac-address property, removing the need for a downstream patch +to the driver to read its MAC address from a module parameter. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 + + arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 + + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 + + arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 1 + + 4 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index 51f575e5d201fdfc1632e9bc8ed3bbd3e55dddcb..08bf838fab551638e898930fba7ba49b3aeefbb3 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2708.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi Model B+"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 028ef91a6c4f5d6573204635a03b912284505baa..4e6b4dd6a8d9c4f13bc865bb8ced68264162cb6c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2708.dtsi" ++#include "bcm283x-rpi-smsc9512.dtsi" + + / { + model = "Raspberry Pi Model B"; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index a4ffeff9fda62da830e674ff06c3a5394bd9d8cf..2dc0e1204e6374bbc6924e26dc4a04b68718559a 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2709.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi 2 Model B"; +diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +index d29ba72de727fe26b5a586e0bd0a41181c68ae04..78101849441679baf3624cf67a0ff7a2f1b34581 100644 +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +@@ -5,6 +5,7 @@ + #endif + + #include "bcm2710.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi 3 Model B"; + +From 8ea4ba72ff44fad758eef3756cdaf823f7005033 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Feb 2017 15:26:13 +0000 +Subject: [PATCH 180/187] brcmfmac: Mute expected startup 'errors' + +The brcmfmac WiFi driver always complains about the '00' country code +and the firmware version is reported as an error. Modify the driver to +ignore '00' silently and display firmware version at INFO level. + +Signed-off-by: Phil Elwell +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 ++ + drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 3fcb1887b2d312e050c02e9fe66ea20f48f0abcb..e2a459f7a2003cb316f29b6dace3ca975f4d7a95 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6804,6 +6804,8 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { ++ if (req->alpha2[0] == '0' && req->alpha2[1] == '0') ++ return; + brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + req->alpha2[0], req->alpha2[1]); + return; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index 4051780f64f44a5ce522babe6c371a1beb79a824..b081673abcb4aa72d70d8e0834b608f65fea16e8 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -161,7 +161,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + strsep(&ptr, "\n"); + + /* Print fw version info */ +- brcmf_err("Firmware version = %s\n", buf); ++ pr_info("Firmware version = %s\n", buf); + + /* locate firmware version number for ethtool */ + ptr = strrchr(buf, ' ') + 1; + +From 112f8f716394909b4890f754d9782067c36f76c2 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 13 Feb 2017 17:20:08 +0000 +Subject: [PATCH 181/187] clk-bcm2835: Mark used PLLs and dividers CRITICAL + +The VPU configures and relies on several PLLs and dividers. Mark all +enabled dividers and their PLLs as CRITICAL to prevent the kernel from +switching them off. + +Signed-off-by: Phil Elwell +--- + drivers/clk/bcm/clk-bcm2835.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 136e5d28f9eaeaa10d45382a0f31da9f4adb91ef..4192863778c8009aacfc9a49ee38ad1ca62a01e4 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1366,6 +1366,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + divider->div.hw.init = &init; + divider->div.table = NULL; + ++ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { ++ init.flags |= CLK_IS_CRITICAL; ++ divider->div.flags |= CLK_IS_CRITICAL; ++ } ++ + divider->cprman = cprman; + divider->data = data; + + +From 76f825cc6b7fdd30451cbb775b7cfee6921dbef4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 13 Feb 2017 17:20:08 +0000 +Subject: [PATCH 182/187] clk-bcm2835: Add claim-clocks property + +The claim-clocks property can be used to prevent PLLs and dividers +from being marked as critical. It contains a vector of clock IDs, +as defined by dt-bindings/clock/bcm2835.h. + +Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and +PLLH_PIX for the vc4_kms_v3d driver. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 14 +++++++++ + drivers/clk/bcm/clk-bcm2835.c | 34 ++++++++++++++++++++-- + 2 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index a8ef8c9051668a7477dea30aa262568c8e7f221c..c57e795824e9261e0f60bcb40d6a57241019fd91 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -5,6 +5,8 @@ + /dts-v1/; + /plugin/; + ++#include ++ + / { + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + +@@ -155,6 +157,18 @@ + }; + }; + ++ fragment@19 { ++ target = <&clocks>; ++ __overlay__ { ++ claim-clocks = < ++ BCM2835_PLLD_DSI0 ++ BCM2835_PLLD_DSI1 ++ BCM2835_PLLH_AUX ++ BCM2835_PLLH_PIX ++ >; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 4192863778c8009aacfc9a49ee38ad1ca62a01e4..6b245357e4e93c19a839eee92a82f95aec996e4e 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1298,6 +1298,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { + .debug_init = bcm2835_clock_debug_init, + }; + ++static bool bcm2835_clk_is_claimed(const char *name); ++ + static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + const struct bcm2835_pll_data *data) + { +@@ -1314,6 +1316,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + init.ops = &bcm2835_pll_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + ++ if (!bcm2835_clk_is_claimed(data->name)) ++ init.flags |= CLK_IS_CRITICAL; ++ + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return NULL; +@@ -1367,8 +1372,10 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + divider->div.table = NULL; + + if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { +- init.flags |= CLK_IS_CRITICAL; +- divider->div.flags |= CLK_IS_CRITICAL; ++ if (!bcm2835_clk_is_claimed(data->source_pll)) ++ init.flags |= CLK_IS_CRITICAL; ++ if (!bcm2835_clk_is_claimed(data->name)) ++ divider->div.flags |= CLK_IS_CRITICAL; + } + + divider->cprman = cprman; +@@ -2104,6 +2111,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_PERIICTL), + }; + ++static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)]; ++ + /* + * Permanently take a reference on the parent of the SDRAM clock. + * +@@ -2123,6 +2132,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) + return clk_prepare_enable(parent); + } + ++static bool bcm2835_clk_is_claimed(const char *name) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { ++ const char *clk_name = *(const char **)(clk_desc_array[i].data); ++ if (!strcmp(name, clk_name)) ++ return bcm2835_clk_claimed[i]; ++ } ++ ++ return false; ++} ++ + static int bcm2835_clk_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -2132,6 +2154,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + const struct bcm2835_clk_desc *desc; + const size_t asize = ARRAY_SIZE(clk_desc_array); + size_t i; ++ u32 clk_id; + int ret; + + cprman = devm_kzalloc(dev, sizeof(*cprman) + +@@ -2147,6 +2170,13 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + if (IS_ERR(cprman->regs)) + return PTR_ERR(cprman->regs); + ++ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); ++ for (i = 0; ++ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", ++ i, &clk_id); ++ i++) ++ bcm2835_clk_claimed[clk_id]= true; ++ + memcpy(cprman->real_parent_names, cprman_parent_names, + sizeof(cprman_parent_names)); + of_clk_parent_fill(dev->of_node, cprman->real_parent_names, + +From 31bb9062dbef3f4899cc3479f467b3dcf1d2658b Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 20 Feb 2017 20:01:16 +0100 +Subject: [PATCH 183/187] dmaengine: bcm2835: Fix cyclic DMA period splitting + +The code responsible for splitting periods into chunks that +can be handled by the DMA controller missed to update total_len, +the number of bytes processed in the current period, when there +are more chunks to follow. + +Therefore total_len was stuck at 0 and the code didn't work at all. +This resulted in a wrong control block layout and audio issues because +the cyclic DMA callback wasn't executing on period boundaries. + +Fix this by adding the missing total_len update. + +Signed-off-by: Matthias Reichl +Signed-off-by: Martin Sperl +Tested-by: Clive Messer +Reviewed-by: Eric Anholt +--- + drivers/dma/bcm2835-dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c +index 80d35f760b4a4a51e60c355a84d538bac3892a4d..599c218dc8a73172dd4bd4a058fc8f95a73f982f 100644 +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -253,8 +253,11 @@ static void bcm2835_dma_create_cb_set_length( + */ + + /* have we filled in period_length yet? */ +- if (*total_len + control_block->length < period_len) ++ if (*total_len + control_block->length < period_len) { ++ /* update number of bytes in this period so far */ ++ *total_len += control_block->length; + return; ++ } + + /* calculate the length that remains to reach period_length */ + control_block->length = period_len - *total_len; + +From c283874273d029c659a834d2c598a76e43f2dce1 Mon Sep 17 00:00:00 2001 +From: Scott Ellis +Date: Thu, 23 Feb 2017 11:56:20 -0500 +Subject: [PATCH 184/187] Add ads1015 driver to config + +--- + arch/arm/configs/bcm2709_defconfig | 3 ++- + arch/arm/configs/bcmrpi_defconfig | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 669edd7544d79838d9471fbe11b803c342f195df..f251cf76bb080e19fba11d3900a8e81c79c4f67a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -653,6 +653,7 @@ CONFIG_HWMON=m + CONFIG_SENSORS_LM75=m + CONFIG_SENSORS_SHT21=m + CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_ADS1015=m + CONFIG_SENSORS_INA2XX=m + CONFIG_THERMAL=y + CONFIG_THERMAL_BCM2835=y +@@ -833,9 +834,9 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_UDL=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +-CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 9a9cd1cdcb2f76d4408568681ec80885293bae48..554fed3a4fbfd1940422b808046c6d2b1f508394 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -647,6 +647,7 @@ CONFIG_HWMON=m + CONFIG_SENSORS_LM75=m + CONFIG_SENSORS_SHT21=m + CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_ADS1015=m + CONFIG_SENSORS_INA2XX=m + CONFIG_THERMAL=y + CONFIG_THERMAL_BCM2835=y +@@ -827,9 +828,9 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_UDL=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +-CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + +From e4a1aa30f5d5f63f6833a7d0a4729cb77cff2299 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 27 Jan 2017 18:49:30 +0000 +Subject: [PATCH 185/187] config: add slcan kernel module + +See: https://github.com/raspberrypi/linux/issues/1819 +--- + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index f251cf76bb080e19fba11d3900a8e81c79c4f67a..843d8fdb6cc95720267ea5ec7edb8802d10a77f0 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -361,6 +361,7 @@ CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m + CONFIG_CAN=m + CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m + CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 554fed3a4fbfd1940422b808046c6d2b1f508394..99888182259b280790a7506b248a8130e1041d41 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -357,6 +357,7 @@ CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m + CONFIG_CAN=m + CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m + CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + +From d71f78106b46a879302ccebab9cd45b05d11fb14 Mon Sep 17 00:00:00 2001 +From: Miquel +Date: Fri, 24 Feb 2017 20:51:06 +0100 +Subject: [PATCH 186/187] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT + +Signed-off-by: Miquel Blauw +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 19 +++++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + sound/soc/bcm/Kconfig | 7 ++ + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/dionaudio_loco-v2.c | 140 ++++++++++++++++++++++++++++++++++++ + 7 files changed, 171 insertions(+) + create mode 100644 sound/soc/bcm/dionaudio_loco-v2.c + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 0a7d30cd573060964bb081ee6617d5b77a17b974..8856139d061472311b7cead0641b5645ef33caad 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -13,6 +13,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + bmp085_i2c-sensor.dtbo \ + dht11.dtbo \ + dionaudio-loco.dtbo \ ++ dionaudio-loco-v2.dtbo \ + dpi18.dtbo \ + dpi24.dtbo \ + dwc-otg.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 46228fd324fc4c52eb0ba50316b4c02f8245bf04..c9845ba37018b821d7e5093e15a06721318b558f 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -308,6 +308,25 @@ Load: dtoverlay=dionaudio-loco + Params: + + ++Name: dionaudio-loco-v2 ++Info: Configures the Dion Audio LOCO-V2 DAC-AMP ++Load: dtoverlay=dionaudio-loco-v2,= ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ Digital volume control. Enable with ++ "dtoverlay=hifiberry-dacplus,24db_digital_gain" ++ (The default behaviour is that the Digital ++ volume control is limited to a maximum of ++ 0dB. ie. it can attenuate but not provide ++ gain. For most users, this will be desired ++ as it will prevent clipping. By appending ++ the 24dB_digital_gain parameter, the Digital ++ volume control will allow up to 24dB of ++ gain. If this parameter is enabled, it is the ++ responsibility of the user to ensure that ++ the Digital volume control is set to a value ++ that does not result in clipping/distortion!) ++ ++ + Name: dpi18 + Info: Overlay for a generic 18-bit DPI display + This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 843d8fdb6cc95720267ea5ec7edb8802d10a77f0..7d31052cfd1d87f7488d3b8ffa1a476d8dc9f275 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -889,6 +889,7 @@ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m + CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m + CONFIG_SND_DIGIDAC1_SOUNDCARD=m + CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m ++CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m + CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m + CONFIG_SND_PISOUND=m + CONFIG_SND_SOC_ADAU1701=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 99888182259b280790a7506b248a8130e1041d41..2abbcad49833dc2fb1bf98f3258d625ee58577f9 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -883,6 +883,7 @@ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m + CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m + CONFIG_SND_DIGIDAC1_SOUNDCARD=m + CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m ++CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m + CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m + CONFIG_SND_PISOUND=m + CONFIG_SND_SOC_ADAU1701=m +diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig +index 10f6b201777946af8e8e78d2ffb0b0cff38093df..ba5cb8eed455962cc9840e7a8088fddadd49f5e3 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -133,6 +133,13 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO + help + Say Y or M if you want to add support for Dion Audio LOCO. + ++config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2 ++ tristate "Support for Dion Audio LOCO-V2 DAC-AMP" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_PCM5122 ++ help ++ Say Y or M if you want to add support for Dion Audio LOCO-V2. ++ + config SND_BCM2708_SOC_ALLO_PIANO_DAC + tristate "Support for Allo Piano DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index 84c2b20ce2e51b525797ee58de95734ee7847e15..4d8adf691021a974310589e92e599924811f22cb 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -25,6 +25,7 @@ snd-soc-raspidac3-objs := raspidac3.o + snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o + snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o + snd-soc-dionaudio-loco-objs := dionaudio_loco.o ++snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o + snd-soc-allo-piano-dac-objs := allo-piano-dac.o + snd-soc-pisound-objs := pisound.o + +@@ -44,5 +45,6 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o + obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o + obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o + obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o ++obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o + obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o + obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o +diff --git a/sound/soc/bcm/dionaudio_loco-v2.c b/sound/soc/bcm/dionaudio_loco-v2.c +new file mode 100644 +index 0000000000000000000000000000000000000000..a009c49477972a9832175d86f201b0357a08f7c0 +--- /dev/null ++++ b/sound/soc/bcm/dionaudio_loco-v2.c +@@ -0,0 +1,140 @@ ++/* ++ * ASoC Driver for Dion Audio LOCO-V2 DAC-AMP ++ * ++ * Author: Miquel Blauw ++ * Copyright 2017 ++ * ++ * Based on the software of the RPi-DAC writen by Florian Meier ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static bool digital_gain_0db_limit = true; ++ ++static int snd_rpi_dionaudio_loco_v2_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ if (digital_gain_0db_limit) { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ ++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_dionaudio_loco_v2_hw_params( ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ unsigned int sample_bits = ++ snd_pcm_format_physical_width(params_format(params)); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_dionaudio_loco_v2_ops = { ++ .hw_params = snd_rpi_dionaudio_loco_v2_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_dionaudio_loco_v2_dai[] = { ++{ ++ .name = "DionAudio LOCO-V2", ++ .stream_name = "DionAudio LOCO-V2 DAC-AMP", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "pcm512x-hifi", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "pcm512x.1-004d", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_dionaudio_loco_v2_ops, ++ .init = snd_rpi_dionaudio_loco_v2_init, ++},}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_dionaudio_loco_v2 = { ++ .name = "Dion Audio LOCO-V2", ++ .dai_link = snd_rpi_dionaudio_loco_v2_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_v2_dai), ++}; ++ ++static int snd_rpi_dionaudio_loco_v2_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_dionaudio_loco_v2.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai = ++ &snd_rpi_dionaudio_loco_v2_dai[0]; ++ ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpu_dai_name = NULL; ++ dai->cpu_of_node = i2s_node; ++ dai->platform_name = NULL; ++ dai->platform_of_node = i2s_node; ++ } ++ ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "dionaudio,24db_digital_gain"); ++ } ++ ++ ret = snd_soc_register_card(&snd_rpi_dionaudio_loco_v2); ++ if (ret) ++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ++ ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_dionaudio_loco_v2_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_dionaudio_loco_v2); ++} ++ ++static const struct of_device_id dionaudio_of_match[] = { ++ { .compatible = "dionaudio,dionaudio-loco-v2", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dionaudio_of_match); ++ ++static struct platform_driver snd_rpi_dionaudio_loco_v2_driver = { ++ .driver = { ++ .name = "snd-rpi-dionaudio-loco-v2", ++ .owner = THIS_MODULE, ++ .of_match_table = dionaudio_of_match, ++ }, ++ .probe = snd_rpi_dionaudio_loco_v2_probe, ++ .remove = snd_rpi_dionaudio_loco_v2_remove, ++}; ++ ++module_platform_driver(snd_rpi_dionaudio_loco_v2_driver); ++ ++MODULE_AUTHOR("Miquel Blauw "); ++MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2"); ++MODULE_LICENSE("GPL v2"); + +From 77bd32f0f2f58e714ba250a1a4c6b51d3fcb3361 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sun, 26 Feb 2017 01:13:02 +0000 +Subject: [PATCH 187/187] SQUASH: Add LOCO-V2 overlay from last commit + +--- + .../dts/overlays/dionaudio-loco-v2-overlay.dts | 49 ++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..a1af93de30119734e8d14cbd454589d365a3ba10 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts +@@ -0,0 +1,49 @@ ++/* ++ * Definitions for Dion Audio LOCO-V2 DAC-AMP ++ * eg. dtoverlay=dionaudio-loco-v2 ++ * ++ * PCM5242 DAC (in software mode) and TPA3255 AMP. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&sound>; ++ frag0: __overlay__ { ++ compatible = "dionaudio,dionaudio-loco-v2"; ++ i2s-controller = <&i2s>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pcm5122@4c { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm5122"; ++ reg = <0x4d>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag0>,"dionaudio,24db_digital_gain?"; ++ }; ++}; diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index bebef04465..051688a41f 100644 --- a/projects/RPi2/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi2/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From 3df8aa3aa981f3c463d793b69fa23c5aab53fec2 Mon Sep 17 00:00:00 2001 +From 5b3bce3c7cc7c2c353709f0197c86cc09978922b Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 001/140] smsx95xx: fix crimes against truesize +Subject: [PATCH 001/187] smsx95xx: fix crimes against truesize smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. @@ -48,10 +48,10 @@ index 831aa33d078ae7d2dd57fdded5de71d1eb915f99..b77935bded8c0ff7808b00f170ff10e5 usbnet_skb_return(dev, ax_skb); } -From aefca8fa1aefb12cc7ac1862b4c6e94c1ec9e74c Mon Sep 17 00:00:00 2001 +From f1b3225d7b4b1bf55b5daf2c95a19b7565b08b52 Mon Sep 17 00:00:00 2001 From: Sam Nazarko Date: Fri, 1 Apr 2016 17:27:21 +0100 -Subject: [PATCH 002/140] smsc95xx: Experimental: Enable turbo_mode and +Subject: [PATCH 002/187] smsc95xx: Experimental: Enable turbo_mode and packetsize=2560 by default See: http://forum.kodi.tv/showthread.php?tid=285288 @@ -94,10 +94,10 @@ index b77935bded8c0ff7808b00f170ff10e594300ad0..693f163684de921404738e33244881e0 netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -From a4774fe88b0a06562a7b6c5d3181f13e7444a3f0 Mon Sep 17 00:00:00 2001 +From 1d04650c28a39de8e0e3158e17cc84c5580fa1a6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 003/140] Allow mac address to be set in smsc95xx +Subject: [PATCH 003/187] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -193,10 +193,10 @@ index 693f163684de921404738e33244881e0aab92ec9..df60c989fc229bf0aab3c27e95ccd453 eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -From 0b4480a51b80954e34605c9bf42947d97e37d1c3 Mon Sep 17 00:00:00 2001 +From 7cb0c34c77963aac8b7c282986088eb479ea3362 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 13 Mar 2015 12:43:36 +0000 -Subject: [PATCH 004/140] Protect __release_resource against resources without +Subject: [PATCH 004/187] Protect __release_resource against resources without parents Without this patch, removing a device tree overlay can crash here. @@ -224,10 +224,10 @@ index 9b5f04404152c296af3a96132f27cfc80ffa9af9..f8a9af6e6b915812be2ba2c1c2b40106 for (;;) { tmp = *p; -From 029f649c29d81583b412cb6ff5792a3cf9102a95 Mon Sep 17 00:00:00 2001 +From 1c0b6f37973324f7ce3557f57d11133d2c9372cf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Dec 2014 16:07:15 -0800 -Subject: [PATCH 005/140] mm: Remove the PFN busy warning +Subject: [PATCH 005/187] mm: Remove the PFN busy warning See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is expected sometimes when using CMA. However, that commit still spams @@ -252,10 +252,10 @@ index f4a02e240fb68acbaa0d3a0c7ac5a498c051a272..0e1fba92702858ceaf2f92a1d5fa53d5 goto done; } -From 3fad09910dafeb93a351aefa90ca4fd490f68c84 Mon Sep 17 00:00:00 2001 +From a1116c4d3195b96d0f79fbeccc9d454bc3fa967a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 4 Dec 2015 17:41:50 +0000 -Subject: [PATCH 006/140] irq-bcm2836: Prevent spurious interrupts, and trap +Subject: [PATCH 006/187] irq-bcm2836: Prevent spurious interrupts, and trap them early The old arch-specific IRQ macros included a dsb to ensure the @@ -282,10 +282,10 @@ index d96b2c947e74e3edab3917551c64fbd1ced0f34c..93e3f7660c4230c9f1dd3b195958cb49 #endif } else if (stat) { -From 0c9c73fafac86e96a1d1fb59b13aac0ce6d70692 Mon Sep 17 00:00:00 2001 +From 3ea010e54a24c8e7a8aaad6811b7864d1352ed63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 12 Jun 2015 19:01:05 +0200 -Subject: [PATCH 007/140] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 007/187] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -414,10 +414,10 @@ index 44d7c38dde479d771f3552e914bf8c1c1f5019f7..42ff5e6a8e0d532f5b60a1e7af7cc4d9 } -From 3b662c4466e336bab7ebb438b65bd5487d30305d Mon Sep 17 00:00:00 2001 +From c91bab759ca14e6ed6ff31b71f104c7535fa69f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Oct 2015 16:26:55 +0200 -Subject: [PATCH 008/140] irqchip: irq-bcm2835: Add 2836 FIQ support +Subject: [PATCH 008/187] irqchip: irq-bcm2835: Add 2836 FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -516,10 +516,10 @@ index 42ff5e6a8e0d532f5b60a1e7af7cc4d941bd5008..eccf6ed025299cb480884f5bcbe77abf for (b = 0; b < NR_BANKS; b++) { for (i = 0; i < bank_irqs[b]; i++) { -From 21a313f8517a1be2b0962710ffe9ad94e7334ba1 Mon Sep 17 00:00:00 2001 +From 22f4e30205024f86c31328e8fc0e6a624417a9a4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 009/140] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 009/187] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -540,10 +540,10 @@ index 2e05046f866bd01bf87edcdeff0d5b76d4d0aea7..d780491b8013a4e97fa843958964454e }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 0059a02a50c6d01a399024cad56ec5254c645fd0 Mon Sep 17 00:00:00 2001 +From 1b90d0328bad60569b3876ef844d31aca382814c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 010/140] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 010/187] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -563,10 +563,10 @@ index e8819aa20415603c80547e382838a8fa3ce54792..cf9c7d2e3f95e1a19410247a89c2e49c for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From c9d0e1314de3cde0674ef5a2c8688b1dc10b2091 Mon Sep 17 00:00:00 2001 +From de236bea6bfc0787a78afda32e0dab3dd6cf716d Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 011/140] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 011/187] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -588,10 +588,10 @@ index fa77165fab2c1348163979da507df17e7168c49b..d11e2e4ea189466e686d762cb6c6fef9 .can_sleep = false, }; -From c7ab4eb8e79ceaa923a7c9f4e14dc085a1934a29 Mon Sep 17 00:00:00 2001 +From 190101af65ca984d506d90d97a109bab83f8cb0f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 012/140] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 012/187] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -737,10 +737,10 @@ index d11e2e4ea189466e686d762cb6c6fef9111ecf8e..107ad7d58de8f8a7f55e09c9cdcf7d66 }, }; -From a5a46d240c25576b901f0afa76575c1ab4a1469a Mon Sep 17 00:00:00 2001 +From 258765d54675e739f457d478218ea3a10bee5c84 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 013/140] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 013/187] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -767,10 +767,10 @@ index 107ad7d58de8f8a7f55e09c9cdcf7d66fa7ab66b..644bdecbcfcb79d3b84a33769265fca5 pc->irq_data[i].irqgroup = i; -From 403ea1795165839348e5953b80ec4da31b639f8e Mon Sep 17 00:00:00 2001 +From dd4ea5e4cac6ee63d4f97a9cddc1c5d52ec87c5b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 May 2016 12:32:47 +0100 -Subject: [PATCH 014/140] pinctrl-bcm2835: Return pins to inputs when freed +Subject: [PATCH 014/187] pinctrl-bcm2835: Return pins to inputs when freed When dynamically unloading overlays, it is important that freed pins are restored to being inputs to prevent functions from being enabled in @@ -811,10 +811,10 @@ index 644bdecbcfcb79d3b84a33769265fca5d3d0c9e5..81a66cba2ab0f7e3ae179de7edd10122 .get_function_name = bcm2835_pmx_get_function_name, .get_function_groups = bcm2835_pmx_get_function_groups, -From d4a8fe93bffd4cab698a2630ee7125da93d55d8a Mon Sep 17 00:00:00 2001 +From 6c2da0e15244836a68c33f3c661bed8c7395d102 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 015/140] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 015/187] spi-bcm2835: Support pin groups other than 7-11 The spi-bcm2835 driver automatically uses GPIO chip-selects due to some unreliability of the native ones. In doing so it chooses the @@ -895,10 +895,10 @@ index f35cc10772f6670397ea923ad30158270dd68578..5dfe20ffc2866fa6789825016c585175 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From fa79e1013557f418119bd9dd2c0cf4c51eb4c093 Mon Sep 17 00:00:00 2001 +From bfe6009cfa1d1d3bafd5178c7e57a7a5d1ce3ee6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 016/140] spi-bcm2835: Disable forced software CS +Subject: [PATCH 016/187] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -932,10 +932,10 @@ index 5dfe20ffc2866fa6789825016c585175a29705b6..8493474d286f7a1ac6454a22c61c8c2c return 0; } -From 85bb42acd1c5a045d372d187c26b77c6bf1b617a Mon Sep 17 00:00:00 2001 +From f8573fdb3818a34ffb20e355e886b1714bc26619 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Nov 2016 21:35:38 +0000 -Subject: [PATCH 017/140] spi-bcm2835: Remove unused code +Subject: [PATCH 017/187] spi-bcm2835: Remove unused code --- drivers/spi/spi-bcm2835.c | 61 ----------------------------------------------- @@ -1023,10 +1023,10 @@ index 8493474d286f7a1ac6454a22c61c8c2cef9121bf..33d75ad38a7f77d085321ace9101900a } -From c33ee72bce07fc83e4797ebea1bce97c0b301ba2 Mon Sep 17 00:00:00 2001 +From 6444138c2aae35d68ae725f3282c412806c039c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 3 Jun 2015 12:26:13 +0200 -Subject: [PATCH 018/140] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 018/187] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1079,10 +1079,10 @@ index 0c1edfc98696da0e0bb7f4a18cdfbcdd27a9795d..8f152266ba9b470df2eaaed9ebcf158e static const char * const bcm2835_compat[] = { -From b4e0c1c3facd38ef5e615248c42dba90d2622257 Mon Sep 17 00:00:00 2001 +From 46b3c73e94090e79f781794efa9eb5c3baca7182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 3 Oct 2015 22:22:55 +0200 -Subject: [PATCH 019/140] dmaengine: bcm2835: Load driver early and support +Subject: [PATCH 019/187] dmaengine: bcm2835: Load driver early and support legacy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -1185,10 +1185,10 @@ index e18dc596cf2447fa9ef7e41b62d9396e29043426..80d35f760b4a4a51e60c355a84d538ba MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); -From 05f9e93200ec5d5e27c8a93f69588180cddda924 Mon Sep 17 00:00:00 2001 +From 5370c41f35ce93bf75842234ebe2e095478d70fb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jan 2016 17:25:12 +0000 -Subject: [PATCH 020/140] firmware: Updated mailbox header +Subject: [PATCH 020/187] firmware: Updated mailbox header --- include/soc/bcm2835/raspberrypi-firmware.h | 11 +++++++++++ @@ -1251,10 +1251,10 @@ index 3fb357193f09914fe21f8555a4b8613f74f22bc3..227a107214a02deadcca3db202da265e RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From c9cb54929b3466ed0da304563e22739477055d3b Mon Sep 17 00:00:00 2001 +From 69546c227775515917c1b037b28ce39307e73482 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 May 2016 17:28:18 -0700 -Subject: [PATCH 021/140] clk: bcm2835: Mark GPIO clocks enabled at boot as +Subject: [PATCH 021/187] clk: bcm2835: Mark GPIO clocks enabled at boot as critical. These divide off of PLLD_PER and are used for the ethernet and wifi @@ -1292,10 +1292,10 @@ index 3bbd2a58db470a89b870a793e59ddf9fc4f48e57..7040c6426e35c11608121893b662c601 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 6c8399fb8dcc815aa9d6b4488a519785912ea983 Mon Sep 17 00:00:00 2001 +From 7682665c3927a4ad4f3826477d390a700aa9bbbe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jun 2016 16:48:41 +0100 -Subject: [PATCH 022/140] rtc: Add SPI alias for pcf2123 driver +Subject: [PATCH 022/187] rtc: Add SPI alias for pcf2123 driver Without this alias, Device Tree won't cause the driver to be loaded. @@ -1315,10 +1315,10 @@ index 8895f77726e8da5444afcd602dceff8f25a9b3fd..1833b8853ceb0e6147cceb93a00e558c MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); -From 259f169ef05f12bc7fed007befc11ed6c66dd9c8 Mon Sep 17 00:00:00 2001 +From 051fa2bc6b71ceb8fcf127bcdc0e9967c4bd3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 7 Oct 2016 16:50:59 +0200 -Subject: [PATCH 023/140] watchdog: bcm2835: Support setting reboot partition +Subject: [PATCH 023/187] watchdog: bcm2835: Support setting reboot partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1442,10 +1442,10 @@ index 4dddd8298a227d64862f2e92954a465f2e44b3f6..1f545e024422f59280932713e6a1b051 register_restart_handler(&wdt->restart_handler); if (pm_power_off == NULL) -From 79d93260c98e0164ca89c9f7c767528d7a3aaeae Mon Sep 17 00:00:00 2001 +From da7d9873080833fc0776c9dd62e2663654c6bd63 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 Apr 2016 19:40:12 +0100 -Subject: [PATCH 024/140] reboot: Use power off rather than busy spinning when +Subject: [PATCH 024/187] reboot: Use power off rather than busy spinning when halt is requested --- @@ -1468,10 +1468,10 @@ index 3fa867a2aae672755c6ce6448f4148c989dbf964..80dca8dcd6709034b643c6a3f35729e0 /* -From 9799ea4ba8ae1e6c586a3dd728ad75f68830e93f Mon Sep 17 00:00:00 2001 +From a5e16e1716206bbe5006cbc44bafbfd938745b94 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 9 Nov 2016 13:02:52 +0000 -Subject: [PATCH 025/140] bcm: Make RASPBERRYPI_POWER depend on PM +Subject: [PATCH 025/187] bcm: Make RASPBERRYPI_POWER depend on PM --- drivers/soc/bcm/Kconfig | 1 + @@ -1490,10 +1490,10 @@ index a39b0d58ddd0fdf0ac1cc7295f8aafb12546e226..e037a6dd79d1881a09e3ca9115782709 help This enables support for the RPi power domains which can be enabled -From 261269cc41f6b77f7264f0e44f9b9da5cc36de00 Mon Sep 17 00:00:00 2001 +From 540071d235f5bef9c51be32bedd1c50b310bcf5a Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Fri, 2 Sep 2016 16:45:27 +0100 -Subject: [PATCH 026/140] Register the clocks early during the boot process, so +Subject: [PATCH 026/187] Register the clocks early during the boot process, so that special/critical clocks can get enabled early on in the boot process avoiding the risk of disabling a clock, pll_divider or pll when a claiming driver fails to install propperly - maybe it needs to defer. @@ -1538,10 +1538,10 @@ index 7040c6426e35c11608121893b662c601cd8d6543..21e2a538ff0d0ab4e63adff9b93705f3 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver"); -From a195976d635c3672cae684d6338655aa25f6d98c Mon Sep 17 00:00:00 2001 +From 1885a738a3b5e11b5af867075b97e6fd283d90d4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 6 Dec 2016 17:05:39 +0000 -Subject: [PATCH 027/140] bcm2835-rng: Avoid initialising if already enabled +Subject: [PATCH 027/187] bcm2835-rng: Avoid initialising if already enabled Avoids the 0x40000 cycles of warmup again if firmware has already used it --- @@ -1567,10 +1567,10 @@ index 574211a495491d9d6021dcaefe4274a63ed02055..e66c0fca8c6090e32f72796c0877a1cf err = hwrng_register(&bcm2835_rng_ops); if (err) { -From 6c52812a34fa4ab0d40b57fef10d23fe2fb0768b Mon Sep 17 00:00:00 2001 +From ebd93733bef0834994066fd061e1d64ec524c3f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Aug 2016 16:28:44 +0100 -Subject: [PATCH 028/140] kbuild: Ignore dtco targets when filtering symbols +Subject: [PATCH 028/187] kbuild: Ignore dtco targets when filtering symbols --- scripts/Kbuild.include | 2 +- @@ -1590,10 +1590,10 @@ index 179219845dfcdfbeb586d12c5ec1296095d9fbf4..e0743e44f84188667a0c322e8c3d36f1 esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' -From 8ee6fd93aa3328d325524b8503714e3b4839d1b9 Mon Sep 17 00:00:00 2001 +From 517f6e19e36779402ddfae837f071613d0a07c0e Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 029/140] BCM2835_DT: Fix I2S register map +Subject: [PATCH 029/187] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -1631,10 +1631,10 @@ index 65783de0aedf3da79adc36fd077b7a89954ddb6b..a89fe4220fdc3f26f75ee66daf187554 dmas = <&dma 2>, <&dma 3>; -From 28a1aeb6b49ffdf5cb5ba9e326df962c270c1f34 Mon Sep 17 00:00:00 2001 +From 39da7256f238d3c92e4cd96a6585ceb5534e26ff Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 030/140] Main bcm2708/bcm2709 linux port +Subject: [PATCH 030/187] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1841,10 +1841,10 @@ index cfb4b4496dd9f61362dea012176c146120fada07..d9c6c217c4d6a2408abe2665bf7f2700 MODULE_AUTHOR("Lubomir Rintel "); MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); -From 4c7d2ae77def863967cbc6e73597d92fe0fb24e7 Mon Sep 17 00:00:00 2001 +From 93b5a8b8dcfe84da8fd054e50b8d1fe3dfe7c7fc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 031/140] Add dwc_otg driver +Subject: [PATCH 031/187] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -62901,10 +62901,10 @@ index 0000000000000000000000000000000000000000..cdc9963176e5a4a0d5250613b61e26c5 +test_main(); +0; -From a5db9164cfc4fdbd25b20962f3da042cdc75a4dc Mon Sep 17 00:00:00 2001 +From 39343516c1962fb3e7e035858d8b97ad6f301bc0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 032/140] bcm2708 framebuffer driver +Subject: [PATCH 032/187] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66363,10 +66363,10 @@ index 3c14e43b82fefe1d32f591d1b2f61d2cd28d0fa8..7626beb6a5bb8df601ddf0f6e6909d1f +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From 5ab35842ff7cc211dcfbf1113953778923097496 Mon Sep 17 00:00:00 2001 +From 252a798d80da007d2d636ebcb8ce481b06e3e661 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 033/140] dmaengine: Add support for BCM2708 +Subject: [PATCH 033/187] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66997,10 +66997,10 @@ index 0000000000000000000000000000000000000000..c5bfff2765be4606077e6c8af73040ec + +#endif /* _PLAT_BCM2708_DMA_H */ -From feab5b6b38842fca38720e0b2e9bfdc66d41c991 Mon Sep 17 00:00:00 2001 +From 891e1563c5b2d17a95c286e41b975cc88fc6041d Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 034/140] MMC: added alternative MMC driver +Subject: [PATCH 034/187] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -68750,10 +68750,10 @@ index 0000000000000000000000000000000000000000..4fe8d1fe44578fbefcd48f8c327ba3d0 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 3d0f0b3db1b62e5d913517ce305913cc71803ef1 Mon Sep 17 00:00:00 2001 +From 04187758f889fda7564f2ced4508a61ab561d3ec Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 035/140] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 035/187] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -71158,10 +71158,10 @@ index 0000000000000000000000000000000000000000..a9bc79bfdbb71807819dfe2d8f165144 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From f6be5bc28ee258731e13b5e917d69f601d062014 Mon Sep 17 00:00:00 2001 +From 0c952d59003067b51766f343f3808bdef9b63d12 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 May 2016 12:50:33 +0100 -Subject: [PATCH 036/140] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards +Subject: [PATCH 036/187] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards Some SD cards have been found that corrupt data when small blocks are erased. Add a quirk to indicate that ERASE should not be used, @@ -71297,10 +71297,10 @@ index 73fad83acbcb6a157587180516f9ffe7c61eb7d7..e7c9d3098ac06e3c6554fa3373a311f9 unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ -From a079bbcd1d23f00392eb79d7bcad867844f84cd9 Mon Sep 17 00:00:00 2001 +From d3833aa3ee47d3efd66073d4696567be1e21481e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 037/140] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 037/187] cma: Add vc_cma driver to enable use of CMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -72636,10 +72636,10 @@ index 0000000000000000000000000000000000000000..be2819d5d41f9d5ed65daf8eedb94c9e + +#endif /* VC_CMA_H */ -From 340dfdd9f8dfad3f60665cac7f19d774c001b0de Mon Sep 17 00:00:00 2001 +From a6713fca54e802f6585314cf3a9d408b6fd6a5cd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 038/140] bcm2708: alsa sound driver +Subject: [PATCH 038/187] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75374,10 +75374,10 @@ index 0000000000000000000000000000000000000000..af3e6eb690113fc32ce9e06bd2f0f294 + +#endif // _VC_AUDIO_DEFS_H_ -From 079c7a4a324b1baa4e727c9e3dfacf503345bb18 Mon Sep 17 00:00:00 2001 +From df6bec6bf36ad61d9f5a468cdc6d86b5b5087ffb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 28 Oct 2016 15:36:43 +0100 -Subject: [PATCH 039/140] vc_mem: Add vc_mem driver for querying firmware +Subject: [PATCH 039/187] vc_mem: Add vc_mem driver for querying firmware memory addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -75901,10 +75901,10 @@ index 0000000000000000000000000000000000000000..20a475377eb3078ea1ecaef2b24efc35 + +#endif /* _VC_MEM_H */ -From 148da7d48af0416c716b0103bcc14d01cc97d09b Mon Sep 17 00:00:00 2001 +From 6fba2c3459adf4e1d4a621da9b5afad5a619ba61 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 040/140] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 040/187] vcsm: VideoCore shared memory service for BCM2835 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -80311,10 +80311,10 @@ index 0000000000000000000000000000000000000000..334f36d0d697b047df2922b5f2db67f3 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ -From f035c5328fecc8970b9a9713cd345d56f5e81f98 Mon Sep 17 00:00:00 2001 +From 60c74f5fe52b96703e250e1a24feee4087af7ae4 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 041/140] Add /dev/gpiomem device for rootless user GPIO access +Subject: [PATCH 041/187] Add /dev/gpiomem device for rootless user GPIO access Signed-off-by: Luke Wren @@ -80625,10 +80625,10 @@ index 0000000000000000000000000000000000000000..911f5b7393ed48ceed8751f06967ae64 +MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); +MODULE_AUTHOR("Luke Wren "); -From ddedd1f135c5311bb4615dda5b285ce688cc50d4 Mon Sep 17 00:00:00 2001 +From 15610d99528e08cd09431d4fb8e096f8a1429c30 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 042/140] Add SMI driver +Subject: [PATCH 042/187] Add SMI driver Signed-off-by: Luke Wren --- @@ -82579,10 +82579,10 @@ index 0000000000000000000000000000000000000000..ee3a75edfc033eeb0d90a687ffb68b10 + +#endif /* BCM2835_SMI_H */ -From 6e5058f6cb203dd31935ba03eeff0d98c7531bcf Mon Sep 17 00:00:00 2001 +From c1fc2e3713740d34d3ebffa23562f5517a11e856 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 26 Apr 2016 14:59:21 +0000 -Subject: [PATCH 043/140] MISC: bcm2835: smi: use clock manager and fix reload +Subject: [PATCH 043/187] MISC: bcm2835: smi: use clock manager and fix reload issues Use clock manager instead of self-made clockmanager. @@ -82752,10 +82752,10 @@ index 63a4ea08b9930a3a31a985f0a1d969b488ed49ec..1261540703127d1d63b9f3c87042c6e5 return 0; } -From 83148030b231764e7a5fc14bd2c9ccc6a104a872 Mon Sep 17 00:00:00 2001 +From e33564f1fb6810986eea99d15e1dcfb08854db26 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 044/140] Add SMI NAND driver +Subject: [PATCH 044/187] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -83120,10 +83120,10 @@ index 0000000000000000000000000000000000000000..02adda6da18bd0ba9ab19a104975b79d + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From e12517458be7d5ec0eccc2c23db2b78badd54587 Mon Sep 17 00:00:00 2001 +From fe1ebea96978a74e9d6629319d75e909a2939568 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 045/140] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 045/187] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -83986,10 +83986,10 @@ index 0000000000000000000000000000000000000000..fb69624ccef00ddbdccf8256d6baf1b1 + +#endif -From 91eeb6693671b5ae0220f4a276b84e6597266cb9 Mon Sep 17 00:00:00 2001 +From 4a06b6a752541356b941a1456561d6919ce271de Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 046/140] Add cpufreq driver +Subject: [PATCH 046/187] Add cpufreq driver Signed-off-by: popcornmix --- @@ -84256,10 +84256,10 @@ index 0000000000000000000000000000000000000000..414fbdc10dfbfc6e4bb47870a7af3fd5 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From c83d1bbc2d9feaf23252482682824babbbd7bbd9 Mon Sep 17 00:00:00 2001 +From 55f87fdafb41219c6dfe09205b99995f04344afc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 047/140] Added hwmon/thermal driver for reporting core +Subject: [PATCH 047/187] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -84425,10 +84425,10 @@ index 0000000000000000000000000000000000000000..c63fb9f9d143e19612a18fe530c7b2b3 +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip"); +MODULE_LICENSE("GPL"); -From d34838cfa7c139fa069b7e038d3ea2b56c50a353 Mon Sep 17 00:00:00 2001 +From 7364dbd24a0a0dabf31282739cef4e8e525180b4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 048/140] Add Chris Boot's i2c driver +Subject: [PATCH 048/187] Add Chris Boot's i2c driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85093,10 +85093,10 @@ index 0000000000000000000000000000000000000000..962f2e5c7455d91bf32925d785f5f16b +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From e826eaf145a568f477ab9e5554a563233ad7fb49 Mon Sep 17 00:00:00 2001 +From 3e28d525179e460d15f4597ac3ba3cb3dd5c0654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:27:06 +0200 -Subject: [PATCH 049/140] char: broadcom: Add vcio module +Subject: [PATCH 049/187] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85322,10 +85322,10 @@ index 0000000000000000000000000000000000000000..c19bc2075c77879563ef5e59038b5a14 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From 2838aca7eb2ef14cb94ac43921fc2db291af96a7 Mon Sep 17 00:00:00 2001 +From 14f966c1540fbc4564e283cd04f45ac4f7589c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:25:01 +0200 -Subject: [PATCH 050/140] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 050/187] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85408,10 +85408,10 @@ index dd506cd3a5b874f9e1acd07efb8cd151bb6145d1..3f070bd38a91511c986e3fb114b15bd4 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From 35fa034f52f341a95e10034b2f36e2af05fee117 Mon Sep 17 00:00:00 2001 +From 63c40ffcafaf4fd2b6dac73ffce0ff20fa13bfa4 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 051/140] bcm2835: add v4l2 camera device +Subject: [PATCH 051/187] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -93153,10 +93153,10 @@ index 0000000000000000000000000000000000000000..9d1d11e4a53e510c04a416d92d195a7d + +#endif /* MMAL_VCHIQ_H */ -From 59799351c2a2951565e10b2ef69ccff34f94fd30 Mon Sep 17 00:00:00 2001 +From d8f6d2d3da8a446c4435eedc19eeb78a4c55dccf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 052/140] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 052/187] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -93676,10 +93676,10 @@ index 0000000000000000000000000000000000000000..60206de7fa9a49bd027c635306674a29 + return $trailer; +} -From 913a79481bedcfed6727e899ab3f5a9291328f55 Mon Sep 17 00:00:00 2001 +From e279a8b4fd6b3065f278b8dc178e21fa71b9e7ac Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 10 Aug 2015 09:49:15 +0100 -Subject: [PATCH 053/140] scripts/dtc: Update to upstream version 1.4.1 +Subject: [PATCH 053/187] scripts/dtc: Update to upstream version 1.4.1 Includes the new localfixups format. @@ -96530,10 +96530,10 @@ index ad9b05ae698b0495ecbda42ffcf4743555313a27..2595dfda020fd9e03f0beff5006f229d -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.1-g25efc119" -From 2ad7caa56296821bfab4ce0e808a0d1d2c8ac9f4 Mon Sep 17 00:00:00 2001 +From f5bb88317d954b3a76cebb7611c5695d9873fca5 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 054/140] BCM2708: Add core Device Tree support +Subject: [PATCH 054/187] BCM2708: Add core Device Tree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -106661,10 +106661,10 @@ index 0a07f9014944ed92a8e2e42983ae43be60b3e471..1967878a843461c3ff1f473b9a030eb0 # Bzip2 -From f760337032ce3078b0ecfe2ec8420bbdf173151d Mon Sep 17 00:00:00 2001 +From 2bed5e08a6bc8c22915d5794f36108b06b9d8063 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 055/140] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 055/187] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -106840,10 +106840,10 @@ index ddfcb2df3656cf0ab6aebd1fa3d624a6ec2e94e9..271563eb835f9018712e2076a88f341d /* Set LED brightness level * Must not sleep. Use brightness_set_blocking for drivers -From c19ea76c6206a3e5a897cef2da65d82c6dd76430 Mon Sep 17 00:00:00 2001 +From d4cbcc3c16c64a448532c80d64b33cf2f41696f5 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 056/140] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 056/187] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -107095,10 +107095,10 @@ index fb795c3b3c178ad3cd7c9e9e4547ffd492bac181..703fa8a70574323abe2fb32599254582 __u32 dx; /* screen-relative */ __u32 dy; -From 11db806d75a8958fb706d8a1b4e67818a04d68c7 Mon Sep 17 00:00:00 2001 +From 6bf48a366444156dea2df2500dc242cab2a45bdb Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 057/140] Speed up console framebuffer imageblit function +Subject: [PATCH 057/187] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -107307,10 +107307,10 @@ index a2bb276a8b2463eee98eb237c4647bc00cd93601..436494fba15abecb400ef28688466faf start_index, pitch_index); } else -From d387edf492067aa0d298b90829b784f640375e7c Mon Sep 17 00:00:00 2001 +From 0e0fdde1881539adf417ed1ac11b8b48c7094b59 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 058/140] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 058/187] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -107560,10 +107560,10 @@ index d58594a3232492e33f1dd4babd3798b03e0f0203..feae94256256316fd9d850c3d83325af unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 06dbec311ec4beeac31e1567b5ca499210d1f21e Mon Sep 17 00:00:00 2001 +From 1859374c090dd68d2a7bbbc582e83fa48488db2e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 059/140] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 059/187] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -107571,10 +107571,10 @@ Subject: [PATCH 059/140] config: Enable CONFIG_MEMCG, but leave it disabled 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce0496c69d 100644 +index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b811f26343 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c -@@ -5629,7 +5629,7 @@ int __init cgroup_init_early(void) +@@ -5626,7 +5626,7 @@ int __init cgroup_init_early(void) return 0; } @@ -107583,7 +107583,7 @@ index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce /** * cgroup_init - cgroup initialization -@@ -6166,6 +6166,28 @@ static int __init cgroup_no_v1(char *str) +@@ -6163,6 +6163,28 @@ static int __init cgroup_no_v1(char *str) } __setup("cgroup_no_v1=", cgroup_no_v1); @@ -107613,10 +107613,10 @@ index 85bc9beb046d9a6deda2e3564f4d5bd01d6fc27b..4acdbef46a8f0556469b5580a39c18ce * css_tryget_online_from_dir - get corresponding css from a cgroup dentry * @dentry: directory dentry of interest -From 5f6748b37accdf94cb360cfaa92bca5fdb0a161f Mon Sep 17 00:00:00 2001 +From 7035848318b6cc55db1b828570129c7cd23a2d2a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 060/140] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 060/187] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -107652,10 +107652,10 @@ index ae83af649a607f67239f1a64bf45dd4b5770cc7d..4a7af9d0b910f59d17421ce14138400d ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 712bd947a275fcc4a96363de2aa980111522620a Mon Sep 17 00:00:00 2001 +From 68fc43e57e288e2f60ea3e59cd277e74a3a2b109 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 061/140] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 061/187] rpi-ft5406: Add touchscreen driver for pi LCD display Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected @@ -108013,10 +108013,10 @@ index 227a107214a02deadcca3db202da265eba1fdd21..b0f6e33bd30c35664ceee057f4c3ad32 RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From e1102cfabcece5b4bbd51993bfcf5dcba5470d18 Mon Sep 17 00:00:00 2001 +From 9131e111f37da1075c3b1f3625e67e589c6e3af6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 28 Nov 2016 16:50:04 +0000 -Subject: [PATCH 062/140] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 062/187] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -109591,10 +109591,10 @@ index 333dc3c2e5ffbb2c5ab8fcfb6115b6162643cf20..46b787a6474ffa857da9b663948863ec bool "Broadcom BCM63xx DSL SoC" depends on ARCH_MULTI_V7 -From 565555340550efa6093ef922d0571d795fbce5ee Mon Sep 17 00:00:00 2001 +From 28e35276915860933d56d6054ad6dcf71810e451 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 063/140] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 063/187] gpio-poweroff: Allow it to work on Raspberry Pi The Raspberry Pi firmware manages the power-down and reboot process. To do this it installs a pm_power_off handler, causing @@ -109629,10 +109629,10 @@ index be3d81ff51cc3f510d85e4eed7a52960e51e7bc1..a030ae9fb1fca325061c093696e82186 "%s: pm_power_off function already registered", __func__); -From 2e658b6085a2f857761590e8a780cc19898f3393 Mon Sep 17 00:00:00 2001 +From d7a46aff991220634c119c16d7c55031ba08dc82 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 064/140] mfd: Add Raspberry Pi Sense HAT core driver +Subject: [PATCH 064/187] mfd: Add Raspberry Pi Sense HAT core driver --- drivers/input/joystick/Kconfig | 8 + @@ -110497,10 +110497,10 @@ index 0000000000000000000000000000000000000000..56196dc2af10e464a1e3f98b028dca1c + +#endif -From b463377320e7c95cfe9df94c1fdb7c4cb29d6f35 Mon Sep 17 00:00:00 2001 +From 22848b7aff35ce2e22d395920ac76333cfe9602e Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 065/140] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 065/187] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -110675,10 +110675,10 @@ index 0000000000000000000000000000000000000000..45f2b770ad9e67728ca599a7445d6ae9 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 13807585114080c341126a924de8217edf913e94 Mon Sep 17 00:00:00 2001 +From 7034f481906a088fdfb40bb40862b84ea9974dd0 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 25 Jan 2016 15:48:59 +0000 -Subject: [PATCH 066/140] ASoC: Add support for Rpi-DAC +Subject: [PATCH 066/187] ASoC: Add support for Rpi-DAC --- sound/soc/bcm/Kconfig | 7 +++ @@ -110962,10 +110962,10 @@ index 0000000000000000000000000000000000000000..afe1b419582aa40c4b2729d242bb13cd +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From c7d9bc61bef1c8a08f68d7e0c7685d922fd0da47 Mon Sep 17 00:00:00 2001 +From cbc5d55c367907407b52f7a66930778f6930c536 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 067/140] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 067/187] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -111014,10 +111014,10 @@ index af95d648265b3e92e345101542b332aee35191d4..513f56ba132929662802d15cdc653af3 .component_driver = { .dapm_widgets = wm8804_dapm_widgets, -From 7635da3016caa5b541a80e584a8538125e0b5299 Mon Sep 17 00:00:00 2001 +From 35a5b16cceab45a8c8d790c34aff2f2087e518c0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 068/140] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 068/187] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -111361,10 +111361,10 @@ index 0000000000000000000000000000000000000000..19dc953b7227ba86123fc7a2ba654499 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From bd440ceb58ec584d192d8c0c38c9252119be750c Mon Sep 17 00:00:00 2001 +From 88cac05c9cf1c8b8cfe2c7305aafa139fa51eb36 Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 069/140] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 069/187] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -111694,10 +111694,10 @@ index 0000000000000000000000000000000000000000..4e8e6dec14bcf4a1ff286c43742d4097 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From ab186ec6221b540210504627441a75479f04eb06 Mon Sep 17 00:00:00 2001 +From ed73721503a6da0935a3e51d5331e114250c4e89 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jul 2016 17:06:50 +0100 -Subject: [PATCH 070/140] iqaudio-dac: Compile fix - untested +Subject: [PATCH 070/187] iqaudio-dac: Compile fix - untested --- sound/soc/bcm/iqaudio-dac.c | 6 +++++- @@ -111721,10 +111721,10 @@ index 4e8e6dec14bcf4a1ff286c43742d4097249d6777..aa15bc4b49ca95edec905fddd8fd0a6d if (dapm->dev != codec_dai->dev) return 0; -From 92c77bd4247436d8160e450644faa37a0da6aad5 Mon Sep 17 00:00:00 2001 +From 541f36eeb4c4f38d428639c81e883c39268dd5e4 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 071/140] Added support for HiFiBerry DAC+ +Subject: [PATCH 071/187] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -112354,10 +112354,10 @@ index 72b19e62f6267698aea45d2410d616d91c1825cb..c6839ef6e16754ed9de2698507b8986a dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From 3247df6b45b656dc288ef26723abd9a0888ddf49 Mon Sep 17 00:00:00 2001 +From fc90457b4e4754c9669542fb77325c6089b87c89 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 072/140] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 072/187] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -112372,15 +112372,19 @@ reported correctly by a non-zero return code. HiFiBerry Amp: fix device-tree problems Some code to load the driver based on device-tree-overlays was missing. This is added by this patch. + +hifiberry-amp: Adjust for ALSA object refactoring + +See: https://github.com/raspberrypi/linux/issues/1775 --- sound/soc/bcm/Kconfig | 7 + sound/soc/bcm/Makefile | 2 + sound/soc/bcm/hifiberry_amp.c | 129 +++++++++++++++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++ + sound/soc/codecs/tas5713.c | 371 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++ - 7 files changed, 723 insertions(+) + 7 files changed, 725 insertions(+) create mode 100644 sound/soc/bcm/hifiberry_amp.c create mode 100644 sound/soc/codecs/tas5713.c create mode 100644 sound/soc/codecs/tas5713.h @@ -112404,23 +112408,24 @@ index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..b1d877407dd69c9bd6b2787b0a559f41 tristate "Support for RPi-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 203afc03167acbcad15e836209956bc5ab151157..a4838e2cf8e93c9285836f95f4151daea33e1bd1 100644 +index 203afc03167acbcad15e836209956bc5ab151157..8ffe0725ba10307b5636a252b6bb8d61ecfe2591 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,11 +12,13 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -9,12 +9,14 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o + obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o + + # BCM2708 Machine Support ++snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o -+snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c new file mode 100644 index 0000000000000000000000000000000000000000..d17c29780507dc31c50f1d567ff5cea7c8241ff5 @@ -112600,10 +112605,10 @@ index 77786e7f44a7fa22d9b5beed3eb687e2b7a28526..5a2db0d2fe2f49920eeccfecef62c969 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c new file mode 100644 -index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1eae5867411 +index 0000000000000000000000000000000000000000..560234d58a6b0a6e7fd3a63e8de73339ee002b1c --- /dev/null +++ b/sound/soc/codecs/tas5713.c -@@ -0,0 +1,369 @@ +@@ -0,0 +1,371 @@ +/* + * ASoC Driver for TAS5713 + * @@ -112838,8 +112843,10 @@ index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1ea +static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { + .probe = tas5713_probe, + .remove = tas5713_remove, -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), ++ .component_driver = { ++ .controls = tas5713_snd_controls, ++ .num_controls = ARRAY_SIZE(tas5713_snd_controls), ++ }, +}; + + @@ -113190,835 +113197,10 @@ index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8 + +#endif /* _TAS5713_H */ -From 73485d00032dc13327d26e44a0038505651b35f7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 12 Dec 2016 16:26:54 +0000 -Subject: [PATCH 073/140] Revert "Added driver for HiFiBerry Amp amplifier - add-on board" - -This reverts commit 3e6b00833d92a50cbcc9922deb6e1bc8fcdbb587. ---- - sound/soc/bcm/Kconfig | 7 - - sound/soc/bcm/Makefile | 2 - - sound/soc/bcm/hifiberry_amp.c | 129 --------------- - sound/soc/codecs/Kconfig | 4 - - sound/soc/codecs/Makefile | 2 - - sound/soc/codecs/tas5713.c | 369 ------------------------------------------ - sound/soc/codecs/tas5713.h | 210 ------------------------ - 7 files changed, 723 deletions(-) - delete mode 100644 sound/soc/bcm/hifiberry_amp.c - delete mode 100644 sound/soc/codecs/tas5713.c - delete mode 100644 sound/soc/codecs/tas5713.h - -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b1d877407dd69c9bd6b2787b0a559f4113bc21f2..4473cc728097bda0ce9fe68d4a9da348ec41f8b3 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -38,13 +38,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI - help - Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. - --config SND_BCM2708_SOC_HIFIBERRY_AMP -- tristate "Support for the HifiBerry Amp" -- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -- select SND_SOC_TAS5713 -- help -- Say Y or M if you want to add support for the HifiBerry Amp amplifier board. -- - config SND_BCM2708_SOC_RPI_DAC - tristate "Support for RPi-DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a4838e2cf8e93c9285836f95f4151daea33e1bd1..203afc03167acbcad15e836209956bc5ab151157 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -12,13 +12,11 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o --snd-soc-hifiberry-amp-objs := hifiberry_amp.o - snd-soc-rpi-dac-objs := rpi-dac.o - snd-soc-iqaudio-dac-objs := iqaudio-dac.o - - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o --obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o -diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c -deleted file mode 100644 -index d17c29780507dc31c50f1d567ff5cea7c8241ff5..0000000000000000000000000000000000000000 ---- a/sound/soc/bcm/hifiberry_amp.c -+++ /dev/null -@@ -1,129 +0,0 @@ --/* -- * ASoC Driver for HifiBerry AMP -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#include --#include -- --#include --#include --#include --#include --#include -- --static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd) --{ -- // ToDo: init of the dsp-registers. -- return 0; --} -- --static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params ) --{ -- struct snd_soc_pcm_runtime *rtd = substream->private_data; -- struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -- -- return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); --} -- --static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = { -- .hw_params = snd_rpi_hifiberry_amp_hw_params, --}; -- --static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { -- { -- .name = "HifiBerry AMP", -- .stream_name = "HifiBerry AMP HiFi", -- .cpu_dai_name = "bcm2708-i2s.0", -- .codec_dai_name = "tas5713-hifi", -- .platform_name = "bcm2708-i2s.0", -- .codec_name = "tas5713.1-001b", -- .dai_fmt = SND_SOC_DAIFMT_I2S | -- SND_SOC_DAIFMT_NB_NF | -- SND_SOC_DAIFMT_CBS_CFS, -- .ops = &snd_rpi_hifiberry_amp_ops, -- .init = snd_rpi_hifiberry_amp_init, -- }, --}; -- -- --static struct snd_soc_card snd_rpi_hifiberry_amp = { -- .name = "snd_rpi_hifiberry_amp", -- .driver_name = "HifiberryAmp", -- .owner = THIS_MODULE, -- .dai_link = snd_rpi_hifiberry_amp_dai, -- .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), --}; -- --static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = { -- { .compatible = "hifiberry,hifiberry-amp", }, -- {}, --}; --MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match); -- -- --static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) --{ -- int ret = 0; -- -- snd_rpi_hifiberry_amp.dev = &pdev->dev; -- -- if (pdev->dev.of_node) { -- struct device_node *i2s_node; -- struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0]; -- i2s_node = of_parse_phandle(pdev->dev.of_node, -- "i2s-controller", 0); -- -- if (i2s_node) { -- dai->cpu_dai_name = NULL; -- dai->cpu_of_node = i2s_node; -- dai->platform_name = NULL; -- dai->platform_of_node = i2s_node; -- } -- } -- -- ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); -- -- if (ret != 0) { -- dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -- } -- -- return ret; --} -- -- --static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev) --{ -- return snd_soc_unregister_card(&snd_rpi_hifiberry_amp); --} -- -- --static struct platform_driver snd_rpi_hifiberry_amp_driver = { -- .driver = { -- .name = "snd-hifiberry-amp", -- .owner = THIS_MODULE, -- .of_match_table = snd_rpi_hifiberry_amp_of_match, -- }, -- .probe = snd_rpi_hifiberry_amp_probe, -- .remove = snd_rpi_hifiberry_amp_remove, --}; -- -- --module_platform_driver(snd_rpi_hifiberry_amp_driver); -- -- --MODULE_AUTHOR("Sebastian Eickhoff "); --MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); --MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4..74a93e52bdc8116df3db08aaf98fffa1e6f6cc1b 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -139,7 +139,6 @@ config SND_SOC_ALL_CODECS - select SND_SOC_TFA9879 if I2C - select SND_SOC_TLV320AIC23_I2C if I2C - select SND_SOC_TLV320AIC23_SPI if SPI_MASTER -- select SND_SOC_TAS5713 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC31XX if I2C - select SND_SOC_TLV320AIC32X4_I2C if I2C -@@ -822,9 +821,6 @@ config SND_SOC_TFA9879 - tristate "NXP Semiconductors TFA9879 amplifier" - depends on I2C - --config SND_SOC_TAS5713 -- tristate -- - config SND_SOC_TLV320AIC23 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 5a2db0d2fe2f49920eeccfecef62c969ae2e99a1..77786e7f44a7fa22d9b5beed3eb687e2b7a28526 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -144,7 +144,6 @@ snd-soc-tas5086-objs := tas5086.o - snd-soc-tas571x-objs := tas571x.o - snd-soc-tas5720-objs := tas5720.o - snd-soc-tfa9879-objs := tfa9879.o --snd-soc-tas5713-objs := tas5713.o - snd-soc-tlv320aic23-objs := tlv320aic23.o - snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o - snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o -@@ -367,7 +366,6 @@ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o - obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o - obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o - obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o --obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o - obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -deleted file mode 100644 -index 9b2713861dcbed751842ca29c88eb1eae5867411..0000000000000000000000000000000000000000 ---- a/sound/soc/codecs/tas5713.c -+++ /dev/null -@@ -1,369 +0,0 @@ --/* -- * ASoC Driver for TAS5713 -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include -- --#include "tas5713.h" -- -- --static struct i2c_client *i2c; -- --struct tas5713_priv { -- struct regmap *regmap; -- int mclk_div; -- struct snd_soc_codec *codec; --}; -- --static struct tas5713_priv *priv_data; -- -- -- -- --/* -- * _ _ ___ _ ___ _ _ -- * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___ -- * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-< -- * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/ -- * -- */ -- --static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1); -- -- --static const struct snd_kcontrol_new tas5713_snd_controls[] = { -- SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv), -- SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv) --}; -- -- -- -- --/* -- * __ __ _ _ ___ _ -- * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _ -- * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_| -- * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_| -- * -- */ -- --static int tas5713_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params, -- struct snd_soc_dai *dai) --{ -- u16 blen = 0x00; -- -- struct snd_soc_codec *codec; -- codec = dai->codec; -- priv_data->codec = dai->codec; -- -- switch (params_format(params)) { -- case SNDRV_PCM_FORMAT_S16_LE: -- blen = 0x03; -- break; -- case SNDRV_PCM_FORMAT_S20_3LE: -- blen = 0x1; -- break; -- case SNDRV_PCM_FORMAT_S24_LE: -- blen = 0x04; -- break; -- case SNDRV_PCM_FORMAT_S32_LE: -- blen = 0x05; -- break; -- default: -- dev_err(dai->dev, "Unsupported word length: %u\n", -- params_format(params)); -- return -EINVAL; -- } -- -- // set word length -- snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen); -- -- return 0; --} -- -- --static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream) --{ -- unsigned int val = 0; -- -- struct tas5713_priv *tas5713; -- struct snd_soc_codec *codec = dai->codec; -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- if (mute) { -- val = TAS5713_SOFT_MUTE_ALL; -- } -- -- return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val); --} -- -- --static const struct snd_soc_dai_ops tas5713_dai_ops = { -- .hw_params = tas5713_hw_params, -- .mute_stream = tas5713_mute_stream, --}; -- -- --static struct snd_soc_dai_driver tas5713_dai = { -- .name = "tas5713-hifi", -- .playback = { -- .stream_name = "Playback", -- .channels_min = 2, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_48000, -- .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ), -- }, -- .ops = &tas5713_dai_ops, --}; -- -- -- -- --/* -- * ___ _ ___ _ -- * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _ -- * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_| -- * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_| -- * -- */ -- --static int tas5713_remove(struct snd_soc_codec *codec) --{ -- struct tas5713_priv *tas5713; -- -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- return 0; --} -- -- --static int tas5713_probe(struct snd_soc_codec *codec) --{ -- struct tas5713_priv *tas5713; -- int i, ret; -- -- i2c = container_of(codec->dev, struct i2c_client, dev); -- -- tas5713 = snd_soc_codec_get_drvdata(codec); -- -- // Reset error -- ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -- if (ret < 0) return ret; -- -- // Trim oscillator -- ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00); -- if (ret < 0) return ret; -- msleep(1000); -- -- // Reset error -- ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -- if (ret < 0) return ret; -- -- // Clock mode: 44/48kHz, MCLK=64xfs -- ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60); -- if (ret < 0) return ret; -- -- // I2S 24bit -- ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05); -- if (ret < 0) return ret; -- -- // Unmute -- ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -- if (ret < 0) return ret; -- ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00); -- if (ret < 0) return ret; -- -- // Set volume to 0db -- ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00); -- if (ret < 0) return ret; -- -- // Now start programming the default initialization sequence -- for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) { -- ret = i2c_master_send(i2c, -- tas5713_init_sequence[i].data, -- tas5713_init_sequence[i].size); -- if (ret < 0) { -- printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret); -- } -- } -- -- // Unmute -- ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -- if (ret < 0) return ret; -- -- return 0; --} -- -- --static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { -- .probe = tas5713_probe, -- .remove = tas5713_remove, -- .controls = tas5713_snd_controls, -- .num_controls = ARRAY_SIZE(tas5713_snd_controls), --}; -- -- -- -- --/* -- * ___ ___ ___ ___ _ -- * |_ _|_ ) __| | \ _ _(_)_ _____ _ _ -- * | | / / (__ | |) | '_| \ V / -_) '_| -- * |___/___\___| |___/|_| |_|\_/\___|_| -- * -- */ -- --static const struct reg_default tas5713_reg_defaults[] = { -- { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB -- { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB -- { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB -- { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB --}; -- -- --static bool tas5713_reg_volatile(struct device *dev, unsigned int reg) --{ -- switch (reg) { -- case TAS5713_DEVICE_ID: -- case TAS5713_ERROR_STATUS: -- return true; -- default: -- return false; -- } --} -- -- --static const struct of_device_id tas5713_of_match[] = { -- { .compatible = "ti,tas5713", }, -- { } --}; --MODULE_DEVICE_TABLE(of, tas5713_of_match); -- -- --static struct regmap_config tas5713_regmap_config = { -- .reg_bits = 8, -- .val_bits = 8, -- -- .max_register = TAS5713_MAX_REGISTER, -- .volatile_reg = tas5713_reg_volatile, -- -- .cache_type = REGCACHE_RBTREE, -- .reg_defaults = tas5713_reg_defaults, -- .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults), --}; -- -- --static int tas5713_i2c_probe(struct i2c_client *i2c, -- const struct i2c_device_id *id) --{ -- int ret; -- -- priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL); -- if (!priv_data) -- return -ENOMEM; -- -- priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config); -- if (IS_ERR(priv_data->regmap)) { -- ret = PTR_ERR(priv_data->regmap); -- return ret; -- } -- -- i2c_set_clientdata(i2c, priv_data); -- -- ret = snd_soc_register_codec(&i2c->dev, -- &soc_codec_dev_tas5713, &tas5713_dai, 1); -- -- return ret; --} -- -- --static int tas5713_i2c_remove(struct i2c_client *i2c) --{ -- snd_soc_unregister_codec(&i2c->dev); -- i2c_set_clientdata(i2c, NULL); -- -- kfree(priv_data); -- -- return 0; --} -- -- --static const struct i2c_device_id tas5713_i2c_id[] = { -- { "tas5713", 0 }, -- { } --}; -- --MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id); -- -- --static struct i2c_driver tas5713_i2c_driver = { -- .driver = { -- .name = "tas5713", -- .owner = THIS_MODULE, -- .of_match_table = tas5713_of_match, -- }, -- .probe = tas5713_i2c_probe, -- .remove = tas5713_i2c_remove, -- .id_table = tas5713_i2c_id --}; -- -- --static int __init tas5713_modinit(void) --{ -- int ret = 0; -- -- ret = i2c_add_driver(&tas5713_i2c_driver); -- if (ret) { -- printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n", -- ret); -- } -- -- return ret; --} --module_init(tas5713_modinit); -- -- --static void __exit tas5713_exit(void) --{ -- i2c_del_driver(&tas5713_i2c_driver); --} --module_exit(tas5713_exit); -- -- --MODULE_AUTHOR("Sebastian Eickhoff "); --MODULE_DESCRIPTION("ASoC driver for TAS5713"); --MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/tas5713.h b/sound/soc/codecs/tas5713.h -deleted file mode 100644 -index 8f019e04898754d2f87e9630137be9e8f612a342..0000000000000000000000000000000000000000 ---- a/sound/soc/codecs/tas5713.h -+++ /dev/null -@@ -1,210 +0,0 @@ --/* -- * ASoC Driver for TAS5713 -- * -- * Author: Sebastian Eickhoff -- * Copyright 2014 -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License -- * version 2 as published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- */ -- --#ifndef _TAS5713_H --#define _TAS5713_H -- -- --// TAS5713 I2C-bus register addresses -- --#define TAS5713_CLOCK_CTRL 0x00 --#define TAS5713_DEVICE_ID 0x01 --#define TAS5713_ERROR_STATUS 0x02 --#define TAS5713_SYSTEM_CTRL1 0x03 --#define TAS5713_SERIAL_DATA_INTERFACE 0x04 --#define TAS5713_SYSTEM_CTRL2 0x05 --#define TAS5713_SOFT_MUTE 0x06 --#define TAS5713_VOL_MASTER 0x07 --#define TAS5713_VOL_CH1 0x08 --#define TAS5713_VOL_CH2 0x09 --#define TAS5713_VOL_HEADPHONE 0x0A --#define TAS5713_VOL_CONFIG 0x0E --#define TAS5713_MODULATION_LIMIT 0x10 --#define TAS5713_IC_DLY_CH1 0x11 --#define TAS5713_IC_DLY_CH2 0x12 --#define TAS5713_IC_DLY_CH3 0x13 --#define TAS5713_IC_DLY_CH4 0x14 -- --#define TAS5713_START_STOP_PERIOD 0x1A --#define TAS5713_OSC_TRIM 0x1B --#define TAS5713_BKND_ERR 0x1C -- --#define TAS5713_INPUT_MUX 0x20 --#define TAS5713_SRC_SELECT_CH4 0x21 --#define TAS5713_PWM_MUX 0x25 -- --#define TAS5713_CH1_BQ0 0x29 --#define TAS5713_CH1_BQ1 0x2A --#define TAS5713_CH1_BQ2 0x2B --#define TAS5713_CH1_BQ3 0x2C --#define TAS5713_CH1_BQ4 0x2D --#define TAS5713_CH1_BQ5 0x2E --#define TAS5713_CH1_BQ6 0x2F --#define TAS5713_CH1_BQ7 0x58 --#define TAS5713_CH1_BQ8 0x59 -- --#define TAS5713_CH2_BQ0 0x30 --#define TAS5713_CH2_BQ1 0x31 --#define TAS5713_CH2_BQ2 0x32 --#define TAS5713_CH2_BQ3 0x33 --#define TAS5713_CH2_BQ4 0x34 --#define TAS5713_CH2_BQ5 0x35 --#define TAS5713_CH2_BQ6 0x36 --#define TAS5713_CH2_BQ7 0x5C --#define TAS5713_CH2_BQ8 0x5D -- --#define TAS5713_CH4_BQ0 0x5A --#define TAS5713_CH4_BQ1 0x5B --#define TAS5713_CH3_BQ0 0x5E --#define TAS5713_CH3_BQ1 0x5F -- --#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B --#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C --#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E --#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F --#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40 --#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43 --#define TAS5713_DRC_CTRL 0x46 -- --#define TAS5713_BANK_SW_CTRL 0x50 --#define TAS5713_CH1_OUTPUT_MIXER 0x51 --#define TAS5713_CH2_OUTPUT_MIXER 0x52 --#define TAS5713_CH1_INPUT_MIXER 0x53 --#define TAS5713_CH2_INPUT_MIXER 0x54 --#define TAS5713_OUTPUT_POST_SCALE 0x56 --#define TAS5713_OUTPUT_PRESCALE 0x57 -- --#define TAS5713_IDF_POST_SCALE 0x62 -- --#define TAS5713_CH1_INLINE_MIXER 0x70 --#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71 --#define TAS5713_CH1_R_CHANNEL_MIXER 0x72 --#define TAS5713_CH1_L_CHANNEL_MIXER 0x73 --#define TAS5713_CH2_INLINE_MIXER 0x74 --#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75 --#define TAS5713_CH2_L_CHANNEL_MIXER 0x76 --#define TAS5713_CH2_R_CHANNEL_MIXER 0x77 -- --#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8 --#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9 -- --#define TAS5713_REGISTER_COUNT 0x46 --#define TAS5713_MAX_REGISTER 0xF9 -- -- --// Bitmasks for registers --#define TAS5713_SOFT_MUTE_ALL 0x07 -- -- -- --struct tas5713_init_command { -- const int size; -- const char *const data; --}; -- --static const struct tas5713_init_command tas5713_init_sequence[] = { -- -- // Trim oscillator -- { .size = 2, .data = "\x1B\x00" }, -- // System control register 1 (0x03): block DC -- { .size = 2, .data = "\x03\x80" }, -- // Mute everything -- { .size = 2, .data = "\x05\x40" }, -- // Modulation limit register (0x10): 97.7% -- { .size = 2, .data = "\x10\x02" }, -- // Interchannel delay registers -- // (0x11, 0x12, 0x13, and 0x14): BD mode -- { .size = 2, .data = "\x11\xB8" }, -- { .size = 2, .data = "\x12\x60" }, -- { .size = 2, .data = "\x13\xA0" }, -- { .size = 2, .data = "\x14\x48" }, -- // PWM shutdown group register (0x19): no shutdown -- { .size = 2, .data = "\x19\x00" }, -- // Input multiplexer register (0x20): BD mode -- { .size = 2, .data = "\x20\x00\x89\x77\x72" }, -- // PWM output mux register (0x25) -- // Channel 1 --> OUTA, channel 1 neg --> OUTB -- // Channel 2 --> OUTC, channel 2 neg --> OUTD -- { .size = 5, .data = "\x25\x01\x02\x13\x45" }, -- // DRC control (0x46): DRC off -- { .size = 5, .data = "\x46\x00\x00\x00\x00" }, -- // BKND_ERR register (0x1C): 299ms reset period -- { .size = 2, .data = "\x1C\x07" }, -- // Mute channel 3 -- { .size = 2, .data = "\x0A\xFF" }, -- // Volume configuration register (0x0E): volume slew 512 steps -- { .size = 2, .data = "\x0E\x90" }, -- // Clock control register (0x00): 44/48kHz, MCLK=64xfs -- { .size = 2, .data = "\x00\x60" }, -- // Bank switch and eq control (0x50): no bank switching -- { .size = 5, .data = "\x50\x00\x00\x00\x00" }, -- // Volume registers (0x07, 0x08, 0x09, 0x0A) -- { .size = 2, .data = "\x07\x20" }, -- { .size = 2, .data = "\x08\x30" }, -- { .size = 2, .data = "\x09\x30" }, -- { .size = 2, .data = "\x0A\xFF" }, -- // 0x72, 0x73, 0x76, 0x77 input mixer: -- // no intermix between channels -- { .size = 5, .data = "\x72\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x73\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x76\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x77\x00\x80\x00\x00" }, -- // 0x70, 0x71, 0x74, 0x75 inline DRC mixer: -- // no inline DRC inmix -- { .size = 5, .data = "\x70\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x71\x00\x00\x00\x00" }, -- { .size = 5, .data = "\x74\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x75\x00\x00\x00\x00" }, -- // 0x56, 0x57 Output scale -- { .size = 5, .data = "\x56\x00\x80\x00\x00" }, -- { .size = 5, .data = "\x57\x00\x02\x00\x00" }, -- // 0x3B, 0x3c -- { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" }, -- { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" }, -- { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -- // 0x51, 0x52: output mixer -- { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" }, -- { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" }, -- // PEQ defaults -- { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -- { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, --}; -- -- --#endif /* _TAS5713_H */ - -From d57832b2c5b4c66930109bb8f3093c2cb7af4f07 Mon Sep 17 00:00:00 2001 +From 888492e69472efb4ee72996b3910af74eefa1ce1 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 074/140] Update ds1307 driver for device-tree support +Subject: [PATCH 073/187] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -114045,10 +113227,10 @@ index 4e31036ee2596dec93accd26f627c5b95591ae9f..b92044cf03e750afa521a93519500e9d .driver = { .name = "rtc-ds1307", -From bb9ce0a15501a541ebe0848eaac02cbb6528f18e Mon Sep 17 00:00:00 2001 +From d692e87173ff13253c5e1443ea7ba8761db07411 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 075/140] Add driver for rpi-proto +Subject: [PATCH 074/187] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -114068,10 +113250,10 @@ Signed-off-by: Waldemar Brodkorb create mode 100644 sound/soc/bcm/rpi-proto.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..ac0dbaf29b821c4b21855f22104a986f6e0849ec 100644 +index b1d877407dd69c9bd6b2787b0a559f4113bc21f2..eb5a5a14731bc7a144ac421d89e6a9f5ccfbd235 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -45,6 +45,13 @@ config SND_BCM2708_SOC_RPI_DAC +@@ -52,6 +52,13 @@ config SND_BCM2708_SOC_RPI_DAC help Say Y or M if you want to add support for RPi-DAC. @@ -114086,17 +113268,18 @@ index 4473cc728097bda0ce9fe68d4a9da348ec41f8b3..ac0dbaf29b821c4b21855f22104a986f tristate "Support for IQaudIO-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 203afc03167acbcad15e836209956bc5ab151157..3badc43cbe1fcb6972829a6d5eb3143cfa812da9 100644 +index 8ffe0725ba10307b5636a252b6bb8d61ecfe2591..5793c83cf2f53a831f5f49bb46b5bd4515d711a7 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -13,10 +13,12 @@ snd-soc-hifiberry-dac-objs := hifiberry_dac.o +@@ -14,6 +14,7 @@ snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o snd-soc-rpi-dac-objs := rpi-dac.o +snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -21,4 +22,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o @@ -114263,10 +113446,10 @@ index 0000000000000000000000000000000000000000..9db678e885efd63d84d60a098a84ed67 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From b167c67288fd6fe5abff0115b02b5a76e1b92a7b Mon Sep 17 00:00:00 2001 +From 618f202699b0a0ae85c2ae4ba2fa63614a89cd63 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 076/140] RaspiDAC3 support +Subject: [PATCH 075/187] RaspiDAC3 support Signed-off-by: Jan Grulich @@ -114284,10 +113467,10 @@ Signed-off-by: Matthias Reichl create mode 100644 sound/soc/bcm/raspidac3.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index ac0dbaf29b821c4b21855f22104a986f6e0849ec..c59c835757a51aa8ad72933d35a83b73a889477c 100644 +index eb5a5a14731bc7a144ac421d89e6a9f5ccfbd235..a2e74be19fa79e3354583b3d110ecb3286e20f3d 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -58,3 +58,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC +@@ -65,3 +65,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC select SND_SOC_PCM512x_I2C help Say Y or M if you want to add support for IQaudIO-DAC. @@ -114300,18 +113483,18 @@ index ac0dbaf29b821c4b21855f22104a986f6e0849ec..c59c835757a51aa8ad72933d35a83b73 + help + Say Y or M if you want to add support for RaspiDAC Rev.3x. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 3badc43cbe1fcb6972829a6d5eb3143cfa812da9..07d2b52376b1d16e427cf6f51cbf4779d6219ce0 100644 +index 5793c83cf2f53a831f5f49bb46b5bd4515d711a7..c078798106818e3a23f4fbb8068c9ff143b8a2c7 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -15,6 +15,7 @@ snd-soc-hifiberry-digi-objs := hifiberry_digi.o +@@ -16,6 +16,7 @@ snd-soc-hifiberry-digi-objs := hifiberry_digi.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o +snd-soc-raspidac3-objs := raspidac3.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o -@@ -22,3 +23,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o +@@ -24,3 +25,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o @@ -114509,10 +113692,10 @@ index 0000000000000000000000000000000000000000..dd9eeea2af0382307f437e6db09d1546 +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From af90a75803c25ed57bc3099fe73d5224c79a8f82 Mon Sep 17 00:00:00 2001 +From 3dfb83d89a6a376903e882e6d72bd75197298f72 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Thu, 7 Apr 2016 21:26:21 +0100 -Subject: [PATCH 077/140] Add Support for JustBoom Audio boards +Subject: [PATCH 076/187] Add Support for JustBoom Audio boards justboom-dac: Adjust for ALSA API change @@ -114530,10 +113713,10 @@ Signed-off-by: Phil Elwell create mode 100644 sound/soc/bcm/justboom-digi.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index c59c835757a51aa8ad72933d35a83b73a889477c..b2f6339c318cdfe3516d73952a5be1fd32bc1156 100644 +index a2e74be19fa79e3354583b3d110ecb3286e20f3d..1130c52314ece624a5555ec0819edf39667f3990 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -52,6 +52,20 @@ config SND_BCM2708_SOC_RPI_PROTO +@@ -59,6 +59,20 @@ config SND_BCM2708_SOC_RPI_PROTO help Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). @@ -114555,10 +113738,10 @@ index c59c835757a51aa8ad72933d35a83b73a889477c..b2f6339c318cdfe3516d73952a5be1fd tristate "Support for IQaudIO-DAC" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 07d2b52376b1d16e427cf6f51cbf4779d6219ce0..cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a 100644 +index c078798106818e3a23f4fbb8068c9ff143b8a2c7..94f5a29386d4e164be428f35d98b007f79dad663 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,6 +12,8 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -13,6 +13,8 @@ snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o @@ -114567,7 +113750,7 @@ index 07d2b52376b1d16e427cf6f51cbf4779d6219ce0..cb8ab1901b172bdee0bd9cddd2f2e7ab snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o -@@ -20,6 +22,8 @@ snd-soc-raspidac3-objs := raspidac3.o +@@ -22,6 +24,8 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o @@ -114966,10 +114149,10 @@ index 0000000000000000000000000000000000000000..91acb666380faa3c0deb2230f8a0f8bb +MODULE_DESCRIPTION("ASoC Driver for JustBoom PI Digi HAT Sound Card"); +MODULE_LICENSE("GPL v2"); -From 0c2b4b8751a7d5b17e6b819610f8a48cea1f98f6 Mon Sep 17 00:00:00 2001 +From cac71895bacf68bfa77f1af57f1a3c621cbad0fc Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Tue, 3 May 2016 22:10:59 -0400 -Subject: [PATCH 078/140] ARM: adau1977-adc: Add basic machine driver for +Subject: [PATCH 077/187] ARM: adau1977-adc: Add basic machine driver for adau1977 codec driver. This commit adds basic support for the codec usage including: Device tree overlay, @@ -114985,10 +114168,10 @@ Signed-off-by: Andrey Grodzovsky create mode 100644 sound/soc/bcm/adau1977-adc.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b2f6339c318cdfe3516d73952a5be1fd32bc1156..190a79dffa53a34c2df9b2c9b5160065c759de65 100644 +index 1130c52314ece624a5555ec0819edf39667f3990..0dbeea9227ec59e0072be4f850b11202485aa2cc 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -80,3 +80,10 @@ config SND_BCM2708_SOC_RASPIDAC3 +@@ -87,3 +87,10 @@ config SND_BCM2708_SOC_RASPIDAC3 select SND_SOC_TPA6130A2 help Say Y or M if you want to add support for RaspiDAC Rev.3x. @@ -115000,7 +114183,7 @@ index b2f6339c318cdfe3516d73952a5be1fd32bc1156..190a79dffa53a34c2df9b2c9b5160065 + help + Say Y or M if you want to add support for ADAU1977 ADC. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a..9dd0785532aae24f3366cc2910d4dbc558cb0e5d 100644 +index 94f5a29386d4e164be428f35d98b007f79dad663..8c20ce506f2b0d653be39ceb9224503a0ef63c39 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile @@ -9,6 +9,7 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o @@ -115008,17 +114191,17 @@ index cb8ab1901b172bdee0bd9cddd2f2e7ab2f36c16a..9dd0785532aae24f3366cc2910d4dbc5 # BCM2708 Machine Support +snd-soc-adau1977-adc-objs := adau1977-adc.o + snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-hifiberry-dac-objs := hifiberry_dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o -@@ -19,6 +20,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o +@@ -20,6 +21,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-raspidac3-objs := raspidac3.o +obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o diff --git a/sound/soc/bcm/adau1977-adc.c b/sound/soc/bcm/adau1977-adc.c new file mode 100644 index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d2434b0e1 @@ -115151,10 +114334,10 @@ index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d +MODULE_DESCRIPTION("ASoC Driver for ADAU1977 ADC"); +MODULE_LICENSE("GPL v2"); -From 35cd58d093a51d20d9f093eb1963fee33e6d9a07 Mon Sep 17 00:00:00 2001 +From c7210de20ddd76773a54e4cb89f3a6f361379352 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 16 May 2016 21:36:31 +1000 -Subject: [PATCH 079/140] New AudioInjector.net Pi soundcard with low jitter +Subject: [PATCH 078/187] New AudioInjector.net Pi soundcard with low jitter audio in and out. Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile. @@ -115173,10 +114356,10 @@ This patch adds headphone and microphone capability to the Audio Injector sound create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 190a79dffa53a34c2df9b2c9b5160065c759de65..eb16c3a7fb316eb5938a54dfa864f66f9b167eb0 100644 +index 0dbeea9227ec59e0072be4f850b11202485aa2cc..0ebfea3c1cbb59513741818cf65ea8ecc4767515 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -87,3 +87,10 @@ config SND_BCM2708_SOC_ADAU1977_ADC +@@ -94,3 +94,10 @@ config SND_BCM2708_SOC_ADAU1977_ADC select SND_SOC_ADAU1977_I2C help Say Y or M if you want to add support for ADAU1977 ADC. @@ -115188,18 +114371,18 @@ index 190a79dffa53a34c2df9b2c9b5160065c759de65..eb16c3a7fb316eb5938a54dfa864f66f + help + Say Y or M if you want to add support for audioinjector.net Pi Hat diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 9dd0785532aae24f3366cc2910d4dbc558cb0e5d..a68469644535a38305bb5b0f3780e03e0ca4f519 100644 +index 8c20ce506f2b0d653be39ceb9224503a0ef63c39..4d4189b6d0c57645c5ec19554f1e77d4ccc716d6 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -19,6 +19,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o +@@ -20,6 +20,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-raspidac3-objs := raspidac3.o +snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -30,3 +31,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -32,3 +33,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o @@ -115405,10 +114588,10 @@ index 0000000000000000000000000000000000000000..ef54e0f07ea03f59e9957b5d98f3e7fd +MODULE_ALIAS("platform:audioinjector-pi-soundcard"); + -From fc549ae82d8c88a4b51d129b4ed5f4aa1ef55b62 Mon Sep 17 00:00:00 2001 +From d2611b7c324fff94443f868061b6651906baa155 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Thu, 30 Jun 2016 18:38:42 +0100 -Subject: [PATCH 080/140] Add IQAudIO Digi WM8804 board support +Subject: [PATCH 079/187] Add IQAudIO Digi WM8804 board support Support IQAudIO Digi board with iqaudio_digi machine driver and iqaudio-digi-wm8804-audio overlay. @@ -115425,10 +114608,10 @@ Signed-off-by: DigitalDreamtime create mode 100644 sound/soc/bcm/iqaudio_digi.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index eb16c3a7fb316eb5938a54dfa864f66f9b167eb0..9cba69ab877ef73beb2dff2f4f82d1d243f7c604 100644 +index 0ebfea3c1cbb59513741818cf65ea8ecc4767515..24723d09e7bda0c6c06292b159220b180310b12b 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -73,6 +73,13 @@ config SND_BCM2708_SOC_IQAUDIO_DAC +@@ -80,6 +80,13 @@ config SND_BCM2708_SOC_IQAUDIO_DAC help Say Y or M if you want to add support for IQaudIO-DAC. @@ -115443,10 +114626,10 @@ index eb16c3a7fb316eb5938a54dfa864f66f9b167eb0..9cba69ab877ef73beb2dff2f4f82d1d2 tristate "Support for RaspiDAC Rev.3x" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a68469644535a38305bb5b0f3780e03e0ca4f519..fa2739206b79a9f9d2e1173b2099e1156e4e08c8 100644 +index 4d4189b6d0c57645c5ec19554f1e77d4ccc716d6..ee41d6bbdbbda2913aba143a59b4953e800bdb3c 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -18,6 +18,7 @@ snd-soc-justboom-digi-objs := justboom-digi.o +@@ -19,6 +19,7 @@ snd-soc-justboom-digi-objs := justboom-digi.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o @@ -115454,7 +114637,7 @@ index a68469644535a38305bb5b0f3780e03e0ca4f519..fa2739206b79a9f9d2e1173b2099e115 snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o -@@ -30,6 +31,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o +@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o @@ -115708,10 +114891,10 @@ index 0000000000000000000000000000000000000000..9b6e829bcb5b1762a853775e78163196 +MODULE_DESCRIPTION("ASoC Driver for IQAudIO WM8804 Digi"); +MODULE_LICENSE("GPL v2"); -From bd20905a5f6f0e22433f9e56d83dc838c77d16b3 Mon Sep 17 00:00:00 2001 +From f33b80d08fc3c8155844b48da5fe553be1f41f44 Mon Sep 17 00:00:00 2001 From: escalator2015 Date: Tue, 24 May 2016 16:20:09 +0100 -Subject: [PATCH 081/140] New driver for RRA DigiDAC1 soundcard using WM8741 + +Subject: [PATCH 080/187] New driver for RRA DigiDAC1 soundcard using WM8741 + WM8804 --- @@ -115722,10 +114905,10 @@ Subject: [PATCH 081/140] New driver for RRA DigiDAC1 soundcard using WM8741 + create mode 100644 sound/soc/bcm/digidac1-soundcard.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 9cba69ab877ef73beb2dff2f4f82d1d243f7c604..2be5b64fb0d5dcad0d5747626015a6886c3c273b 100644 +index 24723d09e7bda0c6c06292b159220b180310b12b..c432ef568823787baeccd296be0c107ca8c124ab 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -101,3 +101,11 @@ config SND_AUDIOINJECTOR_PI_SOUNDCARD +@@ -108,3 +108,11 @@ config SND_AUDIOINJECTOR_PI_SOUNDCARD select SND_SOC_WM8731 help Say Y or M if you want to add support for audioinjector.net Pi Hat @@ -115738,18 +114921,18 @@ index 9cba69ab877ef73beb2dff2f4f82d1d243f7c604..2be5b64fb0d5dcad0d5747626015a688 + help + Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index fa2739206b79a9f9d2e1173b2099e1156e4e08c8..a5c30c0bdacafb2bd09b6ac2f8a3bdc6a85a8404 100644 +index ee41d6bbdbbda2913aba143a59b4953e800bdb3c..855f4dbe574fcb725b0309710611fa381e1e29d6 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -21,6 +21,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac.o +@@ -22,6 +22,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac.o snd-soc-iqaudio-digi-objs := iqaudio_digi.o snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o +snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -34,4 +35,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -36,4 +37,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o @@ -116184,10 +115367,10 @@ index 0000000000000000000000000000000000000000..446796e7e4c14a7d95b2f2a01211d9a0 +MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1"); +MODULE_LICENSE("GPL v2"); -From d769f04e989d8ca654b67d64f021982382e75f47 Mon Sep 17 00:00:00 2001 +From 4948d886046e68390cb574d40b9741681c040a11 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Sat, 2 Jul 2016 16:26:19 +0100 -Subject: [PATCH 082/140] Add support for Dion Audio LOCO DAC-AMP HAT +Subject: [PATCH 081/187] Add support for Dion Audio LOCO DAC-AMP HAT Using dedicated machine driver and pcm5102a codec driver. @@ -116200,10 +115383,10 @@ Signed-off-by: DigitalDreamtime create mode 100644 sound/soc/bcm/dionaudio_loco.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 2be5b64fb0d5dcad0d5747626015a6886c3c273b..b8cb5eb7af9b3e6d8d100926e04bfef629641d1d 100644 +index c432ef568823787baeccd296be0c107ca8c124ab..668d163c37051dddafa6ee6d0984705966c883ef 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -109,3 +109,10 @@ config SND_DIGIDAC1_SOUNDCARD +@@ -116,3 +116,10 @@ config SND_DIGIDAC1_SOUNDCARD select SND_SOC_WM8741 help Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board. @@ -116215,18 +115398,18 @@ index 2be5b64fb0d5dcad0d5747626015a6886c3c273b..b8cb5eb7af9b3e6d8d100926e04bfef6 + help + Say Y or M if you want to add support for Dion Audio LOCO. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index a5c30c0bdacafb2bd09b6ac2f8a3bdc6a85a8404..28cdf019dbc7aafda194c83817d260ad1a477666 100644 +index 855f4dbe574fcb725b0309710611fa381e1e29d6..fca9d682bbd2e7821ae01aefc7a5a94e0880a41e 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -22,6 +22,7 @@ snd-soc-iqaudio-digi-objs := iqaudio_digi.o +@@ -23,6 +23,7 @@ snd-soc-iqaudio-digi-objs := iqaudio_digi.o snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o +snd-soc-dionaudio-loco-objs := dionaudio_loco.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -36,4 +37,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -38,4 +39,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI) += snd-soc-iqaudio-digi.o obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o @@ -116360,10 +115543,10 @@ index 0000000000000000000000000000000000000000..89e65317512bc774453ac8d0d5b0ff98 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO"); +MODULE_LICENSE("GPL v2"); -From f8dbc341d0ecfa295a817771e693b2e37612c20c Mon Sep 17 00:00:00 2001 +From 852ce462975b2c46948a559739463d913ede1326 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Mon, 19 Sep 2016 14:01:04 +0100 -Subject: [PATCH 083/140] Allo Piano DAC boards: Initial 2 channel (stereo) +Subject: [PATCH 082/187] Allo Piano DAC boards: Initial 2 channel (stereo) support (#1645) Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards, @@ -116388,10 +115571,10 @@ Tested-by: Clive Messer create mode 100644 sound/soc/bcm/allo-piano-dac.c diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index b8cb5eb7af9b3e6d8d100926e04bfef629641d1d..4f0330a6c06115f077938cba3dc744d4ae10f056 100644 +index 668d163c37051dddafa6ee6d0984705966c883ef..4e83bd6b1703a0bd3de60ad8c799e0cd3bc16b66 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -116,3 +116,10 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO +@@ -123,3 +123,10 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO select SND_SOC_PCM5102a help Say Y or M if you want to add support for Dion Audio LOCO. @@ -116403,18 +115586,18 @@ index b8cb5eb7af9b3e6d8d100926e04bfef629641d1d..4f0330a6c06115f077938cba3dc744d4 + help + Say Y or M if you want to add support for Allo Piano DAC. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 28cdf019dbc7aafda194c83817d260ad1a477666..4b94a42efecaee41df37f3c59fddefa5fe78521c 100644 +index fca9d682bbd2e7821ae01aefc7a5a94e0880a41e..64f007f8ba38276a42e0bd8db92544db9412544b 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -23,6 +23,7 @@ snd-soc-raspidac3-objs := raspidac3.o +@@ -24,6 +24,7 @@ snd-soc-raspidac3-objs := raspidac3.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o snd-soc-dionaudio-loco-objs := dionaudio_loco.o +snd-soc-allo-piano-dac-objs := allo-piano-dac.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -38,3 +39,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -40,3 +41,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o @@ -116570,10 +115753,10 @@ index 0000000000000000000000000000000000000000..8e8e62e5a36a279b425ed4655cfbac99 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC"); +MODULE_LICENSE("GPL v2"); -From e1275c43efe1053a9916fb11e27b286338f87195 Mon Sep 17 00:00:00 2001 +From cd1a43e18d800ec4c2c8a7c5350bc1e13b267169 Mon Sep 17 00:00:00 2001 From: gtrainavicius Date: Sun, 23 Oct 2016 12:06:53 +0300 -Subject: [PATCH 084/140] Support for Blokas Labs pisound board +Subject: [PATCH 083/187] Support for Blokas Labs pisound board Pisound dynamic overlay (#1760) @@ -116724,10 +115907,10 @@ index 7cdfc29ba4fbffd3216376677922e7ae26019055..5197e656a3d741d14bd9dd6c812b4b93 - }; }; diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4f0330a6c06115f077938cba3dc744d4ae10f056..a0ef6a028136beb27ed13a4136712a70a60f2966 100644 +index 4e83bd6b1703a0bd3de60ad8c799e0cd3bc16b66..d024377e8450fb5402dcb5ea27161f774b04a8ec 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -123,3 +123,9 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC +@@ -130,3 +130,9 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC select SND_SOC_PCM512x_I2C help Say Y or M if you want to add support for Allo Piano DAC. @@ -116738,18 +115921,18 @@ index 4f0330a6c06115f077938cba3dc744d4ae10f056..a0ef6a028136beb27ed13a4136712a70 + help + Say Y or M if you want to add support for Blokas Labs pisound. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 4b94a42efecaee41df37f3c59fddefa5fe78521c..f720a3d3b5832844ee6d0558317c728f00c40b65 100644 +index 64f007f8ba38276a42e0bd8db92544db9412544b..bb1df438540193652ec5464e8bc51f636a1b844e 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -24,6 +24,7 @@ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o +@@ -25,6 +25,7 @@ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o snd-soc-dionaudio-loco-objs := dionaudio_loco.o snd-soc-allo-piano-dac-objs := allo-piano-dac.o +snd-soc-pisound-objs := pisound.o obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -40,3 +41,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundca + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o +@@ -42,3 +43,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundca obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o @@ -117750,10 +116933,10 @@ index 0000000000000000000000000000000000000000..4b8545487d06e4ea70073a5d063fb231 +MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound"); +MODULE_LICENSE("GPL v2"); -From cb9c788998e6d04f2095a3d079a294389886f22a Mon Sep 17 00:00:00 2001 +From 7b14e374b8add26dc1d2d883d190e43c85820325 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 085/140] rpi_display: add backlight driver and overlay +Subject: [PATCH 084/187] rpi_display: add backlight driver and overlay Add a mailbox-driven backlight controller for the Raspberry Pi DSI touchscreen display. Requires updated GPU firmware to recognise the @@ -117922,10 +117105,10 @@ index 0000000000000000000000000000000000000000..14a0d9b037395497c1fdae2961feccd5 +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); -From 1e42c44b40a1be7fc26e92375504e9008156490a Mon Sep 17 00:00:00 2001 +From 3b430599904c04d437a81f7a1c287bc6e4c35532 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Feb 2016 19:56:04 +0000 -Subject: [PATCH 086/140] bcm2835-virtgpio: Virtual GPIO driver +Subject: [PATCH 085/187] bcm2835-virtgpio: Virtual GPIO driver Add a virtual GPIO driver that uses the firmware mailbox interface to request that the VPU toggles LEDs. @@ -118199,10 +117382,10 @@ index b0f6e33bd30c35664ceee057f4c3ad32b914291d..e92278968b2b979db2a1f855f70e7aaf RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From c8452a4f0c6aecede8c8cd2e0f8d571df62f7d77 Mon Sep 17 00:00:00 2001 +From e46e675846fab8bd468653486071b72afbd6ef6b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 23 Feb 2016 17:26:48 +0000 -Subject: [PATCH 087/140] amba_pl011: Don't use DT aliases for numbering +Subject: [PATCH 086/187] amba_pl011: Don't use DT aliases for numbering The pl011 driver looks for DT aliases of the form "serial", and if found uses as the device ID. This can cause @@ -118231,10 +117414,10 @@ index e2c33b9528d82ed7a2c27d083d7b1d222da68178..5a11ff833e1fd112ba04df3a427cd94b uap->old_cr = 0; uap->port.dev = dev; -From d1429c129c393594f65f2da36b42687973498747 Mon Sep 17 00:00:00 2001 +From 6324540ac51de67caef39b5281b005c77372e74d Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 3 Dec 2014 13:23:28 +0200 -Subject: [PATCH 088/140] OF: DT-Overlay configfs interface +Subject: [PATCH 087/187] OF: DT-Overlay configfs interface This is a port of Pantelis Antoniou's v3 port that makes use of the new upstreamed configfs support for binary attributes. @@ -118666,10 +117849,10 @@ index 0000000000000000000000000000000000000000..0037e6868a6cda8706c88194c6a4454b +} +late_initcall(of_cfs_init); -From 375ba3269f5ef7044260d9ee190c936fc72c9836 Mon Sep 17 00:00:00 2001 +From bfbb95a2357ad45f96920b21216a0061d89ae04a Mon Sep 17 00:00:00 2001 From: Cheong2K Date: Fri, 26 Feb 2016 18:20:10 +0800 -Subject: [PATCH 089/140] brcm: adds support for BCM43341 wifi +Subject: [PATCH 088/187] brcm: adds support for BCM43341 wifi brcmfmac: Disable power management @@ -118832,10 +118015,10 @@ index d0407d9ad7827cd756b6311410ffe2d9a7cacc78..f1fb8a3c7a3211e8429585861f2f42e0 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 -From 5c75e3d1bc4df013f745e78385f458613bf7b32e Mon Sep 17 00:00:00 2001 +From d08b3b2e366e63348adc2ed3601f184bc00aa80c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 17 Dec 2015 13:37:07 +0000 -Subject: [PATCH 090/140] hci_h5: Don't send conf_req when ACTIVE +Subject: [PATCH 089/187] hci_h5: Don't send conf_req when ACTIVE Without this patch, a modem and kernel can continuously bombard each other with conf_req and conf_rsp messages, in a demented game of tag. @@ -118858,10 +118041,10 @@ index 0879d64b1caf58afb6e5d494c07d9ab7e7cdf983..5161ab30fd533d50f516bb93d5b9f402 if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data[2] & 0x07); -From 1fbc772f5f537bdab6e27783d6acc2d10e7aecec Mon Sep 17 00:00:00 2001 +From 3490894ce5d697151ca18d1125e865f0aa5cd499 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 091/140] config: Add default configs +Subject: [PATCH 090/187] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1297 +++++++++++++++++++++++++++++++++++ @@ -121488,10 +120671,10 @@ index 0000000000000000000000000000000000000000..8acee9f31202ec14f2933d92dd70831c +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From e565c8cc4a7024d22170905c846b8545cd7fa662 Mon Sep 17 00:00:00 2001 +From 9d9231cb2087d2b16c74d7be316aa81d23f94929 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Wed, 24 Aug 2016 03:35:56 -0700 -Subject: [PATCH 092/140] Add arm64 configuration and device tree differences. +Subject: [PATCH 091/187] Add arm64 configuration and device tree differences. Disable MMC_BCM2835_SDHOST and MMC_BCM2835 since these drivers are crashing at the moment. @@ -122906,10 +122089,10 @@ index 0000000000000000000000000000000000000000..d7406f5a4620151044b8f716b4d10bb8 +CONFIG_LIBCRC32C=y +CONFIG_BCM2708_VCHIQ=n -From 35fd48cb4edfef0dbf91800e07655db35533305a Mon Sep 17 00:00:00 2001 +From 20fb3a0e5c039dbdef223ca31bdf8e56e50ae601 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 7 Mar 2016 15:05:11 +0000 -Subject: [PATCH 093/140] vchiq_arm: Tweak the logging output +Subject: [PATCH 092/187] vchiq_arm: Tweak the logging output Signed-off-by: Phil Elwell --- @@ -122984,10 +122167,10 @@ index 2c98da4307dff994a00dc246574ef0aaee05d5da..160db24aeea33a8296923501009c1f02 switch (type) { -From 7ec1488f0ba404ea96cfee0f8f28bbdbab20a7d6 Mon Sep 17 00:00:00 2001 +From 601d9ca790405317d2d4b02bb9b88b7397bf3ddb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 14:16:25 +0000 -Subject: [PATCH 094/140] vchiq_arm: Access the dequeue_pending flag locked +Subject: [PATCH 093/187] vchiq_arm: Access the dequeue_pending flag locked Reading through this code looking for another problem (now found in userland) the use of dequeue_pending outside a lock didn't seem safe. @@ -123045,10 +122228,10 @@ index 7b6cd4d80621e38ff6d47fcd87b45fbe9cd4259b..d8669fa7f39b077877eca1829ba9538b return add_completion(instance, reason, header, user_service, -From f17f2d01f807587bb82898dad5753c74ad5e966c Mon Sep 17 00:00:00 2001 +From 2f27e6a032314fbb27c3859a96fa49fe99b53b04 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 20:53:47 +0000 -Subject: [PATCH 095/140] vchiq_arm: Service callbacks must not fail +Subject: [PATCH 094/187] vchiq_arm: Service callbacks must not fail Service callbacks are not allowed to return an error. The internal callback that delivers events and messages to user tasks does not enqueue them if @@ -123074,10 +122257,10 @@ index d8669fa7f39b077877eca1829ba9538bf2e21a82..54552c6ce54f413c9781ba279b936f98 DEBUG_TRACE(SERVICE_CALLBACK_LINE); } -From 357aa48f33262ca57a65682b9b9e70a13ecada2d Mon Sep 17 00:00:00 2001 +From c04c96f22141ed319200757d1c1dad8cbd2e3658 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 21 Apr 2016 13:49:32 +0100 -Subject: [PATCH 096/140] vchiq_arm: Add completion records under the mutex +Subject: [PATCH 095/187] vchiq_arm: Add completion records under the mutex An issue was observed when flushing openmax components which generate a large number of messages returning @@ -123140,10 +122323,10 @@ index 54552c6ce54f413c9781ba279b936f98be4f47b0..bde8955b7d8505d73579b77b5b392154 return VCHIQ_SUCCESS; -From e55fbce2a8a409274e1f13ceceb9fa856f3241bf Mon Sep 17 00:00:00 2001 +From 5305ba9a2ed0c51be45ee36fa9c547413341612c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jun 2016 13:51:44 +0100 -Subject: [PATCH 097/140] vchiq_arm: Avoid use of mutex in add_completion +Subject: [PATCH 096/187] vchiq_arm: Avoid use of mutex in add_completion Claiming the completion_mutex within add_completion did prevent some messages appearing twice, but provokes a deadlock caused by vcsm using @@ -123337,10 +122520,10 @@ index 160db24aeea33a8296923501009c1f02bc41e599..71a3bedc55314f3b22dbff40c05dedf0 up(&state->slot_available_event); } -From 79c80fcffa0edd56fd39cde6225a8595d20b8e13 Mon Sep 17 00:00:00 2001 +From 3f088bf35e3319a4efcf593c7eb717429f59c783 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:14:10 -0700 -Subject: [PATCH 098/140] staging/vchi: Convert to current get_user_pages() +Subject: [PATCH 097/187] staging/vchi: Convert to current get_user_pages() arguments. Signed-off-by: Eric Anholt @@ -123377,10 +122560,10 @@ index e5cdda12c7e5c35c69eb96991cfdb8326def167f..085d37588c59198b4e5f00b9249bb842 num_pages, /* len */ 0, /* gup_flags */ -From 1e387fd101bc3670fe99c7470ccce6a0a73a82ef Mon Sep 17 00:00:00 2001 +From aca21ab5ab5b57a8f013380ff7f2b9dfff14636a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:16:03 -0700 -Subject: [PATCH 099/140] staging/vchi: Update for rename of +Subject: [PATCH 098/187] staging/vchi: Update for rename of page_cache_release() to put_page(). Signed-off-by: Eric Anholt @@ -123425,10 +122608,10 @@ index 085d37588c59198b4e5f00b9249bb8421695854f..5a2b8fb459ebe086ec229f37b6381bdb kfree(pages); } -From fa0f59766f7817bbafb26e74fabadf9770cd0c54 Mon Sep 17 00:00:00 2001 +From 789222dfdfbfdcfbc2513f3680fc13c1dded8050 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:21:17 -0700 -Subject: [PATCH 100/140] drivers/vchi: Remove dependency on CONFIG_BROKEN. +Subject: [PATCH 099/187] drivers/vchi: Remove dependency on CONFIG_BROKEN. The driver builds now. @@ -123450,10 +122633,10 @@ index 9676fb29075a457109e4d4235f086987aec74868..db8e1beb89f9f8c48ea5964016c8285e help Kernel to VideoCore communication interface for the -From 348cb13e9eb0943b5a3d2ccc9f8447bd906fafb9 Mon Sep 17 00:00:00 2001 +From 13af1452d680d811bb10721f7b08b9b6a2718ccc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:16:19 +0100 -Subject: [PATCH 101/140] raspberrypi-firmware: Export the general transaction +Subject: [PATCH 100/187] raspberrypi-firmware: Export the general transaction function. The vc4-firmware-kms module is going to be doing the MBOX FB call. @@ -123497,10 +122680,10 @@ index e92278968b2b979db2a1f855f70e7aafb224fa98..09e3d871d110eb0762ebdb5ea3293537 #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -From 1464fdba20dabf739325675298b8cfc94751a531 Mon Sep 17 00:00:00 2001 +From abd4f74c5ead8e51449e3196fda2868f07db87b2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:18:09 +0100 -Subject: [PATCH 102/140] raspberrypi-firmware: Define the MBOX channel in the +Subject: [PATCH 101/187] raspberrypi-firmware: Define the MBOX channel in the header. Signed-off-by: Eric Anholt @@ -123522,10 +122705,10 @@ index 09e3d871d110eb0762ebdb5ea329353738d58661..2859db09e25bb945251e85edb39bc434 enum rpi_firmware_property_status { -From da93c067a6faf0915da62d4763d15fec197e4632 Mon Sep 17 00:00:00 2001 +From 223f7c7232f19ded00dad5e51e2ac13f3c004d1c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 08:39:33 +0100 -Subject: [PATCH 103/140] drm/vc4: Add a mode for using the closed firmware for +Subject: [PATCH 102/187] drm/vc4: Add a mode for using the closed firmware for display. Signed-off-by: Eric Anholt @@ -124292,10 +123475,10 @@ index 0000000000000000000000000000000000000000..d18a1dae51a2275846c9826b5bf1ba57 + }, +}; -From 0c64daf4fec58a7f3bc174a3d73e3ac845f65b86 Mon Sep 17 00:00:00 2001 +From 2c21818d67bd9603071d0920fa147617c8ef5d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 17 Sep 2016 15:07:10 +0200 -Subject: [PATCH 104/140] i2c: bcm2835: Fix hang for writing messages larger +Subject: [PATCH 103/187] i2c: bcm2835: Fix hang for writing messages larger than 16 bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124385,10 +123568,10 @@ index d4f3239b56865919e1b781b20a7c5ebcd76b4eb9..f283b714aa79e2e4685ed95b04b6b289 i2c_dev->msg_buf_remaining = msg->len; reinit_completion(&i2c_dev->completion); -From 0aaf65741593a9fd06e98263363832bd498cc2f7 Mon Sep 17 00:00:00 2001 +From bd85fc46ace73c104fa58bc8f0747609ffef341b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 18:24:38 +0200 -Subject: [PATCH 105/140] i2c: bcm2835: Protect against unexpected TXW/RXR +Subject: [PATCH 104/187] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124513,10 +123696,10 @@ index f283b714aa79e2e4685ed95b04b6b289f7e9eee7..d2ba1a4de36af512e8e3c97251bd3537 return -ETIMEDOUT; } -From 37f07694782131d58654fdddec13530647665c41 Mon Sep 17 00:00:00 2001 +From 7410e42e332b47dd3ac0b0fc44953b24f941429f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 19 Sep 2016 17:19:41 +0200 -Subject: [PATCH 106/140] i2c: bcm2835: Use dev_dbg logging on transfer errors +Subject: [PATCH 105/187] i2c: bcm2835: Use dev_dbg logging on transfer errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124548,10 +123731,10 @@ index d2ba1a4de36af512e8e3c97251bd3537ae61591a..54d510abd46a117c9238fc6d7edec840 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From ecacf486b572638bc4f48ec95ce7487176db6379 Mon Sep 17 00:00:00 2001 +From 588f321b996ccfac8f507323d61c8a530d0e67a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 22 Sep 2016 22:05:50 +0200 -Subject: [PATCH 107/140] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK +Subject: [PATCH 106/187] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124595,10 +123778,10 @@ index 54d510abd46a117c9238fc6d7edec84019d1f60d..565ef69ce61423544dc0558c85ef318b if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) -From f1d345c2d724219a84d35c6b5a0f7c245a350fdc Mon Sep 17 00:00:00 2001 +From 6b38636136ea4492ede6905ae66c53d1c72630d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:54:27 +0200 -Subject: [PATCH 108/140] i2c: bcm2835: Add support for Repeated Start +Subject: [PATCH 107/187] i2c: bcm2835: Add support for Repeated Start Condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -124780,10 +123963,10 @@ index 565ef69ce61423544dc0558c85ef318b0ae9c324..241e08ae7c27cec23fad3c1bf3ebad3a static u32 bcm2835_i2c_func(struct i2c_adapter *adap) -From a4506104d5e6a1163413848796c70bafeb83b529 Mon Sep 17 00:00:00 2001 +From fcb0461ba98a06eb4fe21701f8f075cf9926d437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:57:17 +0200 -Subject: [PATCH 109/140] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT +Subject: [PATCH 108/187] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124820,10 +124003,10 @@ index 241e08ae7c27cec23fad3c1bf3ebad3a4d2a8e6f..d2085dd3742eabebc537621968088261 bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -From bc8206e909535c9cf57538b0c5121b98a880017f Mon Sep 17 00:00:00 2001 +From 8e1ede04b3ed0f4caa6f350bf079c5c39536d786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 27 Sep 2016 01:00:08 +0200 -Subject: [PATCH 110/140] i2c: bcm2835: Add support for dynamic clock +Subject: [PATCH 109/187] i2c: bcm2835: Add support for dynamic clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124939,10 +124122,10 @@ index d2085dd3742eabebc537621968088261f8dc7ea8..c3436f627028477f7e21b47e079fd5ab irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { -From 15d85dfe50f97f181498356e9ef735aa45adcd1d Mon Sep 17 00:00:00 2001 +From 3e3241d385371be14a6beb09565a5046ae9474dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 1 Nov 2016 15:15:41 +0100 -Subject: [PATCH 111/140] i2c: bcm2835: Add debug support +Subject: [PATCH 110/187] i2c: bcm2835: Add debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -125131,10 +124314,10 @@ index c3436f627028477f7e21b47e079fd5ab06ec188a..8642f580ce41803bd22c76a0fa80d083 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From e28b55c5e8d7411c32f6ec15101276060c71c7d1 Mon Sep 17 00:00:00 2001 +From 64556f2c8cd15271c6932c41e3c1722ea5c2a7a2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 31 Dec 2016 14:15:50 +0000 -Subject: [PATCH 112/140] arm64: Add CONFIG_ARCH_BCM2835 +Subject: [PATCH 111/187] arm64: Add CONFIG_ARCH_BCM2835 --- arch/arm64/configs/bcmrpi3_defconfig | 1 + @@ -125150,10 +124333,10 @@ index d7406f5a4620151044b8f716b4d10bb818648e06..53da5c7a33e5898a66e549fb0c39fe3d CONFIG_BCM2708_VCHIQ=n +CONFIG_ARCH_BCM2835=y -From 504cbe6331e8e2fb20532f2cd78d39dc04f5ff54 Mon Sep 17 00:00:00 2001 +From 23096cda9201811a9f0a7e5ae9bacd047deb126b Mon Sep 17 00:00:00 2001 From: Alex Tucker Date: Tue, 13 Dec 2016 19:50:18 +0000 -Subject: [PATCH 113/140] Add support for Silicon Labs Si7013/20/21 +Subject: [PATCH 112/187] Add support for Silicon Labs Si7013/20/21 humidity/temperature sensor. --- @@ -125228,10 +124411,10 @@ index f6d134c095af2398fc55ae7d2b0e86456c30627c..31bda8da4cb6a56bfe493a81b9189009 }; }; -From 7fd3189681ab1e4bcde0efba4d7b9cb92f5bce72 Mon Sep 17 00:00:00 2001 +From 272d577c609238d107527ed6b7120d2b4c3f373c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Jan 2017 21:27:46 +0000 -Subject: [PATCH 114/140] Document the si7020 option +Subject: [PATCH 113/187] Document the si7020 option --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -125252,10 +124435,10 @@ index 81d991803be335e5a1bc3bb0a8c7a2c9f5c392bd..e8fa4ccb44c34a20485c4e6155467af9 Name: i2c0-bcm2708 Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations -From ceb29f8e53ca711738de6c72eeb9d9cb3a857575 Mon Sep 17 00:00:00 2001 +From 0a5470acf780e9ce5aff826f1f9592f298f0df08 Mon Sep 17 00:00:00 2001 From: Giedrius Trainavicius Date: Thu, 5 Jan 2017 02:38:16 +0200 -Subject: [PATCH 115/140] pisound improvements: +Subject: [PATCH 114/187] pisound improvements: * Added a writable sysfs object to enable scripts / user space software to blink MIDI activity LEDs for variable duration. @@ -125549,958 +124732,10 @@ index 4b8545487d06e4ea70073a5d063fb2310b3b94d0..ba70734b89e61a11201657406223f0b3 }; -From f431961cbef359e679dcecd15eac69489e537d07 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 9 Jan 2017 09:23:06 +0000 -Subject: [PATCH 116/140] Revert "Revert "Added driver for HiFiBerry Amp - amplifier add-on board"" - -This reverts commit bf84babd8fffcb79c60f1342c2416f8e1e4b7af9. ---- - sound/soc/bcm/Kconfig | 7 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_amp.c | 129 +++++++++++++++ - sound/soc/codecs/Kconfig | 4 + - sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++ - sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++ - 7 files changed, 723 insertions(+) - create mode 100644 sound/soc/bcm/hifiberry_amp.c - create mode 100644 sound/soc/codecs/tas5713.c - create mode 100644 sound/soc/codecs/tas5713.h - -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index a0ef6a028136beb27ed13a4136712a70a60f2966..d024377e8450fb5402dcb5ea27161f774b04a8ec 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -38,6 +38,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI - help - Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. - -+config SND_BCM2708_SOC_HIFIBERRY_AMP -+ tristate "Support for the HifiBerry Amp" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_TAS5713 -+ help -+ Say Y or M if you want to add support for the HifiBerry Amp amplifier board. -+ - config SND_BCM2708_SOC_RPI_DAC - tristate "Support for RPi-DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index f720a3d3b5832844ee6d0558317c728f00c40b65..bb1df438540193652ec5464e8bc51f636a1b844e 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o - - # BCM2708 Machine Support - snd-soc-adau1977-adc-objs := adau1977-adc.o -+snd-soc-hifiberry-amp-objs := hifiberry_amp.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o -@@ -27,6 +28,7 @@ snd-soc-allo-piano-dac-objs := allo-piano-dac.o - snd-soc-pisound-objs := pisound.o - - obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o -diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d17c29780507dc31c50f1d567ff5cea7c8241ff5 ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_amp.c -@@ -0,0 +1,129 @@ -+/* -+ * ASoC Driver for HifiBerry AMP -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ // ToDo: init of the dsp-registers. -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params ) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); -+} -+ -+static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = { -+ .hw_params = snd_rpi_hifiberry_amp_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { -+ { -+ .name = "HifiBerry AMP", -+ .stream_name = "HifiBerry AMP HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "tas5713-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "tas5713.1-001b", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_amp_ops, -+ .init = snd_rpi_hifiberry_amp_init, -+ }, -+}; -+ -+ -+static struct snd_soc_card snd_rpi_hifiberry_amp = { -+ .name = "snd_rpi_hifiberry_amp", -+ .driver_name = "HifiberryAmp", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_amp_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), -+}; -+ -+static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-amp", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match); -+ -+ -+static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_hifiberry_amp.dev = &pdev->dev; -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ -+ if (i2s_node) { -+ dai->cpu_dai_name = NULL; -+ dai->cpu_of_node = i2s_node; -+ dai->platform_name = NULL; -+ dai->platform_of_node = i2s_node; -+ } -+ } -+ -+ ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); -+ -+ if (ret != 0) { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_hifiberry_amp); -+} -+ -+ -+static struct platform_driver snd_rpi_hifiberry_amp_driver = { -+ .driver = { -+ .name = "snd-hifiberry-amp", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_amp_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_amp_probe, -+ .remove = snd_rpi_hifiberry_amp_remove, -+}; -+ -+ -+module_platform_driver(snd_rpi_hifiberry_amp_driver); -+ -+ -+MODULE_AUTHOR("Sebastian Eickhoff "); -+MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 74a93e52bdc8116df3db08aaf98fffa1e6f6cc1b..9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -139,6 +139,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_TFA9879 if I2C - select SND_SOC_TLV320AIC23_I2C if I2C - select SND_SOC_TLV320AIC23_SPI if SPI_MASTER -+ select SND_SOC_TAS5713 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC31XX if I2C - select SND_SOC_TLV320AIC32X4_I2C if I2C -@@ -821,6 +822,9 @@ config SND_SOC_TFA9879 - tristate "NXP Semiconductors TFA9879 amplifier" - depends on I2C - -+config SND_SOC_TAS5713 -+ tristate -+ - config SND_SOC_TLV320AIC23 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 77786e7f44a7fa22d9b5beed3eb687e2b7a28526..5a2db0d2fe2f49920eeccfecef62c969ae2e99a1 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -144,6 +144,7 @@ snd-soc-tas5086-objs := tas5086.o - snd-soc-tas571x-objs := tas571x.o - snd-soc-tas5720-objs := tas5720.o - snd-soc-tfa9879-objs := tfa9879.o -+snd-soc-tas5713-objs := tas5713.o - snd-soc-tlv320aic23-objs := tlv320aic23.o - snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o - snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o -@@ -366,6 +367,7 @@ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o - obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o - obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o - obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o -+obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o - obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o - obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9b2713861dcbed751842ca29c88eb1eae5867411 ---- /dev/null -+++ b/sound/soc/codecs/tas5713.c -@@ -0,0 +1,369 @@ -+/* -+ * ASoC Driver for TAS5713 -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "tas5713.h" -+ -+ -+static struct i2c_client *i2c; -+ -+struct tas5713_priv { -+ struct regmap *regmap; -+ int mclk_div; -+ struct snd_soc_codec *codec; -+}; -+ -+static struct tas5713_priv *priv_data; -+ -+ -+ -+ -+/* -+ * _ _ ___ _ ___ _ _ -+ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___ -+ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-< -+ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/ -+ * -+ */ -+ -+static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1); -+ -+ -+static const struct snd_kcontrol_new tas5713_snd_controls[] = { -+ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv), -+ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv) -+}; -+ -+ -+ -+ -+/* -+ * __ __ _ _ ___ _ -+ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _ -+ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_| -+ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static int tas5713_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ u16 blen = 0x00; -+ -+ struct snd_soc_codec *codec; -+ codec = dai->codec; -+ priv_data->codec = dai->codec; -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ blen = 0x03; -+ break; -+ case SNDRV_PCM_FORMAT_S20_3LE: -+ blen = 0x1; -+ break; -+ case SNDRV_PCM_FORMAT_S24_LE: -+ blen = 0x04; -+ break; -+ case SNDRV_PCM_FORMAT_S32_LE: -+ blen = 0x05; -+ break; -+ default: -+ dev_err(dai->dev, "Unsupported word length: %u\n", -+ params_format(params)); -+ return -EINVAL; -+ } -+ -+ // set word length -+ snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen); -+ -+ return 0; -+} -+ -+ -+static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream) -+{ -+ unsigned int val = 0; -+ -+ struct tas5713_priv *tas5713; -+ struct snd_soc_codec *codec = dai->codec; -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ if (mute) { -+ val = TAS5713_SOFT_MUTE_ALL; -+ } -+ -+ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val); -+} -+ -+ -+static const struct snd_soc_dai_ops tas5713_dai_ops = { -+ .hw_params = tas5713_hw_params, -+ .mute_stream = tas5713_mute_stream, -+}; -+ -+ -+static struct snd_soc_dai_driver tas5713_dai = { -+ .name = "tas5713-hifi", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ), -+ }, -+ .ops = &tas5713_dai_ops, -+}; -+ -+ -+ -+ -+/* -+ * ___ _ ___ _ -+ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _ -+ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_| -+ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static int tas5713_remove(struct snd_soc_codec *codec) -+{ -+ struct tas5713_priv *tas5713; -+ -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ return 0; -+} -+ -+ -+static int tas5713_probe(struct snd_soc_codec *codec) -+{ -+ struct tas5713_priv *tas5713; -+ int i, ret; -+ -+ i2c = container_of(codec->dev, struct i2c_client, dev); -+ -+ tas5713 = snd_soc_codec_get_drvdata(codec); -+ -+ // Reset error -+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -+ if (ret < 0) return ret; -+ -+ // Trim oscillator -+ ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00); -+ if (ret < 0) return ret; -+ msleep(1000); -+ -+ // Reset error -+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00); -+ if (ret < 0) return ret; -+ -+ // Clock mode: 44/48kHz, MCLK=64xfs -+ ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60); -+ if (ret < 0) return ret; -+ -+ // I2S 24bit -+ ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05); -+ if (ret < 0) return ret; -+ -+ // Unmute -+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -+ if (ret < 0) return ret; -+ ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00); -+ if (ret < 0) return ret; -+ -+ // Set volume to 0db -+ ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00); -+ if (ret < 0) return ret; -+ -+ // Now start programming the default initialization sequence -+ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) { -+ ret = i2c_master_send(i2c, -+ tas5713_init_sequence[i].data, -+ tas5713_init_sequence[i].size); -+ if (ret < 0) { -+ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret); -+ } -+ } -+ -+ // Unmute -+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00); -+ if (ret < 0) return ret; -+ -+ return 0; -+} -+ -+ -+static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { -+ .probe = tas5713_probe, -+ .remove = tas5713_remove, -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+}; -+ -+ -+ -+ -+/* -+ * ___ ___ ___ ___ _ -+ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _ -+ * | | / / (__ | |) | '_| \ V / -_) '_| -+ * |___/___\___| |___/|_| |_|\_/\___|_| -+ * -+ */ -+ -+static const struct reg_default tas5713_reg_defaults[] = { -+ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB -+ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB -+ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB -+ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB -+}; -+ -+ -+static bool tas5713_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case TAS5713_DEVICE_ID: -+ case TAS5713_ERROR_STATUS: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+ -+static const struct of_device_id tas5713_of_match[] = { -+ { .compatible = "ti,tas5713", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, tas5713_of_match); -+ -+ -+static struct regmap_config tas5713_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ -+ .max_register = TAS5713_MAX_REGISTER, -+ .volatile_reg = tas5713_reg_volatile, -+ -+ .cache_type = REGCACHE_RBTREE, -+ .reg_defaults = tas5713_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults), -+}; -+ -+ -+static int tas5713_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ int ret; -+ -+ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL); -+ if (!priv_data) -+ return -ENOMEM; -+ -+ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config); -+ if (IS_ERR(priv_data->regmap)) { -+ ret = PTR_ERR(priv_data->regmap); -+ return ret; -+ } -+ -+ i2c_set_clientdata(i2c, priv_data); -+ -+ ret = snd_soc_register_codec(&i2c->dev, -+ &soc_codec_dev_tas5713, &tas5713_dai, 1); -+ -+ return ret; -+} -+ -+ -+static int tas5713_i2c_remove(struct i2c_client *i2c) -+{ -+ snd_soc_unregister_codec(&i2c->dev); -+ i2c_set_clientdata(i2c, NULL); -+ -+ kfree(priv_data); -+ -+ return 0; -+} -+ -+ -+static const struct i2c_device_id tas5713_i2c_id[] = { -+ { "tas5713", 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id); -+ -+ -+static struct i2c_driver tas5713_i2c_driver = { -+ .driver = { -+ .name = "tas5713", -+ .owner = THIS_MODULE, -+ .of_match_table = tas5713_of_match, -+ }, -+ .probe = tas5713_i2c_probe, -+ .remove = tas5713_i2c_remove, -+ .id_table = tas5713_i2c_id -+}; -+ -+ -+static int __init tas5713_modinit(void) -+{ -+ int ret = 0; -+ -+ ret = i2c_add_driver(&tas5713_i2c_driver); -+ if (ret) { -+ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n", -+ ret); -+ } -+ -+ return ret; -+} -+module_init(tas5713_modinit); -+ -+ -+static void __exit tas5713_exit(void) -+{ -+ i2c_del_driver(&tas5713_i2c_driver); -+} -+module_exit(tas5713_exit); -+ -+ -+MODULE_AUTHOR("Sebastian Eickhoff "); -+MODULE_DESCRIPTION("ASoC driver for TAS5713"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/tas5713.h b/sound/soc/codecs/tas5713.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8f612a342 ---- /dev/null -+++ b/sound/soc/codecs/tas5713.h -@@ -0,0 +1,210 @@ -+/* -+ * ASoC Driver for TAS5713 -+ * -+ * Author: Sebastian Eickhoff -+ * Copyright 2014 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#ifndef _TAS5713_H -+#define _TAS5713_H -+ -+ -+// TAS5713 I2C-bus register addresses -+ -+#define TAS5713_CLOCK_CTRL 0x00 -+#define TAS5713_DEVICE_ID 0x01 -+#define TAS5713_ERROR_STATUS 0x02 -+#define TAS5713_SYSTEM_CTRL1 0x03 -+#define TAS5713_SERIAL_DATA_INTERFACE 0x04 -+#define TAS5713_SYSTEM_CTRL2 0x05 -+#define TAS5713_SOFT_MUTE 0x06 -+#define TAS5713_VOL_MASTER 0x07 -+#define TAS5713_VOL_CH1 0x08 -+#define TAS5713_VOL_CH2 0x09 -+#define TAS5713_VOL_HEADPHONE 0x0A -+#define TAS5713_VOL_CONFIG 0x0E -+#define TAS5713_MODULATION_LIMIT 0x10 -+#define TAS5713_IC_DLY_CH1 0x11 -+#define TAS5713_IC_DLY_CH2 0x12 -+#define TAS5713_IC_DLY_CH3 0x13 -+#define TAS5713_IC_DLY_CH4 0x14 -+ -+#define TAS5713_START_STOP_PERIOD 0x1A -+#define TAS5713_OSC_TRIM 0x1B -+#define TAS5713_BKND_ERR 0x1C -+ -+#define TAS5713_INPUT_MUX 0x20 -+#define TAS5713_SRC_SELECT_CH4 0x21 -+#define TAS5713_PWM_MUX 0x25 -+ -+#define TAS5713_CH1_BQ0 0x29 -+#define TAS5713_CH1_BQ1 0x2A -+#define TAS5713_CH1_BQ2 0x2B -+#define TAS5713_CH1_BQ3 0x2C -+#define TAS5713_CH1_BQ4 0x2D -+#define TAS5713_CH1_BQ5 0x2E -+#define TAS5713_CH1_BQ6 0x2F -+#define TAS5713_CH1_BQ7 0x58 -+#define TAS5713_CH1_BQ8 0x59 -+ -+#define TAS5713_CH2_BQ0 0x30 -+#define TAS5713_CH2_BQ1 0x31 -+#define TAS5713_CH2_BQ2 0x32 -+#define TAS5713_CH2_BQ3 0x33 -+#define TAS5713_CH2_BQ4 0x34 -+#define TAS5713_CH2_BQ5 0x35 -+#define TAS5713_CH2_BQ6 0x36 -+#define TAS5713_CH2_BQ7 0x5C -+#define TAS5713_CH2_BQ8 0x5D -+ -+#define TAS5713_CH4_BQ0 0x5A -+#define TAS5713_CH4_BQ1 0x5B -+#define TAS5713_CH3_BQ0 0x5E -+#define TAS5713_CH3_BQ1 0x5F -+ -+#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B -+#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C -+#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E -+#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F -+#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40 -+#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43 -+#define TAS5713_DRC_CTRL 0x46 -+ -+#define TAS5713_BANK_SW_CTRL 0x50 -+#define TAS5713_CH1_OUTPUT_MIXER 0x51 -+#define TAS5713_CH2_OUTPUT_MIXER 0x52 -+#define TAS5713_CH1_INPUT_MIXER 0x53 -+#define TAS5713_CH2_INPUT_MIXER 0x54 -+#define TAS5713_OUTPUT_POST_SCALE 0x56 -+#define TAS5713_OUTPUT_PRESCALE 0x57 -+ -+#define TAS5713_IDF_POST_SCALE 0x62 -+ -+#define TAS5713_CH1_INLINE_MIXER 0x70 -+#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71 -+#define TAS5713_CH1_R_CHANNEL_MIXER 0x72 -+#define TAS5713_CH1_L_CHANNEL_MIXER 0x73 -+#define TAS5713_CH2_INLINE_MIXER 0x74 -+#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75 -+#define TAS5713_CH2_L_CHANNEL_MIXER 0x76 -+#define TAS5713_CH2_R_CHANNEL_MIXER 0x77 -+ -+#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8 -+#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9 -+ -+#define TAS5713_REGISTER_COUNT 0x46 -+#define TAS5713_MAX_REGISTER 0xF9 -+ -+ -+// Bitmasks for registers -+#define TAS5713_SOFT_MUTE_ALL 0x07 -+ -+ -+ -+struct tas5713_init_command { -+ const int size; -+ const char *const data; -+}; -+ -+static const struct tas5713_init_command tas5713_init_sequence[] = { -+ -+ // Trim oscillator -+ { .size = 2, .data = "\x1B\x00" }, -+ // System control register 1 (0x03): block DC -+ { .size = 2, .data = "\x03\x80" }, -+ // Mute everything -+ { .size = 2, .data = "\x05\x40" }, -+ // Modulation limit register (0x10): 97.7% -+ { .size = 2, .data = "\x10\x02" }, -+ // Interchannel delay registers -+ // (0x11, 0x12, 0x13, and 0x14): BD mode -+ { .size = 2, .data = "\x11\xB8" }, -+ { .size = 2, .data = "\x12\x60" }, -+ { .size = 2, .data = "\x13\xA0" }, -+ { .size = 2, .data = "\x14\x48" }, -+ // PWM shutdown group register (0x19): no shutdown -+ { .size = 2, .data = "\x19\x00" }, -+ // Input multiplexer register (0x20): BD mode -+ { .size = 2, .data = "\x20\x00\x89\x77\x72" }, -+ // PWM output mux register (0x25) -+ // Channel 1 --> OUTA, channel 1 neg --> OUTB -+ // Channel 2 --> OUTC, channel 2 neg --> OUTD -+ { .size = 5, .data = "\x25\x01\x02\x13\x45" }, -+ // DRC control (0x46): DRC off -+ { .size = 5, .data = "\x46\x00\x00\x00\x00" }, -+ // BKND_ERR register (0x1C): 299ms reset period -+ { .size = 2, .data = "\x1C\x07" }, -+ // Mute channel 3 -+ { .size = 2, .data = "\x0A\xFF" }, -+ // Volume configuration register (0x0E): volume slew 512 steps -+ { .size = 2, .data = "\x0E\x90" }, -+ // Clock control register (0x00): 44/48kHz, MCLK=64xfs -+ { .size = 2, .data = "\x00\x60" }, -+ // Bank switch and eq control (0x50): no bank switching -+ { .size = 5, .data = "\x50\x00\x00\x00\x00" }, -+ // Volume registers (0x07, 0x08, 0x09, 0x0A) -+ { .size = 2, .data = "\x07\x20" }, -+ { .size = 2, .data = "\x08\x30" }, -+ { .size = 2, .data = "\x09\x30" }, -+ { .size = 2, .data = "\x0A\xFF" }, -+ // 0x72, 0x73, 0x76, 0x77 input mixer: -+ // no intermix between channels -+ { .size = 5, .data = "\x72\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x73\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x76\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x77\x00\x80\x00\x00" }, -+ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer: -+ // no inline DRC inmix -+ { .size = 5, .data = "\x70\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x71\x00\x00\x00\x00" }, -+ { .size = 5, .data = "\x74\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x75\x00\x00\x00\x00" }, -+ // 0x56, 0x57 Output scale -+ { .size = 5, .data = "\x56\x00\x80\x00\x00" }, -+ { .size = 5, .data = "\x57\x00\x02\x00\x00" }, -+ // 0x3B, 0x3c -+ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" }, -+ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" }, -+ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" }, -+ // 0x51, 0x52: output mixer -+ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" }, -+ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" }, -+ // PEQ defaults -+ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }, -+}; -+ -+ -+#endif /* _TAS5713_H */ - -From 6114307aaa8e31dd0d336fbd67eefd50444a58b3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 9 Jan 2017 09:42:09 +0000 -Subject: [PATCH 117/140] hifiberry-amp: Adjust for ALSA object refactoring - -See: https://github.com/raspberrypi/linux/issues/1775 ---- - sound/soc/codecs/tas5713.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/codecs/tas5713.c b/sound/soc/codecs/tas5713.c -index 9b2713861dcbed751842ca29c88eb1eae5867411..560234d58a6b0a6e7fd3a63e8de73339ee002b1c 100644 ---- a/sound/soc/codecs/tas5713.c -+++ b/sound/soc/codecs/tas5713.c -@@ -232,8 +232,10 @@ static int tas5713_probe(struct snd_soc_codec *codec) - static struct snd_soc_codec_driver soc_codec_dev_tas5713 = { - .probe = tas5713_probe, - .remove = tas5713_remove, -- .controls = tas5713_snd_controls, -- .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+ .component_driver = { -+ .controls = tas5713_snd_controls, -+ .num_controls = ARRAY_SIZE(tas5713_snd_controls), -+ }, - }; - - - -From 8640eb5ad8ecd1ed2eff1428f4ef19d9a0f5af18 Mon Sep 17 00:00:00 2001 -From: Giedrius Trainavicius -Date: Sun, 8 Jan 2017 15:58:54 +0200 -Subject: [PATCH 118/140] bcm2835-i2s: Changes for allowing asymmetric sample - formats. - -This is achieved by making changes only to the requested -stream direction format, keeping the other stream direction -configuration intact. - -Signed-off-by: Giedrius Trainavicius ---- - sound/soc/bcm/bcm2835-i2s.c | 54 +++++++++++++++++++++++++++++++-------------- - 1 file changed, 38 insertions(+), 16 deletions(-) - -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index 6ba20498202ed36906b52096893a88867a79269f..171c2401dfe192740fca3356268aff6432f284ea 100644 ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -237,7 +237,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - unsigned int sampling_rate = params_rate(params); - unsigned int data_length, data_delay, bclk_ratio; - unsigned int ch1pos, ch2pos, mode, format; -+ unsigned int previous_ftxp, previous_frxp; - uint32_t csreg; -+ bool packed; - - /* - * If a stream is already enabled, -@@ -320,26 +322,46 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- /* -- * Set format for both streams. -- * We cannot set another frame length -- * (and therefore word length) anyway, -- * so the format will be the same. -- */ -- regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -- regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -+ /* Set the format for the matching stream direction. */ -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -+ break; -+ default: -+ return -EINVAL; -+ } - - /* Setup the I2S mode */ -+ /* Keep existing FTXP and FRXP values. */ -+ regmap_read(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, &mode); -+ -+ previous_ftxp = mode & BCM2835_I2S_FTXP; -+ previous_frxp = mode & BCM2835_I2S_FRXP; -+ - mode = 0; - -- if (data_length <= 16) { -- /* -- * Use frame packed mode (2 channels per 32 bit word) -- * We cannot set another frame length in the second stream -- * (and therefore word length) anyway, -- * so the format will be the same. -- */ -- mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; -+ /* -+ * Retain the frame packed mode (2 channels per 32 bit word) -+ * of the other direction stream intact. The formats of each -+ * direction can be different as long as the frame length is -+ * shared for both. -+ */ -+ packed = data_length <= 16; -+ -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ mode |= previous_frxp; -+ mode |= packed ? BCM2835_I2S_FTXP : 0; -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ mode |= previous_ftxp; -+ mode |= packed ? BCM2835_I2S_FRXP : 0; -+ break; -+ default: -+ return -EINVAL; - } - - mode |= BCM2835_I2S_FLEN(bclk_ratio - 1); - -From ecf8e89a531ac228706cc49b6caed1d4dfe4adc7 Mon Sep 17 00:00:00 2001 +From 6d7eabf9e6c2652ed71b4fa01951a7e19f47a985 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:05:41 +0000 -Subject: [PATCH 119/140] Add driver_name property +Subject: [PATCH 115/187] Add driver_name property Add driver name property for use with 5.1 passthrough audio in LibreElec and other Kodi based OSs --- @@ -126520,10 +124755,10 @@ index 8fd50dbe681508a2cfe8fdde1c9fedbe9a507fa7..05a224ec712d06b8b7587ab6b8bb562d .dai_link = snd_rpi_justboom_dac_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai), -From 66434539f08795819e610de5df739cf461205bc1 Mon Sep 17 00:00:00 2001 +From 48c21dc46d473a6362e66bfcae1b7cfe1996a497 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:11:04 +0000 -Subject: [PATCH 120/140] Add driver_name paramater +Subject: [PATCH 116/187] Add driver_name paramater Add driver_name parameter for use with 5.1 passthrough audio in LibreElec and other Kodi OSs --- @@ -126543,10 +124778,10 @@ index 91acb666380faa3c0deb2230f8a0f8bbec59417b..abfdc5c4dd5811e6847bddda4921abe3 .dai_link = snd_rpi_justboom_digi_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_digi_dai), -From 296fcf4cadef94895b86e0d6f1cd5480675cc94b Mon Sep 17 00:00:00 2001 +From ee8c66d4165cfa623d1050d2cf48078bae5769d2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Jan 2017 13:01:21 +0000 -Subject: [PATCH 121/140] BCM270X_DT: Add pi3-disable-wifi overlay +Subject: [PATCH 117/187] BCM270X_DT: Add pi3-disable-wifi overlay pi3-disable-wifi is a minimal overlay to disable the onboard WiFi. @@ -126607,10 +124842,10 @@ index 0000000000000000000000000000000000000000..017199554bf2f4e381efcc7bb71e750c + }; +}; -From 0b46fbc4be5ddfec19dbaf619a9c9ef3d8559df3 Mon Sep 17 00:00:00 2001 +From 6a3c02c8633387502a4d76347a540ba402ee8d09 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Thu, 12 Jan 2017 07:07:08 -0800 -Subject: [PATCH 122/140] ARM64: Make it work again on 4.9 (#1790) +Subject: [PATCH 118/187] ARM64: Make it work again on 4.9 (#1790) * Invoke the dtc compiler with the same options used in arm mode. * ARM64 now uses the bcm2835 platform just like ARM32. @@ -127015,10 +125250,10 @@ index 53da5c7a33e5898a66e549fb0c39fe3da555ca87..c7e891d72969a388d9b135a36dbfc9c9 -CONFIG_BCM2708_VCHIQ=n -CONFIG_ARCH_BCM2835=y -From 070417bfe80223f042349b5322d0694e249c6125 Mon Sep 17 00:00:00 2001 +From 5189f9eb2e9e8f1b4e916f2c37b14c564eae6366 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Sat, 14 Jan 2017 02:54:26 -0800 -Subject: [PATCH 123/140] ARM64: Enable Kernel Address Space Randomization +Subject: [PATCH 119/187] ARM64: Enable Kernel Address Space Randomization (#1792) Randomization allows the mapping between virtual addresses and physical @@ -127050,10 +125285,10 @@ index c7e891d72969a388d9b135a36dbfc9c9cb609bf8..974d8889c0cf695eb88b57bbef11bc5a CONFIG_BINFMT_MISC=y CONFIG_COMPAT=y -From 8b1dcc577913872e592b15aead4e90e1e2e7184c Mon Sep 17 00:00:00 2001 +From e5169833aa70954251b7c3486f5706c4f3dd8ccb Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sun, 15 Jan 2017 07:31:59 -0800 -Subject: [PATCH 124/140] ARM64: Enable RTL8187/RTL8192CU wifi in build config +Subject: [PATCH 120/187] ARM64: Enable RTL8187/RTL8192CU wifi in build config These drivers build now, so they can be enabled back in the build configuration just like they are for @@ -127078,10 +125313,10 @@ index 974d8889c0cf695eb88b57bbef11bc5aa556b635..4670a490dfb1e582ec24a3b39a3cb9b2 CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From e3e2c6018b7d88fc2d66e5646e8f026ebd54c3ef Mon Sep 17 00:00:00 2001 +From a825be7b435a9666323b636455d8547c6a4e3ac0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Jan 2017 14:53:12 +0000 -Subject: [PATCH 125/140] BCM270X_DT: Add spi0-cs overlay +Subject: [PATCH 121/187] BCM270X_DT: Add spi0-cs overlay The spi0-cs overlay allows the software chip selectts to be modified using the cs0_pin and cs1_pin parameters. @@ -127169,10 +125404,10 @@ index 0000000000000000000000000000000000000000..7f79029d043c04d7496c7c3480450c69 + }; +}; -From f59b0251d9406e66fdea34d7bf00b996ed949084 Mon Sep 17 00:00:00 2001 +From ddbcf48e6e8560635ca6c7284b3c04d36b3c86f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 126/140] spi-bcm2835: Disable forced software CS +Subject: [PATCH 122/187] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -127198,10 +125433,10 @@ index 74dd21b7373c7564ede01d84a4f63b93a6d52fa7..51cdefbf5eb265f49bd05e0aa91dfbee i2c0: i2c@7e205000 { -From 96fc8668c38ec7d5d97a85851a8f61c2ad16e619 Mon Sep 17 00:00:00 2001 +From 51b4a593707de53db9daa9b8933a16ff5d383671 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 16 Jan 2017 16:33:54 +0000 -Subject: [PATCH 127/140] config: Add CONFIG_TCP_CONG_BBR See: +Subject: [PATCH 123/187] config: Add CONFIG_TCP_CONG_BBR See: https://github.com/raspberrypi/linux/issues/1784 --- @@ -127236,103 +125471,10 @@ index 8acee9f31202ec14f2933d92dd70831cda8d7b51..219f67051a2542329449b0099165ae28 CONFIG_IPV6_ROUTER_PREF=y CONFIG_INET6_AH=m -From aad9e6a0506b7365903934a6b86d8d960e5274f3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 16 Jan 2017 21:02:26 +0000 -Subject: [PATCH 128/140] Revert "bcm2835-i2s: Changes for allowing asymmetric - sample formats." - -This reverts commit f5a6236a32e82068122301d246a94ca755d61704. - -See: https://github.com/raspberrypi/linux/issues/1799 - -Signed-off-by: Phil Elwell ---- - sound/soc/bcm/bcm2835-i2s.c | 54 ++++++++++++++------------------------------- - 1 file changed, 16 insertions(+), 38 deletions(-) - -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index 171c2401dfe192740fca3356268aff6432f284ea..6ba20498202ed36906b52096893a88867a79269f 100644 ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -237,9 +237,7 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - unsigned int sampling_rate = params_rate(params); - unsigned int data_length, data_delay, bclk_ratio; - unsigned int ch1pos, ch2pos, mode, format; -- unsigned int previous_ftxp, previous_frxp; - uint32_t csreg; -- bool packed; - - /* - * If a stream is already enabled, -@@ -322,46 +320,26 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- /* Set the format for the matching stream direction. */ -- switch (substream->stream) { -- case SNDRV_PCM_STREAM_PLAYBACK: -- regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); -- break; -- case SNDRV_PCM_STREAM_CAPTURE: -- regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -- break; -- default: -- return -EINVAL; -- } -+ /* -+ * Set format for both streams. -+ * We cannot set another frame length -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); -+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); - - /* Setup the I2S mode */ -- /* Keep existing FTXP and FRXP values. */ -- regmap_read(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, &mode); -- -- previous_ftxp = mode & BCM2835_I2S_FTXP; -- previous_frxp = mode & BCM2835_I2S_FRXP; -- - mode = 0; - -- /* -- * Retain the frame packed mode (2 channels per 32 bit word) -- * of the other direction stream intact. The formats of each -- * direction can be different as long as the frame length is -- * shared for both. -- */ -- packed = data_length <= 16; -- -- switch (substream->stream) { -- case SNDRV_PCM_STREAM_PLAYBACK: -- mode |= previous_frxp; -- mode |= packed ? BCM2835_I2S_FTXP : 0; -- break; -- case SNDRV_PCM_STREAM_CAPTURE: -- mode |= previous_ftxp; -- mode |= packed ? BCM2835_I2S_FRXP : 0; -- break; -- default: -- return -EINVAL; -+ if (data_length <= 16) { -+ /* -+ * Use frame packed mode (2 channels per 32 bit word) -+ * We cannot set another frame length in the second stream -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; - } - - mode |= BCM2835_I2S_FLEN(bclk_ratio - 1); - -From 7ce4883feb777ba20f03f111fe3e6a208a21f2d4 Mon Sep 17 00:00:00 2001 +From 7729ddc311ba53dd238d7271dd2d023d6e02e8e8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 11:34:58 +0000 -Subject: [PATCH 129/140] BCM270X_DT: Enable UART0 on CM3 +Subject: [PATCH 124/187] BCM270X_DT: Enable UART0 on CM3 Signed-off-by: Phil Elwell --- @@ -127355,10 +125497,10 @@ index 41874c25a84226c0e4af92ec4059e0a571fe6123..3ba6e621856c288ae4694f758604619f sdhost_pins: sdhost_pins { brcm,pins = <48 49 50 51 52 53>; -From 1b279d3d8a778bf7c085e15e02351b5fc336a95b Mon Sep 17 00:00:00 2001 +From eb2a61b5b76a74ec88f6806ad3f17e21087f56ce Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 14:39:39 +0000 -Subject: [PATCH 130/140] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR +Subject: [PATCH 125/187] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR See: https://github.com/raspberrypi/linux/issues/1781 @@ -127397,10 +125539,10 @@ index 219f67051a2542329449b0099165ae2885022bec..c4898d63d74718097ec3a1d1fe60b230 CONFIG_OF_CONFIGFS=y CONFIG_ZRAM=m -From 5623259cfc13aef68cff35a43f080fe9d084bfb3 Mon Sep 17 00:00:00 2001 +From c1ec27e76b5fcd2382170a75115de85200d4ab26 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:33:51 -0800 -Subject: [PATCH 131/140] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 +Subject: [PATCH 126/187] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 In ARM64, the FIQ mechanism used by this driver is not current implemented. As a workaround, reqular IRQ is used instead @@ -127743,10 +125885,10 @@ index 6b2c7d0c93f36a63863ff4b0ecc1f3eab77e058b..d7b700ff17821ad1944e36721fe6b2db /** The OS page size */ #define DWC_OS_PAGE_SIZE PAGE_SIZE -From 8573f30283e6c0e99e42ce97ef61203e936daab7 Mon Sep 17 00:00:00 2001 +From aef6479d8851c123def265acb03814ce7e5210b1 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:43:57 -0800 -Subject: [PATCH 132/140] ARM64: Round-Robin dispatch IRQs between CPUs. +Subject: [PATCH 127/187] ARM64: Round-Robin dispatch IRQs between CPUs. IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced @@ -127820,10 +125962,10 @@ index 93e3f7660c4230c9f1dd3b195958cb498949b0ca..486bcbfb32305ee417f6b3be7e91a3ff .name = "bcm2836-gpu", .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, -From c705045a8d00541a9af2d3a1a10369bd50e2709c Mon Sep 17 00:00:00 2001 +From dd7b1d1f7f28f380616a77bff9440adea1c73aa2 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:45:03 -0800 -Subject: [PATCH 133/140] ARM64: Enable DWC_OTG Driver In ARM64 Build +Subject: [PATCH 128/187] ARM64: Enable DWC_OTG Driver In ARM64 Build Config(bcmrpi3_defconfig) Signed-off-by: Michael Zoran @@ -127844,10 +125986,10 @@ index 4670a490dfb1e582ec24a3b39a3cb9b2488b1864..8c4392344eb4495689c220d5d176ee8c CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From d0b7366a47e0582ee9848bda8ffa3d5996e97c1b Mon Sep 17 00:00:00 2001 +From 39d91c3f6eb913b61b5041cd1816770ebac505ed Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:46:04 -0800 -Subject: [PATCH 134/140] ARM64: Use dwc_otg driver by default for USB. +Subject: [PATCH 129/187] ARM64: Use dwc_otg driver by default for USB. If it breaks on anybody, they can use the standard device tree overlays to switch back to the dwc2 driver. @@ -127873,10 +126015,10 @@ index f6def5d7e5d622cf09e8f87332c7374fe28da08b..3e134a1208610b90e2d0fc22f03c6e9f -}; -#endif -From 5723ba9c29dc308ee19f7da6b70a4925ba54ca1c Mon Sep 17 00:00:00 2001 +From 7813c02fe43f9d4455abe5ac1c6b796470eade2d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 23 Jan 2017 17:36:50 +0000 -Subject: [PATCH 135/140] BCM270X_DT: Add reference to audio_pins to CM dtb +Subject: [PATCH 130/187] BCM270X_DT: Add reference to audio_pins to CM dtb The CM1 dtb contains an empty audio_pins node, but no reference to it. Adding the usual pinctrl reference from the audio node enables the @@ -127904,10 +126046,10 @@ index eb8662f0d222b4c0a9a2bcb8bccb13e86a0006b3..10be69972bd1440f574e35d515f3d6a0 hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; }; -From ba726d8da740161357c3b7a9e255625c5a1304bf Mon Sep 17 00:00:00 2001 +From 8410bf895888f1f20bf80d48a36f96383f76de9b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 25 Jan 2017 11:30:38 +0000 -Subject: [PATCH 136/140] config: Add additional network scheduling modules +Subject: [PATCH 131/187] config: Add additional network scheduling modules --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -127959,10 +126101,10 @@ index c4898d63d74718097ec3a1d1fe60b2307a6a3140..b448eaa866c200f48351819072c7fefc CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS_BASIC=m -From 2cd75a8398d19b0323ff47b166fbe612fb7b5c97 Mon Sep 17 00:00:00 2001 +From 1ab4fe548cc9dbe6dedfee18ddca1811c5562ab2 Mon Sep 17 00:00:00 2001 From: chris johnson Date: Sun, 22 Jan 2017 03:27:31 +0000 -Subject: [PATCH 137/140] ASoC: A simple-card overlay for ADAU7002 +Subject: [PATCH 132/187] ASoC: A simple-card overlay for ADAU7002 Usage: `dtoverlay=adau7002-simple` --- @@ -128060,10 +126202,10 @@ index 0000000000000000000000000000000000000000..e67e6625d7967abc92cf00cb604d4c12 + }; +}; -From 0570bcd7820363a26cf7bfbed6665a1d9268c702 Mon Sep 17 00:00:00 2001 +From 1c434c14fb7e622ff23d95f0837b94614127f701 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Jan 2017 21:17:23 +0000 -Subject: [PATCH 138/140] config: Add SND_SOC_ADAU7002 codec module +Subject: [PATCH 133/187] config: Add SND_SOC_ADAU7002 codec module As there is now an overlay requiring it, build the codec module. @@ -128098,10 +126240,10 @@ index b448eaa866c200f48351819072c7fefcd8ad8132..5105a592c9bcfee1cc6a8b50fd1c6c32 CONFIG_SND_SOC_WM8804_I2C=m CONFIG_SND_SIMPLE_CARD=m -From 87966e84bc93b3e7abda4b1d4fef3e2e0f4db1d6 Mon Sep 17 00:00:00 2001 +From f1af816d887be644255e2ece60875757d156a5d8 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Fri, 27 Jan 2017 06:42:42 -0500 -Subject: [PATCH 139/140] Add overlay for mcp3008 adc (#1818) +Subject: [PATCH 134/187] Add overlay for mcp3008 adc (#1818) Some example usage: @@ -128387,10 +126529,10 @@ index 0000000000000000000000000000000000000000..06bf4264959c380d8a9f90f74e780397 + }; +}; -From 2b2775a3943171ed31f958d5ad86ff478b8ce351 Mon Sep 17 00:00:00 2001 +From ec652ea2f70a6db722dbbc2fc2ac274fe6b4f008 Mon Sep 17 00:00:00 2001 From: ED6E0F17 Date: Fri, 3 Feb 2017 14:52:42 +0000 -Subject: [PATCH 140/140] usb: dwc2: Avoid suspending if we're in gadget mode +Subject: [PATCH 135/187] usb: dwc2: Avoid suspending if we're in gadget mode (#1825) I've found when booting HiKey with the usb gadget cable attached @@ -128441,3 +126583,8896 @@ index df5a065780054f21841ca9f08b8ab118922c530b..619ccfe1eafc4643b16970f8a1129ff9 if (!hsotg->core_params->hibernation) goto skip_power_saving; + +From d909483370a6c9793a9d4295933a17c3e04102d0 Mon Sep 17 00:00:00 2001 +From: JamesH65 +Date: Mon, 6 Feb 2017 15:24:47 +0000 +Subject: [PATCH 136/187] gpio_mem: Remove unnecessary dev_info output (#1830) + +The open function was spamming syslog every time +called, so have removed call completely. +--- + drivers/char/broadcom/bcm2835-gpiomem.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +index 911f5b7393ed48ceed8751f06967ae6463453f9c..f5e7f1ba8fb6f18dee77fad06a17480c6603cb4e 100644 +--- a/drivers/char/broadcom/bcm2835-gpiomem.c ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -76,8 +76,6 @@ static int bcm2835_gpiomem_open(struct inode *inode, struct file *file) + int dev = iminor(inode); + int ret = 0; + +- dev_info(inst->dev, "gpiomem device opened."); +- + if (dev != DEVICE_MINOR) { + dev_err(inst->dev, "Unknown minor device: %d", dev); + ret = -ENXIO; + +From 8c9140191f4c6753156aec36e31a253c34b9f54e Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 137/187] config: Enable regulator support + +Signed-off-by: Matthias Reichl +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 31163b59b9c6f2cc4f4f94afe1b10bd1a195470f..611b63c3fdf18f1df6288bb229f827ecd1619958 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -664,6 +664,8 @@ CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 5105a592c9bcfee1cc6a8b50fd1c6c32f1381158..74bc0d81bcb4d7f6676368926cdcc10e581fbcae 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -658,6 +658,8 @@ CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y + +From 1abcd09eb0db59b22c78234508194f6c4e71429f Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 138/187] BCM270x DT: expose 3.3V and 5V system rails + +Signed-off-by: Matthias Reichl +--- + arch/arm/boot/dts/bcm270x.dtsi | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi +index a46cb4a8b1419edd95e0e07c18b0f373222dc2bf..36d853715f2379e1952ce3d3be58dd670e305159 100644 +--- a/arch/arm/boot/dts/bcm270x.dtsi ++++ b/arch/arm/boot/dts/bcm270x.dtsi +@@ -138,4 +138,20 @@ + status = "disabled"; + }; + }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "5v0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; + }; + +From 3b33b3f1a3395b6dbc560073e2374b11e2d89228 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:36 +0100 +Subject: [PATCH 139/187] BCM270x DT: Consolidate audio card overlays + +Reference 3.3V / 5V system rails instead of instantiating local +regulators. + +Add missing power supply properties for codecs where these are +required according to the DT bindings docs. + +Signed-off-by: Matthias Reichl +--- + .../arm/boot/dts/overlays/adau1977-adc-overlay.dts | 19 ++-------- + .../dts/overlays/akkordion-iqdacplus-overlay.dts | 3 ++ + .../dts/overlays/hifiberry-dacplus-overlay.dts | 3 ++ + .../boot/dts/overlays/hifiberry-digi-overlay.dts | 2 + + .../dts/overlays/hifiberry-digi-pro-overlay.dts | 2 + + arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 3 ++ + .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 3 ++ + .../overlays/iqaudio-digi-wm8804-audio-overlay.dts | 4 +- + .../arm/boot/dts/overlays/justboom-dac-overlay.dts | 3 ++ + .../boot/dts/overlays/justboom-digi-overlay.dts | 2 + + arch/arm/boot/dts/overlays/raspidac3-overlay.dts | 4 ++ + .../overlays/rra-digidac1-wm8741-audio-overlay.dts | 44 +++------------------- + 12 files changed, 36 insertions(+), 56 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts +index 24fcd58fd1dc61d97a77def3d5d1f7c65130dde6..1aaca71c1b677e414ada9a3f94e60e5e2cf30815 100644 +--- a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts +@@ -6,19 +6,6 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; +- +- __overlay__ { +- codec_supply: fixedregulator@0 { +- compatible = "regulator-fixed"; +- regulator-name = "AVDD"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- }; +- }; +- +- fragment@1 { + target = <&i2c>; + + __overlay__ { +@@ -30,19 +17,19 @@ + compatible = "adi,adau1977"; + reg = <0x11>; + reset-gpios = <&gpio 5 0>; +- AVDD-supply = <&codec_supply>; ++ AVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; + +- fragment@2 { ++ fragment@1 { + target = <&i2s>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@3 { ++ fragment@2 { + target = <&sound>; + __overlay__ { + compatible = "adi,adau1977-adc"; +diff --git a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts +index 208849d5c39274ed0aa557f63a19430a451a95f5..241d03b9b79ef5e833cc28819003946a9eb319fd 100644 +--- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +index 2f078d4747ccfdc5172e24b18ce65454f1219b9d..b4dc99633b9d409565c0443de378a4460c7a966a 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -34,6 +34,9 @@ + compatible = "ti,pcm5122"; + reg = <0x4d>; + clocks = <&dacpro_osc>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts +index f5e41f48ba4fed92194ff5a63d13c70bb2d1c091..64cb1e00343b57e3d7dee864416e558dc3163117 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts +index 2a26d9cfffb0f3d7958eb3756ca7c4ba28400e1c..d02479ca4a25c3b2da75fe737fd457b1882c20b1 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts +index 0d35c85382bb5766b3eeb9de1bd4a94621229e4b..f16586f05971f69b928200d212015982e388ce96 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +index d4bad8742a985e2f15eed19ca52ef283a74fefb9..4dcf17515f95589addd5194cf825be813d1e0c98 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts +index da4fbfdfdbbbcf2505b9eb4789ddb779ec72cea8..b86e1e5edc89fb78fd1ab8482bfff6c7ec4ec9f5 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts +@@ -24,8 +24,8 @@ + compatible = "wlf,wm8804"; + reg = <0x3b>; + status = "okay"; +- // DVDD-supply = <®_3v3>; +- // PVDD-supply = <®_3v3>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ PVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts +index 312632ad376d5b8c8ff1dbf31fa03d0d18181d94..2b8dba0c231b20ac7660152356a06abeacc83c2d 100644 +--- a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts +@@ -23,6 +23,9 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4d>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts +index cbbede9a541166ba257122918081982016e0b7eb..1212e3ff591b6071604ee4a519c89ec50ac95d00 100644 +--- a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts +@@ -23,6 +23,8 @@ + #sound-dai-cells = <0>; + compatible = "wlf,wm8804"; + reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/raspidac3-overlay.dts b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts +index 2fac57ca179fcf114655ea91dbef419c16aceb79..2c3c97813f22c94eff6da2193aff0920ac7c39b1 100644 +--- a/arch/arm/boot/dts/overlays/raspidac3-overlay.dts ++++ b/arch/arm/boot/dts/overlays/raspidac3-overlay.dts +@@ -23,12 +23,16 @@ + #sound-dai-cells = <0>; + compatible = "ti,pcm5122"; + reg = <0x4c>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + + tpa6130a2: tpa6130a2@60 { + compatible = "ti,tpa6130a2"; + reg = <0x60>; ++ Vdd-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts +index 16b1247bfa618ff85936ddf78c3aea58075eaa67..f8d48233e28c7c18509b4a95692f6aff29ea33fd 100644 +--- a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts +@@ -6,45 +6,13 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target-path = "/"; +- __overlay__ { +- aliases { +- ldo0 = &ldo0; +- ldo1 = &ldo1; +- }; +- }; +- }; +- +- fragment@1 { +- target-path = "/soc"; +- __overlay__ { +- +- ldo1: ldo1 { +- compatible = "regulator-fixed"; +- regulator-name = "DC_5V"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-always-on; +- }; +- +- ldo0: ldo0 { +- compatible = "regulator-fixed"; +- regulator-name = "DC_3V3"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- }; +- }; +- +- fragment@2 { + target = <&i2s>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@3 { ++ fragment@1 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; +@@ -56,21 +24,21 @@ + compatible = "wlf,wm8804"; + reg = <0x3b>; + status = "okay"; +- PVDD-supply = <&ldo0>; +- DVDD-supply = <&ldo0>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + }; + + wm8742: wm8741@1a { + compatible = "wlf,wm8741"; + reg = <0x1a>; + status = "okay"; +- AVDD-supply = <&ldo1>; +- DVDD-supply = <&ldo0>; ++ AVDD-supply = <&vdd_5v0_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; + }; + }; + }; + +- fragment@4 { ++ fragment@2 { + target = <&sound>; + __overlay__ { + compatible = "rra,digidac1-soundcard"; + +From 1cc84b5f80871ee81f439f4e7571edef15242a6f Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:37 +0100 +Subject: [PATCH 140/187] ASoC: Add driver for Cirrus Logic Audio Card + +Note: due to problems with deferred probing of regulators +the following softdep should be added to a modprobe.d file + +softdep arizona-spi pre: arizona-ldo1 + +Signed-off-by: Matthias Reichl +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 + + .../dts/overlays/rpi-cirrus-wm5102-overlay.dts | 146 +++ + sound/soc/bcm/Kconfig | 9 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/rpi-cirrus.c | 1003 ++++++++++++++++++++ + 6 files changed, 1167 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts + create mode 100644 sound/soc/bcm/rpi-cirrus.c + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index e915dff8a4cdf5af3df0aa519b3ee08dd970d831..0a7d30cd573060964bb081ee6617d5b77a17b974 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -68,6 +68,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + qca7000.dtbo \ + raspidac3.dtbo \ + rpi-backlight.dtbo \ ++ rpi-cirrus-wm5102.dtbo \ + rpi-dac.dtbo \ + rpi-display.dtbo \ + rpi-ft5406.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index aa9b6128c397b33e9c40eec29476d8352933c237..46228fd324fc4c52eb0ba50316b4c02f8245bf04 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -995,6 +995,12 @@ Load: dtoverlay=rpi-backlight + Params: + + ++Name: rpi-cirrus-wm5102 ++Info: Configures the Cirrus Logic Audio Card ++Load: dtoverlay=rpi-cirrus-wm5102 ++Params: ++ ++ + Name: rpi-dac + Info: Configures the RPi DAC audio card + Load: dtoverlay=rpi-dac +diff --git a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..cf85f0af224067cf58053a143664f0716d5ce71a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +@@ -0,0 +1,146 @@ ++// Definitions for the Cirrus Logic Audio Card ++/dts-v1/; ++/plugin/; ++#include ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ wlf_pins: wlf_pins { ++ brcm,pins = <17 22 27 8>; ++ brcm,function = < ++ BCM2835_FSEL_GPIO_OUT ++ BCM2835_FSEL_GPIO_OUT ++ BCM2835_FSEL_GPIO_IN ++ BCM2835_FSEL_GPIO_OUT ++ >; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "RPi-Cirrus 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&spi0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ ++ wm5102@1{ ++ compatible = "wlf,wm5102"; ++ reg = <1>; ++ ++ spi-max-frequency = <500000>; ++ ++ interrupt-parent = <&gpio>; ++ interrupts = <27 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ LDOVDD-supply = <&rpi_cirrus_reg_1v8>; ++ AVDD-supply = <&rpi_cirrus_reg_1v8>; ++ DBVDD1-supply = <&rpi_cirrus_reg_1v8>; ++ DBVDD2-supply = <&vdd_3v3_reg>; ++ DBVDD3-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&rpi_cirrus_reg_1v8>; ++ SPKVDDL-supply = <&vdd_5v0_reg>; ++ SPKVDDR-supply = <&vdd_5v0_reg>; ++ DCVDD-supply = <&arizona_ldo1>; ++ ++ wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>; ++ wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>; ++ wlf,gpio-defaults = < ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ ARIZONA_GP_DEFAULT ++ >; ++ wlf,micd-configs = <0 1 0>; ++ wlf,dmic-ref = < ++ ARIZONA_DMIC_MICVDD ++ ARIZONA_DMIC_MICBIAS2 ++ ARIZONA_DMIC_MICVDD ++ ARIZONA_DMIC_MICVDD ++ >; ++ wlf,inmode = < ++ ARIZONA_INMODE_DIFF ++ ARIZONA_INMODE_DMIC ++ ARIZONA_INMODE_SE ++ ARIZONA_INMODE_DIFF ++ >; ++ status = "okay"; ++ ++ arizona_ldo1: ldo1 { ++ regulator-name = "LDO1"; ++ // default constraints as in ++ // arizona-ldo1.c ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wm8804@3b { ++ compatible = "wlf,wm8804"; ++ reg = <0x3b>; ++ status = "okay"; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "wlf,rpi-cirrus"; ++ i2s-controller = <&i2s>; ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig +index d024377e8450fb5402dcb5ea27161f774b04a8ec..10f6b201777946af8e8e78d2ffb0b0cff38093df 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -45,6 +45,15 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP + help + Say Y or M if you want to add support for the HifiBerry Amp amplifier board. + ++config SND_BCM2708_SOC_RPI_CIRRUS ++ tristate "Support for Cirrus Logic Audio Card" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_WM5102 ++ select SND_SOC_WM8804 ++ help ++ Say Y or M if you want to add support for the Wolfson and ++ Cirrus Logic audio cards. ++ + config SND_BCM2708_SOC_RPI_DAC + tristate "Support for RPi-DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index bb1df438540193652ec5464e8bc51f636a1b844e..84c2b20ce2e51b525797ee58de95734ee7847e15 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o + snd-soc-hifiberry-digi-objs := hifiberry_digi.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-justboom-digi-objs := justboom-digi.o ++snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-dac-objs := rpi-dac.o + snd-soc-rpi-proto-objs := rpi-proto.o + snd-soc-iqaudio-dac-objs := iqaudio-dac.o +@@ -34,6 +35,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o ++obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o + obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o +diff --git a/sound/soc/bcm/rpi-cirrus.c b/sound/soc/bcm/rpi-cirrus.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ac8651ddff7bd3701dffe22c7fb88352f912dff3 +--- /dev/null ++++ b/sound/soc/bcm/rpi-cirrus.c +@@ -0,0 +1,1003 @@ ++/* ++ * ASoC machine driver for Cirrus Logic Audio Card ++ * (with WM5102 and WM8804 codecs) ++ * ++ * Copyright 2015-2017 Matthias Reichl ++ * ++ * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "../codecs/wm5102.h" ++#include "../codecs/wm8804.h" ++ ++#define WM8804_CLKOUT_HZ 12000000 ++ ++#define RPI_CIRRUS_DEFAULT_RATE 44100 ++#define WM5102_MAX_SYSCLK_1 49152000 /* max sysclk for 4K family */ ++#define WM5102_MAX_SYSCLK_2 45158400 /* max sysclk for 11.025K family */ ++ ++static inline unsigned int calc_sysclk(unsigned int rate) ++{ ++ return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1; ++} ++ ++enum { ++ DAI_WM5102 = 0, ++ DAI_WM8804, ++}; ++ ++struct rpi_cirrus_priv { ++ /* mutex for synchronzing FLL1 access with DAPM */ ++ struct mutex lock; ++ unsigned int card_rate; ++ int sync_path_enable; ++ int fll1_freq; /* negative means RefClock in spdif rx case */ ++ ++ /* track hw params/free for substreams */ ++ unsigned int params_set; ++ unsigned int min_rate_idx, max_rate_idx; ++ unsigned char iec958_status[4]; ++}; ++ ++/* helper functions */ ++static inline struct snd_soc_pcm_runtime *get_wm5102_runtime( ++ struct snd_soc_card *card) { ++ return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); ++} ++ ++static inline struct snd_soc_pcm_runtime *get_wm8804_runtime( ++ struct snd_soc_card *card) { ++ return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name); ++} ++ ++ ++struct rate_info { ++ unsigned int value; ++ char *text; ++}; ++ ++static struct rate_info min_rates[] = { ++ { 0, "off"}, ++ { 32000, "32kHz"}, ++ { 44100, "44.1kHz"} ++}; ++ ++#define NUM_MIN_RATES ARRAY_SIZE(min_rates) ++ ++static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_MIN_RATES; ++ ++ if (uinfo->value.enumerated.item >= NUM_MIN_RATES) ++ uinfo->value.enumerated.item = NUM_MIN_RATES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ min_rates[uinfo->value.enumerated.item].text); ++ return 0; ++} ++ ++static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ ++ ucontrol->value.enumerated.item[0] = priv->min_rate_idx; ++ return 0; ++} ++ ++static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int changed = 0; ++ ++ if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) { ++ changed = 1; ++ priv->min_rate_idx = ucontrol->value.enumerated.item[0]; ++ } ++ ++ return changed; ++} ++ ++static struct rate_info max_rates[] = { ++ { 0, "off"}, ++ { 48000, "48kHz"}, ++ { 96000, "96kHz"} ++}; ++ ++#define NUM_MAX_RATES ARRAY_SIZE(max_rates) ++ ++static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_MAX_RATES; ++ if (uinfo->value.enumerated.item >= NUM_MAX_RATES) ++ uinfo->value.enumerated.item = NUM_MAX_RATES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ max_rates[uinfo->value.enumerated.item].text); ++ return 0; ++} ++ ++static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ ++ ucontrol->value.enumerated.item[0] = priv->max_rate_idx; ++ return 0; ++} ++ ++static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int changed = 0; ++ ++ if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) { ++ changed = 1; ++ priv->max_rate_idx = ucontrol->value.enumerated.item[0]; ++ } ++ ++ return changed; ++} ++ ++static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ ucontrol->value.iec958.status[i] = priv->iec958_status[i]; ++ ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned char *stat = priv->iec958_status; ++ unsigned char *ctrl_stat = ucontrol->value.iec958.status; ++ unsigned int mask; ++ int i, changed = 0; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ if ((ctrl_stat[i] & mask) != (stat[i] & mask)) { ++ changed = 1; ++ stat[i] = ctrl_stat[i] & mask; ++ snd_soc_update_bits(wm8804_codec, ++ WM8804_SPDTX1 + i, mask, stat[i]); ++ } ++ } ++ ++ return changed; ++} ++ ++static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ ucontrol->value.iec958.status[0] = 0xff; ++ ucontrol->value.iec958.status[1] = 0xff; ++ ucontrol->value.iec958.status[2] = 0xff; ++ ucontrol->value.iec958.status[3] = 0x3f; ++ ++ return 0; ++} ++ ++static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ unsigned int mask; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ ucontrol->value.iec958.status[i] = ++ snd_soc_read(wm8804_codec, WM8804_RXCHAN1 + i) & mask; ++ } ++ ++ return 0; ++} ++ ++#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \ ++{ \ ++ .access = SNDRV_CTL_ELEM_ACCESS_READ \ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) \ ++ desc " Flag", \ ++ .info = snd_ctl_boolean_mono_info, \ ++ .get = rpi_cirrus_spdif_status_flag_get, \ ++ .private_value = \ ++ (bit) | ((reg) << 8) | ((invert) << 16) \ ++} ++ ++static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ ++ unsigned int bit = kcontrol->private_value & 0xff; ++ unsigned int reg = (kcontrol->private_value >> 8) & 0xff; ++ unsigned int invert = (kcontrol->private_value >> 16) & 0xff; ++ ++ bool flag = snd_soc_read(wm8804_codec, reg) & (1 << bit); ++ ++ ucontrol->value.integer.value[0] = invert ? !flag : flag; ++ ++ return 0; ++} ++ ++static const char * const recovered_frequency_texts[] = { ++ "176.4/192 kHz", ++ "88.2/96 kHz", ++ "44.1/48 kHz", ++ "32 kHz" ++}; ++ ++#define NUM_RECOVERED_FREQUENCIES \ ++ ARRAY_SIZE(recovered_frequency_texts) ++ ++static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->count = 1; ++ uinfo->value.enumerated.items = NUM_RECOVERED_FREQUENCIES; ++ if (uinfo->value.enumerated.item >= NUM_RECOVERED_FREQUENCIES) ++ uinfo->value.enumerated.item = NUM_RECOVERED_FREQUENCIES - 1; ++ strcpy(uinfo->value.enumerated.name, ++ recovered_frequency_texts[uinfo->value.enumerated.item]); ++ return 0; ++} ++ ++static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); ++ struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec; ++ ++ ucontrol->value.enumerated.item[0] = ++ (snd_soc_read(wm8804_codec, WM8804_SPDSTAT) >> 4) & 0x03; ++ return 0; ++} ++ ++static const struct snd_kcontrol_new rpi_cirrus_controls[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Min Sample Rate", ++ .info = rpi_cirrus_min_rate_info, ++ .get = rpi_cirrus_min_rate_get, ++ .put = rpi_cirrus_min_rate_put, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Max Sample Rate", ++ .info = rpi_cirrus_max_rate_info, ++ .get = rpi_cirrus_max_rate_get, ++ .put = rpi_cirrus_max_rate_put, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_playback_get, ++ .put = rpi_cirrus_spdif_playback_put, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_capture_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), ++ .info = rpi_cirrus_spdif_info, ++ .get = rpi_cirrus_spdif_mask_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ ++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) ++ "Recovered Frequency", ++ .info = rpi_cirrus_recovered_frequency_info, ++ .get = rpi_cirrus_recovered_frequency_get, ++ }, ++ SPDIF_FLAG_CTRL("Audio", WM8804_SPDSTAT, 0, 1), ++ SPDIF_FLAG_CTRL("Non-PCM", WM8804_SPDSTAT, 1, 0), ++ SPDIF_FLAG_CTRL("Copyright", WM8804_SPDSTAT, 2, 1), ++ SPDIF_FLAG_CTRL("De-Emphasis", WM8804_SPDSTAT, 3, 0), ++ SPDIF_FLAG_CTRL("Lock", WM8804_SPDSTAT, 6, 1), ++ SPDIF_FLAG_CTRL("Invalid", WM8804_INTSTAT, 1, 0), ++ SPDIF_FLAG_CTRL("TransErr", WM8804_INTSTAT, 3, 0), ++}; ++ ++static const char * const linein_micbias_texts[] = { ++ "off", "on", ++}; ++ ++static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum, ++ linein_micbias_texts); ++ ++static const struct snd_kcontrol_new linein_micbias_mux = ++ SOC_DAPM_ENUM("Route", linein_micbias_enum); ++ ++static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event); ++ ++const struct snd_soc_dapm_widget rpi_cirrus_dapm_widgets[] = { ++ SND_SOC_DAPM_MIC("DMIC", NULL), ++ SND_SOC_DAPM_MIC("Headset Mic", NULL), ++ SND_SOC_DAPM_INPUT("Line Input"), ++ SND_SOC_DAPM_MIC("Line Input with Micbias", NULL), ++ SND_SOC_DAPM_MUX("Line Input Micbias", SND_SOC_NOPM, 0, 0, ++ &linein_micbias_mux), ++ SND_SOC_DAPM_INPUT("dummy SPDIF in"), ++ SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0, NULL, 0, ++ rpi_cirrus_spdif_rx_enable_event, ++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_INPUT("Dummy Input"), ++ SND_SOC_DAPM_OUTPUT("Dummy Output"), ++}; ++ ++const struct snd_soc_dapm_route rpi_cirrus_dapm_routes[] = { ++ { "IN1L", NULL, "Headset Mic" }, ++ { "IN1R", NULL, "Headset Mic" }, ++ { "Headset Mic", NULL, "MICBIAS1" }, ++ ++ { "IN2L", NULL, "DMIC" }, ++ { "IN2R", NULL, "DMIC" }, ++ { "DMIC", NULL, "MICBIAS2" }, ++ ++ { "IN3L", NULL, "Line Input Micbias" }, ++ { "IN3R", NULL, "Line Input Micbias" }, ++ ++ { "Line Input Micbias", "off", "Line Input" }, ++ { "Line Input Micbias", "on", "Line Input with Micbias" }, ++ ++ /* Make sure MICVDD is enabled, otherwise we get noise */ ++ { "Line Input", NULL, "MICVDD" }, ++ { "Line Input with Micbias", NULL, "MICBIAS3" }, ++ ++ /* Dummy routes to check whether SPDIF RX is enabled or not */ ++ {"dummy SPDIFRX", NULL, "dummy SPDIF in"}, ++ {"AIFTX", NULL, "dummy SPDIFRX"}, ++ ++ /* ++ * Dummy routes to keep wm5102 from staying off on ++ * playback/capture if all mixers are off. ++ */ ++ { "Dummy Output", NULL, "AIF1RX1" }, ++ { "Dummy Output", NULL, "AIF1RX2" }, ++ { "AIF1TX1", NULL, "Dummy Input" }, ++ { "AIF1TX2", NULL, "Dummy Input" }, ++}; ++ ++static int rpi_cirrus_clear_flls(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec) { ++ ++ int ret1, ret2; ++ ++ ret1 = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); ++ ret2 = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0); ++ ++ if (ret1) { ++ dev_warn(card->dev, ++ "setting FLL1 to zero failed: %d\n", ret1); ++ return ret1; ++ } ++ if (ret2) { ++ dev_warn(card->dev, ++ "setting FLL1_REFCLK to zero failed: %d\n", ret2); ++ return ret2; ++ } ++ return 0; ++} ++ ++static int rpi_cirrus_set_fll(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec, unsigned int clk_freq) ++{ ++ int ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ++ ARIZONA_CLK_SRC_MCLK1, ++ WM8804_CLKOUT_HZ, ++ clk_freq); ++ if (ret) ++ dev_err(card->dev, "Failed to set FLL1 to %d: %d\n", ++ clk_freq, ret); ++ ++ usleep_range(1000, 2000); ++ return ret; ++} ++ ++static int rpi_cirrus_set_fll_refclk(struct snd_soc_card *card, ++ struct snd_soc_codec *wm5102_codec, ++ unsigned int clk_freq, unsigned int aif2_freq) ++{ ++ int ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1_REFCLK, ++ ARIZONA_CLK_SRC_MCLK1, ++ WM8804_CLKOUT_HZ, ++ clk_freq); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set FLL1_REFCLK to %d: %d\n", ++ clk_freq, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_codec_set_pll(wm5102_codec, ++ WM5102_FLL1, ++ ARIZONA_CLK_SRC_AIF2BCLK, ++ aif2_freq, clk_freq); ++ if (ret) ++ dev_err(card->dev, ++ "Failed to set FLL1 with Sync Clock %d to %d: %d\n", ++ aif2_freq, clk_freq, ret); ++ ++ usleep_range(1000, 2000); ++ return ret; ++} ++ ++static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_card *card = w->dapm->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_codec *wm5102_codec = get_wm5102_runtime(card)->codec; ++ ++ unsigned int clk_freq, aif2_freq; ++ int ret = 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ mutex_lock(&priv->lock); ++ ++ /* Enable sync path in case of SPDIF capture use case */ ++ ++ clk_freq = calc_sysclk(priv->card_rate); ++ aif2_freq = 64 * priv->card_rate; ++ ++ dev_dbg(card->dev, ++ "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n", ++ clk_freq, aif2_freq); ++ ++ ret = rpi_cirrus_clear_flls(card, wm5102_codec); ++ if (ret) { ++ dev_err(card->dev, "spdif_rx: failed to clear FLLs\n"); ++ goto out; ++ } ++ ++ ret = rpi_cirrus_set_fll_refclk(card, wm5102_codec, ++ clk_freq, aif2_freq); ++ ++ if (ret) { ++ dev_err(card->dev, "spdif_rx: failed to set FLLs\n"); ++ goto out; ++ } ++ ++ /* set to negative to indicate we're doing spdif rx */ ++ priv->fll1_freq = -clk_freq; ++ priv->sync_path_enable = 1; ++ break; ++ ++ case SND_SOC_DAPM_POST_PMD: ++ mutex_lock(&priv->lock); ++ priv->sync_path_enable = 0; ++ break; ++ ++ default: ++ return 0; ++ } ++ ++out: ++ mutex_unlock(&priv->lock); ++ return ret; ++} ++ ++static int rpi_cirrus_set_bias_level(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, ++ enum snd_soc_bias_level level) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec; ++ ++ int ret = 0; ++ unsigned int clk_freq; ++ ++ if (dapm->dev != wm5102_runtime->codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_PREPARE: ++ if (dapm->bias_level == SND_SOC_BIAS_ON) ++ break; ++ ++ mutex_lock(&priv->lock); ++ ++ if (!priv->sync_path_enable) { ++ clk_freq = calc_sysclk(priv->card_rate); ++ ++ dev_dbg(card->dev, ++ "set_bias: changing FLL1 from %d to %d\n", ++ priv->fll1_freq, clk_freq); ++ ++ ret = rpi_cirrus_set_fll(card, wm5102_codec, clk_freq); ++ if (ret) ++ dev_err(card->dev, ++ "set_bias: Failed to set FLL1\n"); ++ else ++ priv->fll1_freq = clk_freq; ++ } ++ mutex_unlock(&priv->lock); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static int rpi_cirrus_set_bias_level_post(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, ++ enum snd_soc_bias_level level) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec; ++ ++ if (dapm->dev != wm5102_runtime->codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_STANDBY: ++ mutex_lock(&priv->lock); ++ ++ dev_dbg(card->dev, ++ "set_bias_post: changing FLL1 from %d to off\n", ++ priv->fll1_freq); ++ ++ if (rpi_cirrus_clear_flls(card, wm5102_codec)) ++ dev_err(card->dev, ++ "set_bias_post: failed to clear FLLs\n"); ++ else ++ priv->fll1_freq = 0; ++ ++ mutex_unlock(&priv->lock); ++ ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card, ++ struct snd_soc_dai *wm8804_dai, unsigned int rate) ++{ ++ int ret; ++ ++ /* use 256fs */ ++ unsigned int clk_freq = rate * 256; ++ ++ ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0, ++ WM8804_CLKOUT_HZ, clk_freq); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret); ++ return ret; ++ } ++ ++ /* Set MCLK as PLL Output */ ++ ret = snd_soc_dai_set_sysclk(wm8804_dai, ++ WM8804_TX_CLKSRC_PLL, clk_freq, 0); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set MCLK as PLL Output: %d\n", ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int rpi_cirrus_startup(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned int min_rate = min_rates[priv->min_rate_idx].value; ++ unsigned int max_rate = max_rates[priv->max_rate_idx].value; ++ ++ if (min_rate || max_rate) { ++ if (max_rate == 0) ++ max_rate = UINT_MAX; ++ ++ dev_dbg(card->dev, ++ "startup: limiting rate to %u-%u\n", ++ min_rate, max_rate); ++ ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate); ++ } ++ ++ return 0; ++} ++ ++static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = { ++ .formats = SNDRV_PCM_FMTBIT_S24_LE, ++ .channels_min = 2, ++ .channels_max = 2, ++ .rate_min = RPI_CIRRUS_DEFAULT_RATE, ++ .rate_max = RPI_CIRRUS_DEFAULT_RATE, ++}; ++ ++static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_dai *bcm_i2s_dai = rtd->cpu_dai; ++ struct snd_soc_codec *wm5102_codec = rtd->codec; ++ struct snd_soc_dai *wm8804_dai = get_wm8804_runtime(card)->codec_dai; ++ ++ int ret; ++ ++ unsigned int width = snd_pcm_format_physical_width( ++ params_format(params)); ++ unsigned int rate = params_rate(params); ++ unsigned int clk_freq = calc_sysclk(rate); ++ ++ mutex_lock(&priv->lock); ++ ++ dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate); ++ ++ ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width); ++ if (ret) { ++ dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret); ++ goto out; ++ } ++ ++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03, 2, width); ++ if (ret) { ++ dev_err(card->dev, "set_tdm_slot failed: %d\n", ret); ++ goto out; ++ } ++ ++ /* WM8804 supports sample rates from 32k only */ ++ if (rate >= 32000) { ++ ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate); ++ if (ret) ++ goto out; ++ } ++ ++ ret = snd_soc_codec_set_sysclk(wm5102_codec, ++ ARIZONA_CLK_SYSCLK, ++ ARIZONA_CLK_SRC_FLL1, ++ clk_freq, ++ SND_SOC_CLOCK_IN); ++ if (ret) { ++ dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret); ++ goto out; ++ } ++ ++ if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) { ++ dev_dbg(card->dev, ++ "hw_params: changing FLL1 from %d to %d\n", ++ priv->fll1_freq, clk_freq); ++ ++ if (rpi_cirrus_clear_flls(card, wm5102_codec)) { ++ dev_err(card->dev, "hw_params: failed to clear FLLs\n"); ++ goto out; ++ } ++ ++ if (rpi_cirrus_set_fll(card, wm5102_codec, clk_freq)) { ++ dev_err(card->dev, "hw_params: failed to set FLL\n"); ++ goto out; ++ } ++ ++ priv->fll1_freq = clk_freq; ++ } ++ ++ priv->card_rate = rate; ++ rpi_cirrus_dai_link2_params.rate_min = rate; ++ rpi_cirrus_dai_link2_params.rate_max = rate; ++ ++ priv->params_set |= 1 << substream->stream; ++ ++out: ++ mutex_unlock(&priv->lock); ++ ++ return ret; ++} ++ ++static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_codec *wm5102_codec = rtd->codec; ++ int ret; ++ unsigned int old_params_set = priv->params_set; ++ ++ priv->params_set &= ~(1 << substream->stream); ++ ++ /* disable sysclk if this was the last open stream */ ++ if (priv->params_set == 0 && old_params_set) { ++ dev_dbg(card->dev, ++ "hw_free: Setting SYSCLK to Zero\n"); ++ ++ ret = snd_soc_codec_set_sysclk(wm5102_codec, ++ ARIZONA_CLK_SYSCLK, ++ ARIZONA_CLK_SRC_FLL1, ++ 0, ++ SND_SOC_CLOCK_IN); ++ if (ret) ++ dev_err(card->dev, ++ "hw_free: Failed to set SYSCLK to Zero: %d\n", ++ ret); ++ } ++ return 0; ++} ++ ++static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ int ret; ++ ++ /* no 32kHz input, derive it from sysclk if needed */ ++ snd_soc_update_bits(codec, ++ ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, 2); ++ ++ if (rpi_cirrus_clear_flls(rtd->card, codec)) ++ dev_warn(rtd->card->dev, ++ "init_wm5102: failed to clear FLLs\n"); ++ ++ ret = snd_soc_codec_set_sysclk(codec, ++ ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, ++ 0, SND_SOC_CLOCK_IN); ++ if (ret) { ++ dev_err(rtd->card->dev, ++ "Failed to set SYSCLK to Zero: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_card *card = rtd->card; ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ unsigned int mask; ++ int i, ret; ++ ++ for (i = 0; i < 4; i++) { ++ mask = (i == 3) ? 0x3f : 0xff; ++ priv->iec958_status[i] = ++ snd_soc_read(codec, WM8804_SPDTX1 + i) & mask; ++ } ++ ++ /* Setup for 256fs */ ++ ret = snd_soc_dai_set_clkdiv(codec_dai, ++ WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS); ++ if (ret) { ++ dev_err(card->dev, ++ "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Output OSC on CLKOUT */ ++ ret = snd_soc_dai_set_sysclk(codec_dai, ++ WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0); ++ if (ret) ++ dev_err(card->dev, ++ "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n", ++ ret); ++ ++ /* Init PLL with default samplerate */ ++ ret = rpi_cirrus_set_wm8804_pll(card, codec_dai, ++ RPI_CIRRUS_DEFAULT_RATE); ++ if (ret) ++ dev_err(card->dev, ++ "init_wm8804: Failed to setup PLL for %dHz: %d\n", ++ RPI_CIRRUS_DEFAULT_RATE, ret); ++ ++ return ret; ++} ++ ++static struct snd_soc_ops rpi_cirrus_ops = { ++ .startup = rpi_cirrus_startup, ++ .hw_params = rpi_cirrus_hw_params, ++ .hw_free = rpi_cirrus_hw_free, ++}; ++ ++static struct snd_soc_dai_link rpi_cirrus_dai[] = { ++ [DAI_WM5102] = { ++ .name = "WM5102", ++ .stream_name = "WM5102 AiFi", ++ .codec_dai_name = "wm5102-aif1", ++ .codec_name = "wm5102-codec", ++ .dai_fmt = SND_SOC_DAIFMT_I2S ++ | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM, ++ .ops = &rpi_cirrus_ops, ++ .init = rpi_cirrus_init_wm5102, ++ }, ++ [DAI_WM8804] = { ++ .name = "WM5102 SPDIF", ++ .stream_name = "SPDIF Tx/Rx", ++ .cpu_dai_name = "wm5102-aif2", ++ .codec_dai_name = "wm8804-spdif", ++ .codec_name = "wm8804.1-003b", ++ .dai_fmt = SND_SOC_DAIFMT_I2S ++ | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM, ++ .ignore_suspend = 1, ++ .params = &rpi_cirrus_dai_link2_params, ++ .init = rpi_cirrus_init_wm8804, ++ }, ++}; ++ ++ ++static int rpi_cirrus_late_probe(struct snd_soc_card *card) ++{ ++ struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card); ++ struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card); ++ struct snd_soc_pcm_runtime *wm8804_runtime = get_wm8804_runtime(card); ++ int ret; ++ ++ dev_dbg(card->dev, "iec958_bits: %02x %02x %02x %02x\n", ++ priv->iec958_status[0], ++ priv->iec958_status[1], ++ priv->iec958_status[2], ++ priv->iec958_status[3]); ++ ++ ret = snd_soc_dai_set_sysclk( ++ wm5102_runtime->codec_dai, ARIZONA_CLK_SYSCLK, 0, 0); ++ if (ret) { ++ dev_err(card->dev, ++ "Failed to set WM5102 codec dai clk domain: %d\n", ret); ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_sysclk( ++ wm8804_runtime->cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0); ++ if (ret) ++ dev_err(card->dev, ++ "Failed to set WM8804 codec dai clk domain: %d\n", ret); ++ ++ return ret; ++} ++ ++/* audio machine driver */ ++static struct snd_soc_card rpi_cirrus_card = { ++ .name = "RPi-Cirrus", ++ .driver_name = "RPiCirrus", ++ .owner = THIS_MODULE, ++ .dai_link = rpi_cirrus_dai, ++ .num_links = ARRAY_SIZE(rpi_cirrus_dai), ++ .late_probe = rpi_cirrus_late_probe, ++ .controls = rpi_cirrus_controls, ++ .num_controls = ARRAY_SIZE(rpi_cirrus_controls), ++ .dapm_widgets = rpi_cirrus_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(rpi_cirrus_dapm_widgets), ++ .dapm_routes = rpi_cirrus_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(rpi_cirrus_dapm_routes), ++ .set_bias_level = rpi_cirrus_set_bias_level, ++ .set_bias_level_post = rpi_cirrus_set_bias_level_post, ++}; ++ ++static int rpi_cirrus_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct rpi_cirrus_priv *priv; ++ struct device_node *i2s_node; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->min_rate_idx = 1; /* min samplerate 32kHz */ ++ priv->card_rate = RPI_CIRRUS_DEFAULT_RATE; ++ ++ mutex_init(&priv->lock); ++ ++ snd_soc_card_set_drvdata(&rpi_cirrus_card, priv); ++ ++ if (!pdev->dev.of_node) ++ return -ENODEV; ++ ++ i2s_node = of_parse_phandle( ++ pdev->dev.of_node, "i2s-controller", 0); ++ if (!i2s_node) { ++ dev_err(&pdev->dev, "i2s-controller missing in DT\n"); ++ return -ENODEV; ++ } ++ ++ rpi_cirrus_dai[DAI_WM5102].cpu_of_node = i2s_node; ++ rpi_cirrus_dai[DAI_WM5102].platform_of_node = i2s_node; ++ ++ rpi_cirrus_card.dev = &pdev->dev; ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card); ++ if (ret) { ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(&pdev->dev, ++ "register card requested probe deferral\n"); ++ else ++ dev_err(&pdev->dev, ++ "Failed to register card: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static const struct of_device_id rpi_cirrus_of_match[] = { ++ { .compatible = "wlf,rpi-cirrus", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match); ++ ++static struct platform_driver rpi_cirrus_driver = { ++ .driver = { ++ .name = "snd-rpi-cirrus", ++ .of_match_table = of_match_ptr(rpi_cirrus_of_match), ++ }, ++ .probe = rpi_cirrus_probe, ++}; ++ ++module_platform_driver(rpi_cirrus_driver); ++ ++MODULE_AUTHOR("Matthias Reichl "); ++MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card"); ++MODULE_LICENSE("GPL"); + +From a7a1497e08e063e172d327ae2cdaaf4aa77bd505 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sun, 22 Jan 2017 12:49:37 +0100 +Subject: [PATCH 141/187] config: enable Cirrus Logic Audio Card + +Signed-off-by: Matthias Reichl +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 611b63c3fdf18f1df6288bb229f827ecd1619958..858143b9b68a9cf29714452394cb800e4f41198d 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -666,6 +666,7 @@ CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y + CONFIG_REGULATOR=y + CONFIG_REGULATOR_FIXED_VOLTAGE=m ++CONFIG_REGULATOR_ARIZONA=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +@@ -872,6 +873,7 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m ++CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m + CONFIG_SND_BCM2708_SOC_RPI_DAC=m + CONFIG_SND_BCM2708_SOC_RPI_PROTO=m + CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 74bc0d81bcb4d7f6676368926cdcc10e581fbcae..f0b87d15e959d88eb26e5a11244365dadb57a298 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -660,6 +660,7 @@ CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y + CONFIG_REGULATOR=y + CONFIG_REGULATOR_FIXED_VOLTAGE=m ++CONFIG_REGULATOR_ARIZONA=m + CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +@@ -866,6 +867,7 @@ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m + CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m ++CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m + CONFIG_SND_BCM2708_SOC_RPI_DAC=m + CONFIG_SND_BCM2708_SOC_RPI_PROTO=m + CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m + +From 1f1ed77cc7e1090e1eaef2efe32d9f197cb46c01 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:33:30 +0000 +Subject: [PATCH 142/187] irq-bcm2836: Avoid "Invalid trigger warning" + +Initialise the level for each IRQ to avoid a warning from the +arm arch timer code. + +Signed-off-by: Phil Elwell +--- + drivers/irqchip/irq-bcm2836.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c +index 486bcbfb32305ee417f6b3be7e91a3ff069a586c..e10597c1a1e51e5e27aa574b6a26d87181f26221 100644 +--- a/drivers/irqchip/irq-bcm2836.c ++++ b/drivers/irqchip/irq-bcm2836.c +@@ -178,7 +178,7 @@ static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) + + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); +- irq_set_status_flags(irq, IRQ_NOAUTOEN); ++ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW); + } + + static void + +From 2c4ff814c0a6b93a698bc30960651c90975afd25 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:36:44 +0000 +Subject: [PATCH 143/187] sound: Demote deferral errors to INFO level + +At present there is no mechanism to specify driver load order, +which can lead to deferrals and repeated retries until successful. +Since this situation is expected, reduce the dmesg level to +INFO and mention that the operation will be retried. + +Signed-off-by: Phil Elwell +--- + sound/soc/soc-core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index c0bbcd9032613a78aef551ce697cabc792880bad..a2504d8c83d74d7227e65be142a26cc9d0a88158 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1013,7 +1013,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); + if (!rtd->cpu_dai) { +- dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", ++ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n", + dai_link->cpu_dai_name); + goto _err_defer; + } +@@ -1025,7 +1025,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, + for (i = 0; i < rtd->num_codecs; i++) { + codec_dais[i] = snd_soc_find_dai(&codecs[i]); + if (!codec_dais[i]) { +- dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", ++ dev_info(card->dev, "ASoC: CODEC DAI %s not registered - will retry\n", + codecs[i].dai_name); + goto _err_defer; + } + +From 4570c9447e94aae1b7fe93d534d46625089935fa Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Feb 2017 14:40:33 +0000 +Subject: [PATCH 144/187] sound: Suppress error message about deferrals + +Since driver load deferrals are expected and will already +have resulted in a kernel message, suppress an essentially +duplicate error message from the RPi audio board drivers. + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/adau1977-adc.c | 2 +- + sound/soc/bcm/allo-piano-dac.c | 2 +- + sound/soc/bcm/digidac1-soundcard.c | 4 ++-- + sound/soc/bcm/dionaudio_loco.c | 2 +- + sound/soc/bcm/hifiberry_amp.c | 3 +-- + sound/soc/bcm/hifiberry_dac.c | 2 +- + sound/soc/bcm/hifiberry_dacplus.c | 2 +- + sound/soc/bcm/hifiberry_digi.c | 2 +- + sound/soc/bcm/iqaudio-dac.c | 5 +++-- + sound/soc/bcm/iqaudio_digi.c | 2 +- + sound/soc/bcm/justboom-dac.c | 2 +- + sound/soc/bcm/justboom-digi.c | 2 +- + sound/soc/bcm/pisound.c | 3 ++- + sound/soc/bcm/raspidac3.c | 2 +- + sound/soc/bcm/rpi-dac.c | 2 +- + sound/soc/bcm/rpi-proto.c | 3 +-- + 16 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/sound/soc/bcm/adau1977-adc.c b/sound/soc/bcm/adau1977-adc.c +index 6e2ee027926ee63c89222f75ceb89e3d2434b0e1..f3d7e5db7bb912e1d7ca6f8e8d42df5f59c9edb8 100644 +--- a/sound/soc/bcm/adau1977-adc.c ++++ b/sound/soc/bcm/adau1977-adc.c +@@ -90,7 +90,7 @@ static int snd_adau1977_adc_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_adau1977_adc); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/allo-piano-dac.c b/sound/soc/bcm/allo-piano-dac.c +index 8e8e62e5a36a279b425ed4655cfbac99ecd7e4cf..eaf50fb6dbca1970ae1c6f8662088b0f1573fecb 100644 +--- a/sound/soc/bcm/allo-piano-dac.c ++++ b/sound/soc/bcm/allo-piano-dac.c +@@ -109,7 +109,7 @@ static int snd_allo_piano_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_allo_piano_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/digidac1-soundcard.c b/sound/soc/bcm/digidac1-soundcard.c +index 446796e7e4c14a7d95b2f2a01211d9a0b151f1f3..f200688bb4ae32b90a0ced555aed94b0add0ac8a 100644 +--- a/sound/soc/bcm/digidac1-soundcard.c ++++ b/sound/soc/bcm/digidac1-soundcard.c +@@ -387,9 +387,9 @@ static int digidac1_soundcard_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&digidac1_soundcard); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", +- ret); ++ ret); + + return ret; + } +diff --git a/sound/soc/bcm/dionaudio_loco.c b/sound/soc/bcm/dionaudio_loco.c +index 89e65317512bc774453ac8d0d5b0ff98aacb740a..65e03741d349a2dc5bd91f69855ea952d9cf87a2 100644 +--- a/sound/soc/bcm/dionaudio_loco.c ++++ b/sound/soc/bcm/dionaudio_loco.c +@@ -86,7 +86,7 @@ static int snd_rpi_dionaudio_loco_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_dionaudio_loco); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + +diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c +index d17c29780507dc31c50f1d567ff5cea7c8241ff5..221c6c38e6465ffe5d5ad77fa80a0b146d0b6841 100644 +--- a/sound/soc/bcm/hifiberry_amp.c ++++ b/sound/soc/bcm/hifiberry_amp.c +@@ -96,9 +96,8 @@ static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev) + + ret = snd_soc_register_card(&snd_rpi_hifiberry_amp); + +- if (ret != 0) { ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); +- } + + return ret; + } +diff --git a/sound/soc/bcm/hifiberry_dac.c b/sound/soc/bcm/hifiberry_dac.c +index 45f2b770ad9e67728ca599a7445d6ae9a01c0c29..ee9f133953544629282631e5ef3f73fec857a7c5 100644 +--- a/sound/soc/bcm/hifiberry_dac.c ++++ b/sound/soc/bcm/hifiberry_dac.c +@@ -90,7 +90,7 @@ static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index bdc35e7e6bc12dc1cf04f5ffad8f9ab49a0b0266..b7b401cbe2b0d510d8b12d2dda6d5ff1fff42eb0 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -324,7 +324,7 @@ static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index 19dc953b7227ba86123fc7a2ba654499e0c581c5..7620dd02de40b6d644ff038b445d375d8f632def 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -242,7 +242,7 @@ static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_digi); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index aa15bc4b49ca95edec905fddd8fd0a6d839ca627..1ee4097c846376666775272ed692ca330881b0cb 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -197,8 +197,9 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) + + ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); + if (ret) { +- dev_err(&pdev->dev, +- "snd_soc_register_card() failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); + return ret; + } + +diff --git a/sound/soc/bcm/iqaudio_digi.c b/sound/soc/bcm/iqaudio_digi.c +index 9b6e829bcb5b1762a853775e7816319639e39d65..33aa2be8a43a12a12cfb5d844dd9732c2393d510 100644 +--- a/sound/soc/bcm/iqaudio_digi.c ++++ b/sound/soc/bcm/iqaudio_digi.c +@@ -204,7 +204,7 @@ static int snd_rpi_iqaudio_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(card); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + +diff --git a/sound/soc/bcm/justboom-dac.c b/sound/soc/bcm/justboom-dac.c +index 05a224ec712d06b8b7587ab6b8bb562d19956d47..9bab6cf063d3d450d96b4ee2196a7384e071cbdb 100644 +--- a/sound/soc/bcm/justboom-dac.c ++++ b/sound/soc/bcm/justboom-dac.c +@@ -128,7 +128,7 @@ static int snd_rpi_justboom_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_justboom_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/justboom-digi.c b/sound/soc/bcm/justboom-digi.c +index abfdc5c4dd5811e6847bddda4921abe33fa02812..909cf8928f2f4313982316f9c5b8a709c1d47ab8 100644 +--- a/sound/soc/bcm/justboom-digi.c ++++ b/sound/soc/bcm/justboom-digi.c +@@ -181,7 +181,7 @@ static int snd_rpi_justboom_digi_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_justboom_digi); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/pisound.c b/sound/soc/bcm/pisound.c +index ba70734b89e61a11201657406223f0b37d54f74a..06ff1e53dc9d860946965b6303577762f958fae2 100644 +--- a/sound/soc/bcm/pisound.c ++++ b/sound/soc/bcm/pisound.c +@@ -1076,7 +1076,8 @@ static int pisnd_probe(struct platform_device *pdev) + ret = snd_soc_register_card(&pisnd_card); + + if (ret < 0) { +- printe("snd_soc_register_card() failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ printe("snd_soc_register_card() failed: %d\n", ret); + pisnd_uninit_gpio(); + kobject_put(pisnd_kobj); + pisnd_spi_uninit(); +diff --git a/sound/soc/bcm/raspidac3.c b/sound/soc/bcm/raspidac3.c +index dd9eeea2af0382307f437e6db09d15468c1a470a..ad2b5b89bc8213dc2e277306ef50d6e32448759c 100644 +--- a/sound/soc/bcm/raspidac3.c ++++ b/sound/soc/bcm/raspidac3.c +@@ -149,7 +149,7 @@ static int snd_rpi_raspidac3_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_raspidac3); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + +diff --git a/sound/soc/bcm/rpi-dac.c b/sound/soc/bcm/rpi-dac.c +index 59dc89ecabc082c0a1ed8adacdc4f0f1337a1c73..38224467cbab7d5be3be731e73e2cf787cd9908a 100644 +--- a/sound/soc/bcm/rpi-dac.c ++++ b/sound/soc/bcm/rpi-dac.c +@@ -85,7 +85,7 @@ static int snd_rpi_rpi_dac_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_rpi_dac); +- if (ret) ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + + return ret; +diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c +index 9db678e885efd63d84d60a098a84ed6772b19a2d..fadbfade100228aaafabb0d3bdf35c01f8d10485 100644 +--- a/sound/soc/bcm/rpi-proto.c ++++ b/sound/soc/bcm/rpi-proto.c +@@ -117,10 +117,9 @@ static int snd_rpi_proto_probe(struct platform_device *pdev) + } + + ret = snd_soc_register_card(&snd_rpi_proto); +- if (ret) { ++ if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); +- } + + return ret; + } + +From 1cf189752ecea25d1f57940051cb81477110cb7a Mon Sep 17 00:00:00 2001 +From: Claggy3 +Date: Sat, 11 Feb 2017 14:00:30 +0000 +Subject: [PATCH 145/187] Update vfpmodule.c + +Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. +This patch fixes a problem with VFP state save and restore related +to exception handling (panic with message "BUG: unsupported FP +instruction in kernel mode") present on VFP11 floating point units +(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry +Pi boards). This patch was developed and discussed on + + https://github.com/raspberrypi/linux/issues/859 + +A precondition to see the crashes is that floating point exception +traps are enabled. In this case, the VFP11 might determine that a FPU +operation needs to trap at a point in time when it is not possible to +signal this to the ARM11 core any more. The VFP11 will then set the +FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases, +a second opcode might have been accepted by the VFP11 before the +exception was detected and could be reported to the ARM11 - in this +case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in +FPINST2.) + +If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued +by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode +trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits +to decide what actions to take, i.e., whether to emulate the opcodes +found in FPINST and FPINST2, and whether to retry the bounced instruction. + +If a user space application has left the VFP11 in this "pending trap" +state, the next FPU opcode issued to the VFP11 might actually be the +VSTMIA operation vfp_save_state() uses to store the FPU registers +to memory (in our test cases, when building the signal stack frame). +In this case, the kernel crashes as described above. + +This patch fixes the problem by making sure that vfp_save_state() is +always entered with FPEXC.EX cleared. (The current value of FPEXC has +already been saved, so this does not corrupt the context. Clearing +FPEXC.EX has no effects on FPINST or FPINST2. Also note that many +callers already modify FPEXC by setting FPEXC.EN before invoking +vfp_save_state().) + +This patch also addresses a second problem related to FPEXC.EX: After +returning from signal handling, the kernel reloads the VFP context +from the user mode stack. However, the current code explicitly clears +both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these +bits to be preserved, this patch disables clearing them for VFP +implementations belonging to architecture 1. There should be no +negative side effects: the user can set both bits by executing FPU +opcodes anyway, and while user code may now place arbitrary values +into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support +code knows which instructions can be emulated, and rejects other +opcodes with "unhandled bounce" messages, so there should be no +security impact from allowing reloading FPEXC.EX and FPEXC.FP2V. + +Signed-off-by: Christopher Alexander Tobias Schulze +--- + arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index da0b33deba6d3c2906eef271f253ab7a30a92680..c6f1d6da808cda78a58f184e19e83522bc738815 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) + * case the thread migrates to a different CPU. The + * restoring is done lazily. + */ +- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) ++ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + vfp_save_state(vfp_current_hw_state[cpu], fpexc); ++ } + #endif + + /* +@@ -463,13 +466,16 @@ static int vfp_pm_suspend(void) + /* if vfp is on, then save state for resumption */ + if (fpexc & FPEXC_EN) { + pr_debug("%s: saving vfp state\n", __func__); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + vfp_save_state(&ti->vfpstate, fpexc); + + /* disable, just in case */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + } else if (vfp_current_hw_state[ti->cpu]) { + #ifndef CONFIG_SMP +- fmxr(FPEXC, fpexc | FPEXC_EN); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); + vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); + fmxr(FPEXC, fpexc); + #endif +@@ -532,7 +538,8 @@ void vfp_sync_hwstate(struct thread_info *thread) + /* + * Save the last VFP state on this CPU. + */ +- fmxr(FPEXC, fpexc | FPEXC_EN); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); + vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); + fmxr(FPEXC, fpexc); + } +@@ -604,6 +611,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, + struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; + unsigned long fpexc; + int err = 0; ++ u32 fpsid = fmrx(FPSID); + + /* Disable VFP to avoid corrupting the new thread state. */ + vfp_flush_hwstate(thread); +@@ -627,8 +635,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, + /* Ensure the VFP is enabled. */ + fpexc |= FPEXC_EN; + +- /* Ensure FPINST2 is invalid and the exception flag is cleared. */ +- fpexc &= ~(FPEXC_EX | FPEXC_FP2V); ++ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */ ++ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) { ++ /* Ensure FPINST2 is invalid and the exception flag is cleared. */ ++ fpexc &= ~(FPEXC_EX | FPEXC_FP2V); ++ } ++ + hwstate->fpexc = fpexc; + + __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); +@@ -698,7 +710,8 @@ void kernel_neon_begin(void) + cpu = get_cpu(); + + fpexc = fmrx(FPEXC) | FPEXC_EN; +- fmxr(FPEXC, fpexc); ++ /* vfp_save_state oopses on VFP11 if EX bit set */ ++ fmxr(FPEXC, fpexc & ~FPEXC_EX); + + /* + * Save the userland NEON/VFP state. Under UP, + +From c6c5a7c11bc71d5ab6d648e652ce068f77436928 Mon Sep 17 00:00:00 2001 +From: Martin Cerveny +Date: Mon, 13 Feb 2017 17:23:47 +0100 +Subject: [PATCH 146/187] dwc_otg: fix summarize urb->actual_length for + isochronous transfers + +Kernel does not copy input data of ISO transfers to userspace +if actual_length is set only in ISO transfers and not summarized +in urb->actual_length. Fixes raspberrypi/linux#903 +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +index 162a656501988e56c9d780b7793d365fde09f801..992269d61ecf48126379a38e528f719009ee1d75 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +@@ -334,10 +334,12 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + int i; + + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); ++ urb->actual_length = 0; + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = + dwc_otg_hcd_urb_get_iso_desc_actual_length + (dwc_otg_urb, i); ++ urb->actual_length += urb->iso_frame_desc[i].actual_length; + urb->iso_frame_desc[i].status = + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); + } + +From e4289e93507bd88011935f952254c631152dcbd5 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Tue, 22 Nov 2016 12:45:28 -0800 +Subject: [PATCH 147/187] clk: bcm2835: Fix ->fixed_divider of pllh_aux + +There is no fixed divider on pllh_aux. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit f2a46926aba1f0c33944901d2420a6a887455ddc) +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 21e2a538ff0d0ab4e63adff9b93705f3d45fa15d..a99ccf9f056d3a3e7c482339e08483f3701ebc04 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1607,7 +1607,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 1), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( + .name = "pllh_pix", + .source_pll = "pllh", + +From ed089f64e82626e60252bc56fda8286e2eb7e110 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 1 Dec 2016 22:00:19 +0100 +Subject: [PATCH 148/187] clk: bcm: Support rate change propagation on bcm2835 + clocks + +Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set +to a precise rate (in our case 108MHz). With the current implementation, +where peripheral clocks are not allowed to forward rate change requests +to their parents, it is impossible to match this requirement unless the +bootloader has configured things correctly, or a specific rate has been +assigned through the DT (with the assigned-clk-rates property). + +Add a new field to struct bcm2835_clock_data to specify which parent +clocks accept rate change propagation, and support set rate propagation +in bcm2835_clock_determine_rate(). + +Signed-off-by: Boris Brezillon +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 155e8b3b0ee320ae866b97dd31eba8a1f080a772) +--- + drivers/clk/bcm/clk-bcm2835.c | 67 ++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 63 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index a99ccf9f056d3a3e7c482339e08483f3701ebc04..dafaa6b22724ab41dac1327cfa81de09908a4dfd 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -436,6 +436,9 @@ struct bcm2835_clock_data { + const char *const *parents; + int num_mux_parents; + ++ /* Bitmap encoding which parents accept rate change propagation. */ ++ unsigned int set_rate_parent; ++ + u32 ctl_reg; + u32 div_reg; + +@@ -1017,10 +1020,60 @@ bcm2835_clk_is_pllc(struct clk_hw *hw) + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; + } + ++static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, ++ int parent_idx, ++ unsigned long rate, ++ u32 *div, ++ unsigned long *prate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ struct bcm2835_cprman *cprman = clock->cprman; ++ const struct bcm2835_clock_data *data = clock->data; ++ unsigned long best_rate; ++ u32 curdiv, mindiv, maxdiv; ++ struct clk_hw *parent; ++ ++ parent = clk_hw_get_parent_by_index(hw, parent_idx); ++ ++ if (!(BIT(parent_idx) & data->set_rate_parent)) { ++ *prate = clk_hw_get_rate(parent); ++ *div = bcm2835_clock_choose_div(hw, rate, *prate, true); ++ ++ return bcm2835_clock_rate_from_divisor(clock, *prate, ++ *div); ++ } ++ ++ if (data->frac_bits) ++ dev_warn(cprman->dev, ++ "frac bits are not used when propagating rate change"); ++ ++ /* clamp to min divider of 2 if we're dealing with a mash clock */ ++ mindiv = data->is_mash_clock ? 2 : 1; ++ maxdiv = BIT(data->int_bits) - 1; ++ ++ /* TODO: Be smart, and only test a subset of the available divisors. */ ++ for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) { ++ unsigned long tmp_rate; ++ ++ tmp_rate = clk_hw_round_rate(parent, rate * curdiv); ++ tmp_rate /= curdiv; ++ if (curdiv == mindiv || ++ (tmp_rate > best_rate && tmp_rate <= rate)) ++ best_rate = tmp_rate; ++ ++ if (best_rate == rate) ++ break; ++ } ++ ++ *div = curdiv << CM_DIV_FRAC_BITS; ++ *prate = curdiv * best_rate; ++ ++ return best_rate; ++} ++ + static int bcm2835_clock_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct clk_hw *parent, *best_parent = NULL; + bool current_parent_is_pllc; + unsigned long rate, best_rate = 0; +@@ -1048,9 +1101,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) + continue; + +- prate = clk_hw_get_rate(parent); +- div = bcm2835_clock_choose_div(hw, req->rate, prate, true); +- rate = bcm2835_clock_rate_from_divisor(clock, prate, div); ++ rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, ++ &div, &prate); + if (rate > best_rate && rate <= req->rate) { + best_parent = parent; + best_prate = prate; +@@ -1271,6 +1323,13 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, + if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0) + init.flags &= ~CLK_IS_CRITICAL; + ++ /* ++ * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate ++ * rate changes on at least of the parents. ++ */ ++ if (data->set_rate_parent) ++ init.flags |= CLK_SET_RATE_PARENT; ++ + if (data->is_vpu_clock) { + init.ops = &bcm2835_vpu_clock_clk_ops; + } else { + +From 1363bc916516c74bd7a56f1b44ae383d9a96d2e2 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 1 Dec 2016 22:00:20 +0100 +Subject: [PATCH 149/187] clk: bcm: Allow rate change propagation to PLLH_AUX + on VEC clock + +The VEC clock requires needs to be set at exactly 108MHz. Allow rate +change propagation on PLLH_AUX to match this requirement wihtout +impacting other IPs (PLLH is currently only used by the HDMI encoder, +which cannot be enabled when the VEC encoder is enabled). + +Signed-off-by: Boris Brezillon +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit d86d46af84855403c00018be1c3e7bc190f2a6cd) +--- + drivers/clk/bcm/clk-bcm2835.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index dafaa6b22724ab41dac1327cfa81de09908a4dfd..0453d7c6a63923370e4191db2c4d083b893b3b47 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1870,7 +1870,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_VECCTL, + .div_reg = CM_VECDIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ /* ++ * Allow rate change propagation only on PLLH_AUX which is ++ * assigned index 7 in the parent array. ++ */ ++ .set_rate_parent = BIT(7)), + + /* dsi clocks */ + [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( + +From 9566e3eae15f82c4d58908e6941723413a6794e1 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 12 Dec 2016 09:00:53 +0100 +Subject: [PATCH 150/187] clk: bcm: Fix 'maybe-uninitialized' warning in + bcm2835_clock_choose_div_and_prate() + +best_rate is reported as potentially uninitialized by gcc. + +Signed-off-by: Boris Brezillon +Fixes: 155e8b3b0ee3 ("clk: bcm: Support rate change propagation on bcm2835 clocks") +Reported-by: Stephen Rothwell +Reviewed-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 2aab7a2055a1705c9e30920d95a596226999eb21) +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 0453d7c6a63923370e4191db2c4d083b893b3b47..9d895726ebb24bc78a2014870dbdd7c779cd1cdf 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1029,7 +1029,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + const struct bcm2835_clock_data *data = clock->data; +- unsigned long best_rate; ++ unsigned long best_rate = 0; + u32 curdiv, mindiv, maxdiv; + struct clk_hw *parent; + + +From bea6b2c5eb021f0e20eb9600159a3c9351411670 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:55 +1100 +Subject: [PATCH 151/187] clk: bcm2835: Don't rate change PLLs on behalf of DSI + PLL dividers. + +Our core PLLs are intended to be configured once and left alone. With +the SET_RATE_PARENT, asking to set the PLLD_DSI1 clock rate would +change PLLD just to get closer to the requested DSI clock, thus +changing PLLD_PER, the UART and ethernet PHY clock rates downstream of +it, and breaking ethernet. + +We *do* want PLLH to change so that PLLH_AUX can be exactly the value +we want, though. Thus, we need to have a per-divider policy of +whether to pass rate changes up. + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 55486091bd1e1c5ed28c43c0d6b3392468a9adb5) +--- + drivers/clk/bcm/clk-bcm2835.c | 42 ++++++++++++++++++++++++++++-------------- + 1 file changed, 28 insertions(+), 14 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 9d895726ebb24bc78a2014870dbdd7c779cd1cdf..b58cff2756581ba7e0be8a818cdbdf72eedcb182 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -428,6 +428,7 @@ struct bcm2835_pll_divider_data { + u32 load_mask; + u32 hold_mask; + u32 fixed_divider; ++ u32 flags; + }; + + struct bcm2835_clock_data { +@@ -1252,7 +1253,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + init.num_parents = 1; + init.name = divider_name; + init.ops = &bcm2835_pll_divider_clk_ops; +- init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; ++ init.flags = data->flags | CLK_IGNORE_UNUSED; + + divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); + if (!divider) +@@ -1475,7 +1476,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_CORE, + .load_mask = CM_PLLA_LOADCORE, + .hold_mask = CM_PLLA_HOLDCORE, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( + .name = "plla_per", + .source_pll = "plla", +@@ -1483,7 +1485,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_PER, + .load_mask = CM_PLLA_LOADPER, + .hold_mask = CM_PLLA_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( + .name = "plla_dsi0", + .source_pll = "plla", +@@ -1499,7 +1502,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLA_CCP2, + .load_mask = CM_PLLA_LOADCCP2, + .hold_mask = CM_PLLA_HOLDCCP2, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* PLLB is used for the ARM's clock. */ + [BCM2835_PLLB] = REGISTER_PLL( +@@ -1523,7 +1527,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLB_ARM, + .load_mask = CM_PLLB_LOADARM, + .hold_mask = CM_PLLB_HOLDARM, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* + * PLLC is the core PLL, used to drive the core VPU clock. +@@ -1552,7 +1557,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE0, + .load_mask = CM_PLLC_LOADCORE0, + .hold_mask = CM_PLLC_HOLDCORE0, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV( + .name = "pllc_core1", + .source_pll = "pllc", +@@ -1560,7 +1566,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE1, + .load_mask = CM_PLLC_LOADCORE1, + .hold_mask = CM_PLLC_HOLDCORE1, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV( + .name = "pllc_core2", + .source_pll = "pllc", +@@ -1568,7 +1575,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_CORE2, + .load_mask = CM_PLLC_LOADCORE2, + .hold_mask = CM_PLLC_HOLDCORE2, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLC_PER] = REGISTER_PLL_DIV( + .name = "pllc_per", + .source_pll = "pllc", +@@ -1576,7 +1584,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLC_PER, + .load_mask = CM_PLLC_LOADPER, + .hold_mask = CM_PLLC_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + + /* + * PLLD is the display PLL, used to drive DSI display panels. +@@ -1605,7 +1614,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLD_CORE, + .load_mask = CM_PLLD_LOADCORE, + .hold_mask = CM_PLLD_HOLDCORE, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLD_PER] = REGISTER_PLL_DIV( + .name = "plld_per", + .source_pll = "plld", +@@ -1613,7 +1623,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLD_PER, + .load_mask = CM_PLLD_LOADPER, + .hold_mask = CM_PLLD_HOLDPER, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV( + .name = "plld_dsi0", + .source_pll = "plld", +@@ -1658,7 +1669,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_RCAL, + .load_mask = CM_PLLH_LOADRCAL, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 10, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV( + .name = "pllh_aux", + .source_pll = "pllh", +@@ -1666,7 +1678,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, +- .fixed_divider = 1), ++ .fixed_divider = 1, ++ .flags = CLK_SET_RATE_PARENT), + [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( + .name = "pllh_pix", + .source_pll = "pllh", +@@ -1674,7 +1687,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .a2w_reg = A2W_PLLH_PIX, + .load_mask = CM_PLLH_LOADPIX, + .hold_mask = 0, +- .fixed_divider = 10), ++ .fixed_divider = 10, ++ .flags = CLK_SET_RATE_PARENT), + + /* the clocks */ + + +From 006ab754ec12782715f3331a6fb2cda2b49e6b1d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:56 +1100 +Subject: [PATCH 152/187] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. + +The DSI pixel clocks are muxed from clocks generated in the analog phy +by the DSI driver. In order to set them as parents, we need to do the +same name lookup dance on them as we do for our root oscillator. + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 8a39e9fa578229fd4604266c6ebb1a3a77d7994c) +--- + .../bindings/clock/brcm,bcm2835-cprman.txt | 15 ++- + drivers/clk/bcm/clk-bcm2835.c | 121 +++++++++++++++++++-- + include/dt-bindings/clock/bcm2835.h | 2 + + 3 files changed, 125 insertions(+), 13 deletions(-) + +diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +index e56a1df3a9d3ca7fefbc5058072ee392c49b4cfc..dd906db34b328a581e4f4d99d11284544ff817f4 100644 +--- a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt ++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +@@ -16,7 +16,20 @@ Required properties: + - #clock-cells: Should be <1>. The permitted clock-specifier values can be + found in include/dt-bindings/clock/bcm2835.h + - reg: Specifies base physical address and size of the registers +-- clocks: The external oscillator clock phandle ++- clocks: phandles to the parent clocks used as input to the module, in ++ the following order: ++ ++ - External oscillator ++ - DSI0 byte clock ++ - DSI0 DDR2 clock ++ - DSI0 DDR clock ++ - DSI1 byte clock ++ - DSI1 DDR2 clock ++ - DSI1 DDR clock ++ ++ Only external oscillator is required. The DSI clocks may ++ not be present, in which case their children will be ++ unusable. + + Example: + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index b58cff2756581ba7e0be8a818cdbdf72eedcb182..b2c277b378ee799a4f8e05ad076d1253e85cb392 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -297,11 +297,32 @@ + #define LOCK_TIMEOUT_NS 100000000 + #define BCM2835_MAX_FB_RATE 1750000000u + ++/* ++ * Names of clocks used within the driver that need to be replaced ++ * with an external parent's name. This array is in the order that ++ * the clocks node in the DT references external clocks. ++ */ ++static const char *const cprman_parent_names[] = { ++ "xosc", ++ "dsi0_byte", ++ "dsi0_ddr2", ++ "dsi0_ddr", ++ "dsi1_byte", ++ "dsi1_ddr2", ++ "dsi1_ddr", ++}; ++ + struct bcm2835_cprman { + struct device *dev; + void __iomem *regs; + spinlock_t regs_lock; /* spinlock for all clocks */ +- const char *osc_name; ++ ++ /* ++ * Real names of cprman clock parents looked up through ++ * of_clk_get_parent_name(), which will be used in the ++ * parent_names[] arrays for clock registration. ++ */ ++ const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)]; + + /* Must be last */ + struct clk_hw_onecell_data onecell; +@@ -907,6 +928,9 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, + const struct bcm2835_clock_data *data = clock->data; + u64 temp; + ++ if (data->int_bits == 0 && data->frac_bits == 0) ++ return parent_rate; ++ + /* + * The divisor is a 12.12 fixed point field, but only some of + * the bits are populated in any given clock. +@@ -930,7 +954,12 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + const struct bcm2835_clock_data *data = clock->data; +- u32 div = cprman_read(cprman, data->div_reg); ++ u32 div; ++ ++ if (data->int_bits == 0 && data->frac_bits == 0) ++ return parent_rate; ++ ++ div = cprman_read(cprman, data->div_reg); + + return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); + } +@@ -1209,7 +1238,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + memset(&init, 0, sizeof(init)); + + /* All of the PLLs derive from the external oscillator. */ +- init.parent_names = &cprman->osc_name; ++ init.parent_names = &cprman->real_parent_names[0]; + init.num_parents = 1; + init.name = data->name; + init.ops = &bcm2835_pll_clk_ops; +@@ -1295,18 +1324,22 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, + struct bcm2835_clock *clock; + struct clk_init_data init; + const char *parents[1 << CM_SRC_BITS]; +- size_t i; ++ size_t i, j; + int ret; + + /* +- * Replace our "xosc" references with the oscillator's +- * actual name. ++ * Replace our strings referencing parent clocks with the ++ * actual clock-output-name of the parent. + */ + for (i = 0; i < data->num_mux_parents; i++) { +- if (strcmp(data->parents[i], "xosc") == 0) +- parents[i] = cprman->osc_name; +- else +- parents[i] = data->parents[i]; ++ parents[i] = data->parents[i]; ++ ++ for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) { ++ if (strcmp(parents[i], cprman_parent_names[j]) == 0) { ++ parents[i] = cprman->real_parent_names[j]; ++ break; ++ } ++ } + } + + memset(&init, 0, sizeof(init)); +@@ -1442,6 +1475,47 @@ static const char *const bcm2835_clock_vpu_parents[] = { + __VA_ARGS__) + + /* ++ * DSI parent clocks. The DSI byte/DDR/DDR2 clocks come from the DSI ++ * analog PHY. The _inv variants are generated internally to cprman, ++ * but we don't use them so they aren't hooked up. ++ */ ++static const char *const bcm2835_clock_dsi0_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "dsi0_ddr", ++ "dsi0_ddr_inv", ++ "dsi0_ddr2", ++ "dsi0_ddr2_inv", ++ "dsi0_byte", ++ "dsi0_byte_inv", ++}; ++ ++static const char *const bcm2835_clock_dsi1_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "dsi1_ddr", ++ "dsi1_ddr_inv", ++ "dsi1_ddr2", ++ "dsi1_ddr2_inv", ++ "dsi1_byte", ++ "dsi1_byte_inv", ++}; ++ ++#define REGISTER_DSI0_CLK(...) REGISTER_CLK( \ ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \ ++ .parents = bcm2835_clock_dsi0_parents, \ ++ __VA_ARGS__) ++ ++#define REGISTER_DSI1_CLK(...) REGISTER_CLK( \ ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \ ++ .parents = bcm2835_clock_dsi1_parents, \ ++ __VA_ARGS__) ++ ++/* + * the real definition of all the pll, pll_dividers and clocks + * these make use of the above REGISTER_* macros + */ +@@ -1904,6 +1978,18 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .div_reg = CM_DSI1EDIV, + .int_bits = 4, + .frac_bits = 8), ++ [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( ++ .name = "dsi0p", ++ .ctl_reg = CM_DSI0PCTL, ++ .div_reg = CM_DSI0PDIV, ++ .int_bits = 0, ++ .frac_bits = 0), ++ [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( ++ .name = "dsi1p", ++ .ctl_reg = CM_DSI1PCTL, ++ .div_reg = CM_DSI1PDIV, ++ .int_bits = 0, ++ .frac_bits = 0), + + /* the gates */ + +@@ -1962,8 +2048,19 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + if (IS_ERR(cprman->regs)) + return PTR_ERR(cprman->regs); + +- cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0); +- if (!cprman->osc_name) ++ memcpy(cprman->real_parent_names, cprman_parent_names, ++ sizeof(cprman_parent_names)); ++ of_clk_parent_fill(dev->of_node, cprman->real_parent_names, ++ ARRAY_SIZE(cprman_parent_names)); ++ ++ /* ++ * Make sure the external oscillator has been registered. ++ * ++ * The other (DSI) clocks are not present on older device ++ * trees, which we still need to support for backwards ++ * compatibility. ++ */ ++ if (!cprman->real_parent_names[0]) + return -ENODEV; + + platform_set_drvdata(pdev, cprman); +diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h +index 360e00cefd35679b49890234b5c369fb52b89e20..a0c812b0fa391d149b4f546db39bdc4bef207960 100644 +--- a/include/dt-bindings/clock/bcm2835.h ++++ b/include/dt-bindings/clock/bcm2835.h +@@ -64,3 +64,5 @@ + #define BCM2835_CLOCK_CAM1 46 + #define BCM2835_CLOCK_DSI0E 47 + #define BCM2835_CLOCK_DSI1E 48 ++#define BCM2835_CLOCK_DSI0P 49 ++#define BCM2835_CLOCK_DSI1P 50 + +From 8e9befa946ea6c9eff07a323d7710fb06f0d8422 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 18 Jan 2017 07:31:57 +1100 +Subject: [PATCH 153/187] clk: bcm2835: Add leaf clock measurement support, + disabled by default + +This proved incredibly useful during debugging of the DSI driver, to +see if our clocks were running at rate we requested. Let's leave it +here for the next person interacting with clocks on the platform (and +so that hopefully we can just hook it up to debugfs some day). + +Signed-off-by: Eric Anholt +Signed-off-by: Stephen Boyd +(cherry picked from commit 3f9195811d8d829556c4cd88d3f9e56a80d5ba60) +--- + drivers/clk/bcm/clk-bcm2835.c | 144 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 119 insertions(+), 25 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index b2c277b378ee799a4f8e05ad076d1253e85cb392..136e5d28f9eaeaa10d45382a0f31da9f4adb91ef 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -98,7 +99,8 @@ + #define CM_SMIDIV 0x0b4 + /* no definition for 0x0b8 and 0x0bc */ + #define CM_TCNTCTL 0x0c0 +-#define CM_TCNTDIV 0x0c4 ++# define CM_TCNT_SRC1_SHIFT 12 ++#define CM_TCNTCNT 0x0c4 + #define CM_TECCTL 0x0c8 + #define CM_TECDIV 0x0cc + #define CM_TD0CTL 0x0d0 +@@ -338,6 +340,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) + return readl(cprman->regs + reg); + } + ++/* Does a cycle of measuring a clock through the TCNT clock, which may ++ * source from many other clocks in the system. ++ */ ++static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman, ++ u32 tcnt_mux) ++{ ++ u32 osccount = 19200; /* 1ms */ ++ u32 count; ++ ktime_t timeout; ++ ++ spin_lock(&cprman->regs_lock); ++ ++ cprman_write(cprman, CM_TCNTCTL, CM_KILL); ++ ++ cprman_write(cprman, CM_TCNTCTL, ++ (tcnt_mux & CM_SRC_MASK) | ++ (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT); ++ ++ cprman_write(cprman, CM_OSCCOUNT, osccount); ++ ++ /* do a kind delay at the start */ ++ mdelay(1); ++ ++ /* Finish off whatever is left of OSCCOUNT */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (cprman_read(cprman, CM_OSCCOUNT)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n"); ++ count = 0; ++ goto out; ++ } ++ cpu_relax(); ++ } ++ ++ /* Wait for BUSY to clear. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "timeout waiting for !BUSY\n"); ++ count = 0; ++ goto out; ++ } ++ cpu_relax(); ++ } ++ ++ count = cprman_read(cprman, CM_TCNTCNT); ++ ++ cprman_write(cprman, CM_TCNTCTL, 0); ++ ++out: ++ spin_unlock(&cprman->regs_lock); ++ ++ return count * 1000; ++} ++ + static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, + struct debugfs_reg32 *regs, size_t nregs, + struct dentry *dentry) +@@ -473,6 +530,8 @@ struct bcm2835_clock_data { + + bool is_vpu_clock; + bool is_mash_clock; ++ ++ u32 tcnt_mux; + }; + + struct bcm2835_gate_data { +@@ -1008,6 +1067,17 @@ static int bcm2835_clock_on(struct clk_hw *hw) + CM_GATE); + spin_unlock(&cprman->regs_lock); + ++ /* Debug code to measure the clock once it's turned on to see ++ * if it's ticking at the rate we expect. ++ */ ++ if (data->tcnt_mux && false) { ++ dev_info(cprman->dev, ++ "clk %s: rate %ld, measure %ld\n", ++ data->name, ++ clk_hw_get_rate(hw), ++ bcm2835_measure_tcnt_mux(cprman, data->tcnt_mux)); ++ } ++ + return 0; + } + +@@ -1774,7 +1844,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_OTPCTL, + .div_reg = CM_OTPDIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 6), + /* + * Used for a 1Mhz clock for the system clocksource, and also used + * bythe watchdog timer and the camera pulse generator. +@@ -1808,13 +1879,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_H264CTL, + .div_reg = CM_H264DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 1), + [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( + .name = "isp", + .ctl_reg = CM_ISPCTL, + .div_reg = CM_ISPDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 2), + + /* + * Secondary SDRAM clock. Used for low-voltage modes when the PLL +@@ -1825,13 +1898,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_SDCCTL, + .div_reg = CM_SDCDIV, + .int_bits = 6, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 3), + [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( + .name = "v3d", + .ctl_reg = CM_V3DCTL, + .div_reg = CM_V3DDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 4), + /* + * VPU clock. This doesn't have an enable bit, since it drives + * the bus for everything else, and is special so it doesn't need +@@ -1845,7 +1920,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .int_bits = 12, + .frac_bits = 8, + .flags = CLK_IS_CRITICAL, +- .is_vpu_clock = true), ++ .is_vpu_clock = true, ++ .tcnt_mux = 5), + + /* clocks with per parent mux */ + [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( +@@ -1853,19 +1929,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_AVEOCTL, + .div_reg = CM_AVEODIV, + .int_bits = 4, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 38), + [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( + .name = "cam0", + .ctl_reg = CM_CAM0CTL, + .div_reg = CM_CAM0DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 14), + [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( + .name = "cam1", + .ctl_reg = CM_CAM1CTL, + .div_reg = CM_CAM1DIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 15), + [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( + .name = "dft", + .ctl_reg = CM_DFTCTL, +@@ -1877,7 +1956,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_DPICTL, + .div_reg = CM_DPIDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 17), + + /* Arasan EMMC clock */ + [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( +@@ -1885,7 +1965,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_EMMCCTL, + .div_reg = CM_EMMCDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 39), + + /* General purpose (GPIO) clocks */ + [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( +@@ -1894,7 +1975,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .div_reg = CM_GP0DIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 20), + [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( + .name = "gp1", + .ctl_reg = CM_GP1CTL, +@@ -1902,7 +1984,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .int_bits = 12, + .frac_bits = 12, + .flags = CLK_IS_CRITICAL, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 21), + [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( + .name = "gp2", + .ctl_reg = CM_GP2CTL, +@@ -1917,40 +2000,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_HSMCTL, + .div_reg = CM_HSMDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 22), + [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( + .name = "pcm", + .ctl_reg = CM_PCMCTL, + .div_reg = CM_PCMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 23), + [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( + .name = "pwm", + .ctl_reg = CM_PWMCTL, + .div_reg = CM_PWMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 24), + [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( + .name = "slim", + .ctl_reg = CM_SLIMCTL, + .div_reg = CM_SLIMDIV, + .int_bits = 12, + .frac_bits = 12, +- .is_mash_clock = true), ++ .is_mash_clock = true, ++ .tcnt_mux = 25), + [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( + .name = "smi", + .ctl_reg = CM_SMICTL, + .div_reg = CM_SMIDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 27), + [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( + .name = "uart", + .ctl_reg = CM_UARTCTL, + .div_reg = CM_UARTDIV, + .int_bits = 10, +- .frac_bits = 12), ++ .frac_bits = 12, ++ .tcnt_mux = 28), + + /* TV encoder clock. Only operating frequency is 108Mhz. */ + [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( +@@ -1963,7 +2052,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + * Allow rate change propagation only on PLLH_AUX which is + * assigned index 7 in the parent array. + */ +- .set_rate_parent = BIT(7)), ++ .set_rate_parent = BIT(7), ++ .tcnt_mux = 29), + + /* dsi clocks */ + [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( +@@ -1971,25 +2061,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_DSI0ECTL, + .div_reg = CM_DSI0EDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 18), + [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( + .name = "dsi1e", + .ctl_reg = CM_DSI1ECTL, + .div_reg = CM_DSI1EDIV, + .int_bits = 4, +- .frac_bits = 8), ++ .frac_bits = 8, ++ .tcnt_mux = 19), + [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( + .name = "dsi0p", + .ctl_reg = CM_DSI0PCTL, + .div_reg = CM_DSI0PDIV, + .int_bits = 0, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 12), + [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( + .name = "dsi1p", + .ctl_reg = CM_DSI1PCTL, + .div_reg = CM_DSI1PDIV, + .int_bits = 0, +- .frac_bits = 0), ++ .frac_bits = 0, ++ .tcnt_mux = 13), + + /* the gates */ + + +From c0d869fdcc5294882af65525e0b3cdfd7bb98ea4 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 26 Apr 2016 13:46:13 -0700 +Subject: [PATCH 154/187] drm/panel: Add support for the Raspberry Pi 7" + Touchscreen. + +This driver communicates with the Atmel microcontroller for sequencing +the poweron of the TC358762 DSI-DPI bridge and controlling the +backlight PWM. + +The following lines are required in config.txt, to keep the firmware +from trying to bash our I2C lines and steal the DSI interrupts: + + disable_touchscreen=1 + ignore_lcd=2 + mask_gpu_interrupt1=0x1000 + +This means that the firmware won't power on the panel at boot time (no +rainbow) and the touchscreen input won't work. The native input +driver for the touchscreen still needs to be written. + +v2: Set the same default orientation as the closed source firmware + used, which is the best for viewing angle. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/panel/Kconfig | 8 + + drivers/gpu/drm/panel/Makefile | 1 + + .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 514 +++++++++++++++++++++ + 3 files changed, 523 insertions(+) + create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c + +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 62aba976e744c146c26d7fedf44c54cdd480361e..de7a56ab758b8f043194391f9b9e43df65c06d0a 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -52,6 +52,14 @@ config DRM_PANEL_PANASONIC_VVX10F034N00 + WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some + Xperia Z2 tablets + ++config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN ++ tristate "Raspberry Pi 7-inch touchscreen panel" ++ depends on DRM_MIPI_DSI ++ help ++ Say Y here if you want to enable support for the Raspberry ++ Pi 7" Touchscreen. To compile this driver as a module, ++ choose M here. ++ + config DRM_PANEL_SAMSUNG_S6E8AA0 + tristate "Samsung S6E8AA0 DSI video mode panel" + depends on OF +diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile +index a5c7ec0236e0174079cce0f07d46372967e9cf3b..e8a7ed280fff907e5a730a13ae9a3e5e34cacce4 100644 +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -2,6 +2,7 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o + obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o + obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o + obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o ++obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o + obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o + obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o + obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o +diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +new file mode 100644 +index 0000000000000000000000000000000000000000..1a536fe4d040f5fafe324baee110a6225dd0be08 +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -0,0 +1,514 @@ ++/* ++ * Copyright © 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Portions of this file (derived from panel-simple.c) are: ++ * ++ * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++/** ++ * DOC: Raspberry Pi 7" touchscreen panel driver. ++ * ++ * The 7" touchscreen consists of a DPI LCD panel, a Toshiba ++ * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR ++ * controlling power management, the LCD PWM, and the touchscreen. ++ * ++ * This driver presents this device as a MIPI DSI panel to the DRM ++ * driver, and should expose the touchscreen as a HID device. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* I2C registers of the Atmel microcontroller. */ ++enum REG_ADDR { ++ REG_ID = 0x80, ++ REG_PORTA, // BIT(2) for horizontal flip, BIT(3) for vertical flip ++ REG_PORTB, ++ REG_PORTC, ++ REG_PORTD, ++ REG_POWERON, ++ REG_PWM, ++ REG_DDRA, ++ REG_DDRB, ++ REG_DDRC, ++ REG_DDRD, ++ REG_TEST, ++ REG_WR_ADDRL, ++ REG_WR_ADDRH, ++ REG_READH, ++ REG_READL, ++ REG_WRITEH, ++ REG_WRITEL, ++ REG_ID2, ++}; ++ ++/* We only turn the PWM on or off, without varying values. */ ++#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1 ++ ++/* DSI D-PHY Layer Registers */ ++#define D0W_DPHYCONTTX 0x0004 ++#define CLW_DPHYCONTRX 0x0020 ++#define D0W_DPHYCONTRX 0x0024 ++#define D1W_DPHYCONTRX 0x0028 ++#define COM_DPHYCONTRX 0x0038 ++#define CLW_CNTRL 0x0040 ++#define D0W_CNTRL 0x0044 ++#define D1W_CNTRL 0x0048 ++#define DFTMODE_CNTRL 0x0054 ++ ++/* DSI PPI Layer Registers */ ++#define PPI_STARTPPI 0x0104 ++#define PPI_BUSYPPI 0x0108 ++#define PPI_LINEINITCNT 0x0110 ++#define PPI_LPTXTIMECNT 0x0114 ++//#define PPI_LANEENABLE 0x0134 ++//#define PPI_TX_RX_TA 0x013C ++#define PPI_CLS_ATMR 0x0140 ++#define PPI_D0S_ATMR 0x0144 ++#define PPI_D1S_ATMR 0x0148 ++#define PPI_D0S_CLRSIPOCOUNT 0x0164 ++#define PPI_D1S_CLRSIPOCOUNT 0x0168 ++#define CLS_PRE 0x0180 ++#define D0S_PRE 0x0184 ++#define D1S_PRE 0x0188 ++#define CLS_PREP 0x01A0 ++#define D0S_PREP 0x01A4 ++#define D1S_PREP 0x01A8 ++#define CLS_ZERO 0x01C0 ++#define D0S_ZERO 0x01C4 ++#define D1S_ZERO 0x01C8 ++#define PPI_CLRFLG 0x01E0 ++#define PPI_CLRSIPO 0x01E4 ++#define HSTIMEOUT 0x01F0 ++#define HSTIMEOUTENABLE 0x01F4 ++ ++/* DSI Protocol Layer Registers */ ++#define DSI_STARTDSI 0x0204 ++#define DSI_BUSYDSI 0x0208 ++#define DSI_LANEENABLE 0x0210 ++# define DSI_LANEENABLE_CLOCK BIT(0) ++# define DSI_LANEENABLE_D0 BIT(1) ++# define DSI_LANEENABLE_D1 BIT(2) ++ ++#define DSI_LANESTATUS0 0x0214 ++#define DSI_LANESTATUS1 0x0218 ++#define DSI_INTSTATUS 0x0220 ++#define DSI_INTMASK 0x0224 ++#define DSI_INTCLR 0x0228 ++#define DSI_LPTXTO 0x0230 ++#define DSI_MODE 0x0260 ++#define DSI_PAYLOAD0 0x0268 ++#define DSI_PAYLOAD1 0x026C ++#define DSI_SHORTPKTDAT 0x0270 ++#define DSI_SHORTPKTREQ 0x0274 ++#define DSI_BTASTA 0x0278 ++#define DSI_BTACLR 0x027C ++ ++/* DSI General Registers */ ++#define DSIERRCNT 0x0300 ++#define DSISIGMOD 0x0304 ++ ++/* DSI Application Layer Registers */ ++#define APLCTRL 0x0400 ++#define APLSTAT 0x0404 ++#define APLERR 0x0408 ++#define PWRMOD 0x040C ++#define RDPKTLN 0x0410 ++#define PXLFMT 0x0414 ++#define MEMWRCMD 0x0418 ++ ++/* LCDC/DPI Host Registers */ ++#define LCDCTRL 0x0420 ++#define HSR 0x0424 ++#define HDISPR 0x0428 ++#define VSR 0x042C ++#define VDISPR 0x0430 ++#define VFUEN 0x0434 ++ ++/* DBI-B Host Registers */ ++#define DBIBCTRL 0x0440 ++ ++/* SPI Master Registers */ ++#define SPICMR 0x0450 ++#define SPITCR 0x0454 ++ ++/* System Controller Registers */ ++#define SYSSTAT 0x0460 ++#define SYSCTRL 0x0464 ++#define SYSPLL1 0x0468 ++#define SYSPLL2 0x046C ++#define SYSPLL3 0x0470 ++#define SYSPMCTRL 0x047C ++ ++/* GPIO Registers */ ++#define GPIOC 0x0480 ++#define GPIOO 0x0484 ++#define GPIOI 0x0488 ++ ++/* I2C Registers */ ++#define I2CCLKCTRL 0x0490 ++ ++/* Chip/Rev Registers */ ++#define IDREG 0x04A0 ++ ++/* Debug Registers */ ++#define WCMDQUEUE 0x0500 ++#define RCMDQUEUE 0x0504 ++ ++struct rpi_touchscreen { ++ struct drm_panel base; ++ struct mipi_dsi_device *dsi; ++ struct i2c_client *bridge_i2c; ++ ++ /* Version of the firmware on the bridge chip */ ++ int atmel_ver; ++}; ++ ++static const struct drm_display_mode rpi_touchscreen_modes[] = { ++ { ++ /* The DSI PLL can only integer divide from the 2Ghz ++ * PLLD, giving us few choices. We pick a divide by 3 ++ * as our DSI HS clock, giving us a pixel clock of ++ * that divided by 24 bits. Pad out HFP to get our ++ * panel to refresh at 60Hz, even if that doesn't ++ * match the datasheet. ++ */ ++#define PIXEL_CLOCK ((2000000000 / 3) / 24) ++#define VREFRESH 60 ++#define VTOTAL (480 + 7 + 2 + 21) ++#define HACT 800 ++#define HSW 2 ++#define HBP 46 ++#define HFP ((PIXEL_CLOCK / (VTOTAL * VREFRESH)) - (HACT + HSW + HBP)) ++ ++ .clock = PIXEL_CLOCK / 1000, ++ .hdisplay = HACT, ++ .hsync_start = HACT + HFP, ++ .hsync_end = HACT + HFP + HSW, ++ .htotal = HACT + HFP + HSW + HBP, ++ .vdisplay = 480, ++ .vsync_start = 480 + 7, ++ .vsync_end = 480 + 7 + 2, ++ .vtotal = VTOTAL, ++ .vrefresh = 60, ++ }, ++}; ++ ++static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) ++{ ++ return container_of(panel, struct rpi_touchscreen, base); ++} ++ ++static u8 rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) ++{ ++ return i2c_smbus_read_byte_data(ts->bridge_i2c, reg); ++} ++ ++static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, ++ u8 reg, u8 val) ++{ ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(ts->bridge_i2c, reg, val); ++ if (ret) ++ dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret); ++} ++ ++static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) ++{ ++#if 0 ++ /* The firmware uses LP DSI transactions like this to bring up ++ * the hardware, which should be faster than using I2C to then ++ * pass to the Toshiba. However, I was unable to get it to ++ * work. ++ */ ++ u8 msg[] = { ++ reg, ++ reg >> 8, ++ val, ++ val >> 8, ++ val >> 16, ++ val >> 24, ++ }; ++ ++ mipi_dsi_dcs_write_buffer(ts->dsi, msg, sizeof(msg)); ++#else ++ rpi_touchscreen_i2c_write(ts, REG_WR_ADDRH, reg >> 8); ++ rpi_touchscreen_i2c_write(ts, REG_WR_ADDRL, reg); ++ rpi_touchscreen_i2c_write(ts, REG_WRITEH, val >> 8); ++ rpi_touchscreen_i2c_write(ts, REG_WRITEL, val); ++#endif ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_disable(struct drm_panel *panel) ++{ ++ struct rpi_touchscreen *ts = panel_to_ts(panel); ++ ++ rpi_touchscreen_i2c_write(ts, REG_PWM, 0); ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ udelay(1); ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_noop(struct drm_panel *panel) ++{ ++ return 0; ++} ++ ++static int rpi_touchscreen_enable(struct drm_panel *panel) ++{ ++ struct rpi_touchscreen *ts = panel_to_ts(panel); ++ int i; ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 1); ++ /* Wait for nPWRDWN to go low to indicate poweron is done. */ ++ for (i = 0; i < 100; i++) { ++ if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1) ++ break; ++ } ++ ++ rpi_touchscreen_write(ts, DSI_LANEENABLE, ++ DSI_LANEENABLE_CLOCK | ++ DSI_LANEENABLE_D0 | ++ (ts->dsi->lanes > 1 ? DSI_LANEENABLE_D1 : 0)); ++ rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05); ++ rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05); ++ rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00); ++ rpi_touchscreen_write(ts, PPI_D1S_ATMR, 0x00); ++ rpi_touchscreen_write(ts, PPI_LPTXTIMECNT, 0x03); ++ ++ rpi_touchscreen_write(ts, SPICMR, 0x00); ++ rpi_touchscreen_write(ts, LCDCTRL, 0x00100150); ++ rpi_touchscreen_write(ts, SYSCTRL, 0x040f); ++ msleep(100); ++ ++ rpi_touchscreen_write(ts, PPI_STARTPPI, 0x01); ++ rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01); ++ msleep(100); ++ ++ /* Turn on the backlight. */ ++ rpi_touchscreen_i2c_write(ts, REG_PWM, 255); ++ ++ /* Default to the same orientation as the closed source ++ * firmware used for the panel. Runtime rotation ++ * configuration will be supported using VC4's plane ++ * orientation bits. ++ */ ++ rpi_touchscreen_i2c_write(ts, REG_PORTA, BIT(2)); ++ ++ return 0; ++} ++ ++static int rpi_touchscreen_get_modes(struct drm_panel *panel) ++{ ++ struct drm_connector *connector = panel->connector; ++ struct drm_device *drm = panel->drm; ++ unsigned int i, num = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) { ++ const struct drm_display_mode *m = &rpi_touchscreen_modes[i]; ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(drm, m); ++ if (!mode) { ++ dev_err(drm->dev, "failed to add mode %ux%u@%u\n", ++ m->hdisplay, m->vdisplay, m->vrefresh); ++ continue; ++ } ++ ++ mode->type |= DRM_MODE_TYPE_DRIVER; ++ ++ if (i == 0) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ ++ drm_mode_probed_add(connector, mode); ++ num++; ++ } ++ ++ connector->display_info.bpc = 8; ++ connector->display_info.width_mm = 154; ++ connector->display_info.height_mm = 86; ++ ++ return num; ++} ++ ++static const struct drm_panel_funcs rpi_touchscreen_funcs = { ++ .disable = rpi_touchscreen_disable, ++ .unprepare = rpi_touchscreen_noop, ++ .prepare = rpi_touchscreen_noop, ++ .enable = rpi_touchscreen_enable, ++ .get_modes = rpi_touchscreen_get_modes, ++}; ++ ++static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev, ++ const char *name) ++{ ++ struct device_node *node; ++ struct i2c_client *client; ++ ++ node = of_parse_phandle(dev->of_node, name, 0); ++ if (!node) ++ return ERR_PTR(-ENODEV); ++ ++ client = of_find_i2c_device_by_node(node); ++ ++ of_node_put(node); ++ ++ return client; ++} ++ ++static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts; ++ int ret, ver; ++ ++ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, ts); ++ ++ ts->dsi = dsi; ++ dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_MODE_VIDEO_SYNC_PULSE | ++ MIPI_DSI_MODE_LPM); ++ dsi->format = MIPI_DSI_FMT_RGB888; ++ dsi->lanes = 1; ++ ++ ts->bridge_i2c = ++ rpi_touchscreen_get_i2c(dev, "raspberrypi,touchscreen-bridge"); ++ if (IS_ERR(ts->bridge_i2c)) { ++ ret = -EPROBE_DEFER; ++ return ret; ++ } ++ ++ ver = rpi_touchscreen_i2c_read(ts, REG_ID); ++ if (ver < 0) { ++ dev_err(dev, "Atmel I2C read failed: %d\n", ver); ++ return -ENODEV; ++ } ++ ++ switch (ver) { ++ case 0xde: ++ ts->atmel_ver = 1; ++ break; ++ case 0xc3: ++ ts->atmel_ver = 2; ++ break; ++ default: ++ dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver); ++ return -ENODEV; ++ } ++ ++ /* Turn off at boot, so we can cleanly sequence powering on. */ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ ++ drm_panel_init(&ts->base); ++ ts->base.dev = dev; ++ ts->base.funcs = &rpi_touchscreen_funcs; ++ ++ ret = drm_panel_add(&ts->base); ++ if (ret < 0) ++ goto err_release_bridge; ++ ++ return mipi_dsi_attach(dsi); ++ ++err_release_bridge: ++ put_device(&ts->bridge_i2c->dev); ++ return ret; ++} ++ ++static int rpi_touchscreen_dsi_remove(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = mipi_dsi_detach(dsi); ++ if (ret < 0) { ++ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); ++ return ret; ++ } ++ ++ drm_panel_detach(&ts->base); ++ drm_panel_remove(&ts->base); ++ ++ put_device(&ts->bridge_i2c->dev); ++ ++ return 0; ++} ++ ++static void rpi_touchscreen_dsi_shutdown(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct rpi_touchscreen *ts = dev_get_drvdata(dev); ++ ++ rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++} ++ ++static const struct of_device_id rpi_touchscreen_of_match[] = { ++ { .compatible = "raspberrypi,touchscreen" }, ++ { } /* sentinel */ ++}; ++MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_match); ++ ++static struct mipi_dsi_driver rpi_touchscreen_driver = { ++ .driver = { ++ .name = "raspberrypi-touchscreen", ++ .of_match_table = rpi_touchscreen_of_match, ++ }, ++ .probe = rpi_touchscreen_dsi_probe, ++ .remove = rpi_touchscreen_dsi_remove, ++ .shutdown = rpi_touchscreen_dsi_shutdown, ++}; ++module_mipi_dsi_driver(rpi_touchscreen_driver); ++ ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); ++MODULE_LICENSE("GPL v2"); + +From 3336948d2b15c1ad3623b87758bb1718259fcf03 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Jun 2016 12:29:45 -0700 +Subject: [PATCH 155/187] BCM270X: Add the DSI panel to the defconfig. + +Signed-off-by: Eric Anholt +--- + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + arch/arm64/configs/bcmrpi3_defconfig | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 858143b9b68a9cf29714452394cb800e4f41198d..669edd7544d79838d9471fbe11b803c342f195df 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -833,6 +833,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index f0b87d15e959d88eb26e5a11244365dadb57a298..9a9cd1cdcb2f76d4408568681ec80885293bae48 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -827,6 +827,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y +diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig +index 8c4392344eb4495689c220d5d176ee8c189079fd..301611d2283f5f8800339271cea59aedcbc09130 100644 +--- a/arch/arm64/configs/bcmrpi3_defconfig ++++ b/arch/arm64/configs/bcmrpi3_defconfig +@@ -816,6 +816,8 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_PANEL_SIMPLE=m ++CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m + CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + +From ccc759f89499794d4088429377fd6e534b7177b5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 13 Dec 2016 15:15:10 -0800 +Subject: [PATCH 156/187] ARM: bcm2835: dt: Add the DSI module nodes and + clocks. + +The modules stay disabled by default, and if you want to enable DSI +you'll need an overlay that connects a panel to it. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 8 +++++++ + arch/arm/boot/dts/bcm283x.dtsi | 49 +++++++++++++++++++++++++++++++++++--- + 2 files changed, 54 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index e9b47b2bbc3390edc2541f251ae5167640a445d9..365648898f3acc4f82dc6cb58e4bbebbe249be94 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -84,3 +84,11 @@ + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; + }; ++ ++&dsi0 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI0>; ++}; ++ ++&dsi1 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI1>; ++}; +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 51cdefbf5eb265f49bd05e0aa91dfbeee3fbfdcc..41776b97b4b6b1c053d07fd357fac4ba4787ac53 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -93,10 +93,13 @@ + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + +- /* CPRMAN derives everything from the platform's +- * oscillator. ++ /* CPRMAN derives almost everything from the ++ * platform's oscillator. However, the DSI ++ * pixel clocks come from the DSI analog PHY. + */ +- clocks = <&clk_osc>; ++ clocks = <&clk_osc>, ++ <&dsi0 0>, <&dsi0 1>, <&dsi0 2>, ++ <&dsi1 0>, <&dsi1 1>, <&dsi1 2>; + }; + + rng@7e104000 { +@@ -188,6 +191,26 @@ + interrupts = <2 14>; /* pwa1 */ + }; + ++ dsi0: dsi@7e209000 { ++ compatible = "brcm,bcm2835-dsi0"; ++ reg = <0x7e209000 0x78>; ++ interrupts = <2 4>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ ++ clocks = <&clocks BCM2835_PLLA_DSI0>, ++ <&clocks BCM2835_CLOCK_DSI0E>, ++ <&clocks BCM2835_CLOCK_DSI0P>; ++ clock-names = "phy", "escape", "pixel"; ++ ++ clock-output-names = "dsi0_byte", ++ "dsi0_ddr2", ++ "dsi0_ddr"; ++ ++ status = "disabled"; ++ }; ++ + aux: aux@0x7e215000 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; +@@ -247,6 +270,26 @@ + interrupts = <2 1>; + }; + ++ dsi1: dsi@7e700000 { ++ compatible = "brcm,bcm2835-dsi1"; ++ reg = <0x7e700000 0x8c>; ++ interrupts = <2 12>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ ++ clocks = <&clocks BCM2835_PLLD_DSI1>, ++ <&clocks BCM2835_CLOCK_DSI1E>, ++ <&clocks BCM2835_CLOCK_DSI1P>; ++ clock-names = "phy", "escape", "pixel"; ++ ++ clock-output-names = "dsi1_byte", ++ "dsi1_ddr2", ++ "dsi1_ddr"; ++ ++ status = "disabled"; ++ }; ++ + i2c1: i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; + +From 54cce9bcc058fdfd75b67ba1504a7adeaa708fc8 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Jun 2016 15:09:35 -0700 +Subject: [PATCH 157/187] BCM270X: Enable the DSI panel node in the VC4 + overlay. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 5 ++++ + arch/arm/boot/dts/bcm2708-rpi-b.dts | 5 ++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 5 ++++ + arch/arm/boot/dts/bcm270x.dtsi | 27 ++++++++++++++++++++++ + arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 5 ++++ + arch/arm/boot/dts/bcm2710.dtsi | 1 - + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 22 ++++++++++++++++++ + 7 files changed, 69 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index 360da5c928dc5599b0d2a9055728087604c6b189..51f575e5d201fdfc1632e9bc8ed3bbd3e55dddcb 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -154,3 +154,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 28 0 ++ &gpio 29 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 9c49659ab246bce0656f3514f3b924bc4826b421..028ef91a6c4f5d6573204635a03b912284505baa 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -144,3 +144,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 2 0 ++ &gpio 3 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 19c83823420fc3cc20a01d07091100cb8720ff4d..a4ffeff9fda62da830e674ff06c3a5394bd9d8cf 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -154,3 +154,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 28 0 ++ &gpio 29 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi +index 36d853715f2379e1952ce3d3be58dd670e305159..caa66393518603529d284f360b2000b0ed4852ef 100644 +--- a/arch/arm/boot/dts/bcm270x.dtsi ++++ b/arch/arm/boot/dts/bcm270x.dtsi +@@ -137,6 +137,29 @@ + /* Add alias */ + status = "disabled"; + }; ++ ++ i2c_dsi: i2cdsi { ++ /* We have to use i2c-gpio because the ++ * firmware is also polling another device ++ * using the only hardware I2C bus that could ++ * connect to these pins. ++ */ ++ compatible = "i2c-gpio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ pitouchscreen_bridge: bridge@45 { ++ compatible = "raspberrypi,touchscreen-bridge-i2c"; ++ reg = <0x45>; ++ }; ++ ++ pitouchscreen_touch: bridge@38 { ++ compatible = "raspberrypi,touchscreen-ts-i2c"; ++ reg = <0x38>; ++ }; ++ }; ++ + }; + + vdd_5v0_reg: fixedregulator_5v0 { +@@ -155,3 +178,7 @@ + regulator-always-on; + }; + }; ++ ++&dsi1 { ++ power-domains = <&power RPI_POWER_DOMAIN_DSI1>; ++}; +diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +index 12764a3495b2372ffaf47e32ea0d21326ca83686..d29ba72de727fe26b5a586e0bd0a41181c68ae04 100644 +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +@@ -201,3 +201,8 @@ + sd_debug = <&sdhost>,"brcm,debug"; + }; + }; ++ ++&i2c_dsi { ++ gpios = <&gpio 44 0 ++ &gpio 45 0>; ++}; +diff --git a/arch/arm/boot/dts/bcm2710.dtsi b/arch/arm/boot/dts/bcm2710.dtsi +index 3e134a1208610b90e2d0fc22f03c6e9f372bfcd7..3fabac6a93e846f678d846637c4f9a5f5b8e7922 100644 +--- a/arch/arm/boot/dts/bcm2710.dtsi ++++ b/arch/arm/boot/dts/bcm2710.dtsi +@@ -145,4 +145,3 @@ + interrupt-parent = <&local_intc>; + interrupts = <8>; + }; +- +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index 4f1cc20f90dc6780f74e08ebee00e5a1a6062c85..f25cd9a3936861920b0d518ff2d773ee467e2f49 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -126,6 +126,28 @@ + }; + }; + ++ fragment@16 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pitouchscreen: panel@0 { ++ compatible = "raspberrypi,touchscreen"; ++ reg = <0>; ++ raspberrypi,touchscreen-bridge = <&pitouchscreen_bridge>; ++ }; ++ }; ++ }; ++ ++ fragment@17 { ++ target = <&i2c_dsi>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; + +From 85e5a07c8adcf8733695d5da48e4bee22a019b3d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 20 Oct 2016 16:48:12 -0700 +Subject: [PATCH 158/187] drm/vc4: Fix termination of the initial scan for + branch targets. + +The loop is scanning until the original max_ip (size of the BO), but +we want to not examine any code after the PROG_END's delay slots. +There was a block trying to do that, except that we had some early +continue statements if the signal wasn't a PROG_END or a BRANCH. + +The failure mode would be that a valid shader is rejected because some +undefined memory after the PROG_END slots is parsed as a branch and +the rest of its setup is illegal. I haven't seen this in the wild, +but valgrind was complaining when about this up in the userland +simulator mode. + +Signed-off-by: Eric Anholt +(cherry picked from commit 457e67a728696c4f8e6423c64e93def50530db9a) +--- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +index 2543cf5b8b51869d51b72a5db5017dded38761be..917321ce832ffda9d3e8ca20d987437eea9a1765 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -608,9 +608,7 @@ static bool + vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + { + uint32_t max_branch_target = 0; +- bool found_shader_end = false; + int ip; +- int shader_end_ip = 0; + int last_branch = -2; + + for (ip = 0; ip < validation_state->max_ip; ip++) { +@@ -621,8 +619,13 @@ vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + uint32_t branch_target_ip; + + if (sig == QPU_SIG_PROG_END) { +- shader_end_ip = ip; +- found_shader_end = true; ++ /* There are two delay slots after program end is ++ * signaled that are still executed, then we're ++ * finished. validation_state->max_ip is the ++ * instruction after the last valid instruction in the ++ * program. ++ */ ++ validation_state->max_ip = ip + 3; + continue; + } + +@@ -676,15 +679,9 @@ vc4_validate_branches(struct vc4_shader_validation_state *validation_state) + } + set_bit(after_delay_ip, validation_state->branch_targets); + max_branch_target = max(max_branch_target, after_delay_ip); +- +- /* There are two delay slots after program end is signaled +- * that are still executed, then we're finished. +- */ +- if (found_shader_end && ip == shader_end_ip + 2) +- break; + } + +- if (max_branch_target > shader_end_ip) { ++ if (max_branch_target > validation_state->max_ip - 3) { + DRM_ERROR("Branch landed after QPU_SIG_PROG_END"); + return false; + } + +From dcd3dff96e0737a1a0c68fb608dd898a6374a445 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 3 Nov 2016 18:53:10 -0700 +Subject: [PATCH 159/187] drm/vc4: Add support for rendering with ETC1 + textures. + +The validation for it ends up being quite simple, but I hadn't got +around to it before merging the driver. For backwards compatibility, +we also need to add a flag so that the userspace GL driver can easily +tell if the kernel will allow ETC1 textures (on an old kernel, it will +continue to convert to RGBA8) + +Signed-off-by: Eric Anholt +(cherry picked from commit 7154d76fedf549607afbc0d13db9aaf02da5cebf) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_validate.c | 7 +++++++ + include/uapi/drm/vc4_drm.h | 1 + + 3 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 6c4a4fbc86d0a30a6977b2081bca4372e693b817..157e08ab27771854ffbad101f61ce81e27001e1a 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -78,6 +78,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + pm_runtime_put(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: ++ case DRM_VC4_PARAM_SUPPORTS_ETC1: + args->value = true; + break; + default: +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 26503e307438a34fe526222c8c15be158eb332a2..e18f88203d32f828b7256a05c653586c14095ef3 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -644,6 +644,13 @@ reloc_tex(struct vc4_exec_info *exec, + cpp = 1; + break; + case VC4_TEXTURE_TYPE_ETC1: ++ /* ETC1 is arranged as 64-bit blocks, where each block is 4x4 ++ * pixels. ++ */ ++ cpp = 8; ++ width = (width + 3) >> 2; ++ height = (height + 3) >> 2; ++ break; + case VC4_TEXTURE_TYPE_BW1: + case VC4_TEXTURE_TYPE_A4: + case VC4_TEXTURE_TYPE_A1: +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +index ad7edc3edf7ca1d653a0bc025a5eda6692b74370..69caa21f0cb23c9439238f6239c0041b178d5669 100644 +--- a/include/uapi/drm/vc4_drm.h ++++ b/include/uapi/drm/vc4_drm.h +@@ -286,6 +286,7 @@ struct drm_vc4_get_hang_state { + #define DRM_VC4_PARAM_V3D_IDENT1 1 + #define DRM_VC4_PARAM_V3D_IDENT2 2 + #define DRM_VC4_PARAM_SUPPORTS_BRANCHES 3 ++#define DRM_VC4_PARAM_SUPPORTS_ETC1 4 + + struct drm_vc4_get_param { + __u32 param; + +From a77bc0452ea8328a2bc0a2ddd6ede17db035bfe9 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 4 Nov 2016 15:58:38 -0700 +Subject: [PATCH 160/187] drm/vc4: Use runtime autosuspend to avoid thrashing + V3D power state. + +The pm_runtime_put() we were using immediately released power on the +device, which meant that we were generally turning the device off and +on once per frame. In many profiles I've looked at, that added up to +about 1% of CPU time, but this could get worse in the case of frequent +rendering and readback (as may happen in X rendering). By keeping the +device on until we've been idle for a couple of frames, we drop the +overhead of runtime PM down to sub-.1%. + +Signed-off-by: Eric Anholt +(cherry picked from commit 3a62234680d86efa0239665ed8a0e908f1aef147) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 9 ++++++--- + drivers/gpu/drm/vc4/vc4_gem.c | 6 ++++-- + drivers/gpu/drm/vc4/vc4_v3d.c | 2 ++ + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 157e08ab27771854ffbad101f61ce81e27001e1a..8302bd788be470fd61a7382b8c3ef16e26f6861d 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -61,21 +61,24 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT0); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_V3D_IDENT1: + ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT1); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_V3D_IDENT2: + ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); + if (ret < 0) + return ret; + args->value = V3D_READ(V3D_IDENT2); +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: + case DRM_VC4_PARAM_SUPPORTS_ETC1: +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 18e37171e9c8e2f0729ca1c582af98ccb4647e06..ab3016982466c3ca35ba479050ee107d26eb50ac 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -711,8 +711,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + } + + mutex_lock(&vc4->power_lock); +- if (--vc4->power_refcount == 0) +- pm_runtime_put(&vc4->v3d->pdev->dev); ++ if (--vc4->power_refcount == 0) { ++ pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); ++ pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev); ++ } + mutex_unlock(&vc4->power_lock); + + kfree(exec); +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index e6d3c6028341e447df293cab525713ac10d8ee5e..7cc346ad9b0baed63701d1fae8f0306aa7713129 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -222,6 +222,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + return ret; + } + ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */ + pm_runtime_enable(dev); + + return 0; + +From ebacea179c3f19693c33cf30a304a75fb5fc2689 Mon Sep 17 00:00:00 2001 +From: Jonas Pfeil +Date: Tue, 8 Nov 2016 00:18:39 +0100 +Subject: [PATCH 161/187] drm/vc4: Add fragment shader threading support + +FS threading brings performance improvements of 0-20% in glmark2. + +The validation code checks for thread switch signals and ensures that +the registers of the other thread are not touched, and that our clamps +are not live across thread switches. It also checks that the +threading and branching instructions do not interfere. + +(Original patch by Jonas, changes by anholt for style cleanup, +removing validation the kernel doesn't need to do, and adding the flag +for userspace). + +v2: Minor style fixes from checkpatch. + +Signed-off-by: Jonas Pfeil +Signed-off-by: Eric Anholt +(cherry picked from commit c778cc5df944291dcdb1ca7a6bb781fbc22550c5) +--- + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 2 + + drivers/gpu/drm/vc4/vc4_validate.c | 17 +++++--- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 63 ++++++++++++++++++++++++++++++ + include/uapi/drm/vc4_drm.h | 1 + + 5 files changed, 79 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 8302bd788be470fd61a7382b8c3ef16e26f6861d..3abaa0f85da194016c65f46509d4c64f8e2c8de2 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -82,6 +82,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, + break; + case DRM_VC4_PARAM_SUPPORTS_BRANCHES: + case DRM_VC4_PARAM_SUPPORTS_ETC1: ++ case DRM_VC4_PARAM_SUPPORTS_THREADED_FS: + args->value = true; + break; + default: +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index e1f6ab747f36dd412e00a1e7ea772f13c2fc32d5..e15eb37ca6191e0eae3d4947751437d2646c996d 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -384,6 +384,8 @@ struct vc4_validated_shader_info { + + uint32_t num_uniform_addr_offsets; + uint32_t *uniform_addr_offsets; ++ ++ bool is_threaded; + }; + + /** +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index e18f88203d32f828b7256a05c653586c14095ef3..9fd171c361c23b52a4d507919ec7e26fd1e87aac 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -789,11 +789,6 @@ validate_gl_shader_rec(struct drm_device *dev, + exec->shader_rec_v += roundup(packet_size, 16); + exec->shader_rec_size -= packet_size; + +- if (!(*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD)) { +- DRM_ERROR("Multi-threaded fragment shaders not supported.\n"); +- return -EINVAL; +- } +- + for (i = 0; i < shader_reloc_count; i++) { + if (src_handles[i] > exec->bo_count) { + DRM_ERROR("Shader handle %d too big\n", src_handles[i]); +@@ -810,6 +805,18 @@ validate_gl_shader_rec(struct drm_device *dev, + return -EINVAL; + } + ++ if (((*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD) == 0) != ++ to_vc4_bo(&bo[0]->base)->validated_shader->is_threaded) { ++ DRM_ERROR("Thread mode of CL and FS do not match\n"); ++ return -EINVAL; ++ } ++ ++ if (to_vc4_bo(&bo[1]->base)->validated_shader->is_threaded || ++ to_vc4_bo(&bo[2]->base)->validated_shader->is_threaded) { ++ DRM_ERROR("cs and vs cannot be threaded\n"); ++ return -EINVAL; ++ } ++ + for (i = 0; i < shader_reloc_count; i++) { + struct vc4_validated_shader_info *validated_shader; + uint32_t o = shader_reloc_offsets[i]; +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +index 917321ce832ffda9d3e8ca20d987437eea9a1765..5dba13dd1e9b600b43a769d086d6eb428547ab66 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -83,6 +83,13 @@ struct vc4_shader_validation_state { + * basic blocks. + */ + bool needs_uniform_address_for_loop; ++ ++ /* Set when we find an instruction writing the top half of the ++ * register files. If we allowed writing the unusable regs in ++ * a threaded shader, then the other shader running on our ++ * QPU's clamp validation would be invalid. ++ */ ++ bool all_registers_used; + }; + + static uint32_t +@@ -119,6 +126,13 @@ raddr_add_a_to_live_reg_index(uint64_t inst) + } + + static bool ++live_reg_is_upper_half(uint32_t lri) ++{ ++ return (lri >= 16 && lri < 32) || ++ (lri >= 32 + 16 && lri < 32 + 32); ++} ++ ++static bool + is_tmu_submit(uint32_t waddr) + { + return (waddr == QPU_W_TMU0_S || +@@ -390,6 +404,9 @@ check_reg_write(struct vc4_validated_shader_info *validated_shader, + } else { + validation_state->live_immediates[lri] = ~0; + } ++ ++ if (live_reg_is_upper_half(lri)) ++ validation_state->all_registers_used = true; + } + + switch (waddr) { +@@ -598,6 +615,11 @@ check_instruction_reads(struct vc4_validated_shader_info *validated_shader, + } + } + ++ if ((raddr_a >= 16 && raddr_a < 32) || ++ (raddr_b >= 16 && raddr_b < 32 && sig != QPU_SIG_SMALL_IMM)) { ++ validation_state->all_registers_used = true; ++ } ++ + return true; + } + +@@ -753,6 +775,7 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + { + bool found_shader_end = false; + int shader_end_ip = 0; ++ uint32_t last_thread_switch_ip = -3; + uint32_t ip; + struct vc4_validated_shader_info *validated_shader = NULL; + struct vc4_shader_validation_state validation_state; +@@ -785,6 +808,17 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + if (!vc4_handle_branch_target(&validation_state)) + goto fail; + ++ if (ip == last_thread_switch_ip + 3) { ++ /* Reset r0-r3 live clamp data */ ++ int i; ++ ++ for (i = 64; i < LIVE_REG_COUNT; i++) { ++ validation_state.live_min_clamp_offsets[i] = ~0; ++ validation_state.live_max_clamp_regs[i] = false; ++ validation_state.live_immediates[i] = ~0; ++ } ++ } ++ + switch (sig) { + case QPU_SIG_NONE: + case QPU_SIG_WAIT_FOR_SCOREBOARD: +@@ -794,6 +828,8 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + case QPU_SIG_LOAD_TMU1: + case QPU_SIG_PROG_END: + case QPU_SIG_SMALL_IMM: ++ case QPU_SIG_THREAD_SWITCH: ++ case QPU_SIG_LAST_THREAD_SWITCH: + if (!check_instruction_writes(validated_shader, + &validation_state)) { + DRM_ERROR("Bad write at ip %d\n", ip); +@@ -809,6 +845,18 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + shader_end_ip = ip; + } + ++ if (sig == QPU_SIG_THREAD_SWITCH || ++ sig == QPU_SIG_LAST_THREAD_SWITCH) { ++ validated_shader->is_threaded = true; ++ ++ if (ip < last_thread_switch_ip + 3) { ++ DRM_ERROR("Thread switch too soon after " ++ "last switch at ip %d\n", ip); ++ goto fail; ++ } ++ last_thread_switch_ip = ip; ++ } ++ + break; + + case QPU_SIG_LOAD_IMM: +@@ -823,6 +871,13 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + if (!check_branch(inst, validated_shader, + &validation_state, ip)) + goto fail; ++ ++ if (ip < last_thread_switch_ip + 3) { ++ DRM_ERROR("Branch in thread switch at ip %d", ++ ip); ++ goto fail; ++ } ++ + break; + default: + DRM_ERROR("Unsupported QPU signal %d at " +@@ -844,6 +899,14 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) + goto fail; + } + ++ /* Might corrupt other thread */ ++ if (validated_shader->is_threaded && ++ validation_state.all_registers_used) { ++ DRM_ERROR("Shader uses threading, but uses the upper " ++ "half of the registers, too\n"); ++ goto fail; ++ } ++ + /* If we did a backwards branch and we haven't emitted a uniforms + * reset since then, we still need the uniforms stream to have the + * uniforms address available so that the backwards branch can do its +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +index 69caa21f0cb23c9439238f6239c0041b178d5669..f07a090167261131076438960c1dec175d7d376e 100644 +--- a/include/uapi/drm/vc4_drm.h ++++ b/include/uapi/drm/vc4_drm.h +@@ -287,6 +287,7 @@ struct drm_vc4_get_hang_state { + #define DRM_VC4_PARAM_V3D_IDENT2 2 + #define DRM_VC4_PARAM_SUPPORTS_BRANCHES 3 + #define DRM_VC4_PARAM_SUPPORTS_ETC1 4 ++#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5 + + struct drm_vc4_get_param { + __u32 param; + +From 19878dd3b492a48437e32a8c5cb908a441e13ef2 Mon Sep 17 00:00:00 2001 +From: Derek Foreman +Date: Thu, 24 Nov 2016 12:11:55 -0600 +Subject: [PATCH 162/187] drm/vc4: Fix race between page flip completion event + and clean-up + +There was a small window where a userspace program could submit +a pageflip after receiving a pageflip completion event yet still +receive EBUSY. + +Signed-off-by: Derek Foreman +Signed-off-by: Eric Anholt +Reviewed-by: Eric Anholt +Reviewed-by: Daniel Stone +(cherry picked from commit 26fc78f6fef39b9d7a15def5e7e9826ff68303f4) +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 8 ++++++++ + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_kms.c | 33 +++++++++++++++++++++++++-------- + 3 files changed, 34 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index 13212788eef0e4b77c1e92e6bf3a56c817c50322..61d64c9c4b0cd1aafc6451b0838cb203c1374a5a 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -682,6 +682,14 @@ void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id) + CRTC_WRITE(PV_INTEN, 0); + } + ++/* Must be called with the event lock held */ ++bool vc4_event_pending(struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ ++ return !!vc4_crtc->event; ++} ++ + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + { + struct drm_crtc *crtc = &vc4_crtc->base; +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index e15eb37ca6191e0eae3d4947751437d2646c996d..47fa2987909642b244615ff6c642adb278bcd784 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -445,6 +445,7 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); + extern struct platform_driver vc4_crtc_driver; + int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); + void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); ++bool vc4_event_pending(struct drm_crtc *crtc); + int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); + int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, + unsigned int flags, int *vpos, int *hpos, +diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c +index c1f65c6c8e601e9331768ca040a5609cad686b2e..67af2af70af091bf4b13ac03eb1078f867bc6cea 100644 +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -119,17 +119,34 @@ static int vc4_atomic_commit(struct drm_device *dev, + + /* Make sure that any outstanding modesets have finished. */ + if (nonblock) { +- ret = down_trylock(&vc4->async_modeset); +- if (ret) { ++ struct drm_crtc *crtc; ++ struct drm_crtc_state *crtc_state; ++ unsigned long flags; ++ bool busy = false; ++ ++ /* ++ * If there's an undispatched event to send then we're ++ * obviously still busy. If there isn't, then we can ++ * unconditionally wait for the semaphore because it ++ * shouldn't be contended (for long). ++ * ++ * This is to prevent a race where queuing a new flip ++ * from userspace immediately on receipt of an event ++ * beats our clean-up and returns EBUSY. ++ */ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ for_each_crtc_in_state(state, crtc, crtc_state, i) ++ busy |= vc4_event_pending(crtc); ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ if (busy) { + kfree(c); + return -EBUSY; + } +- } else { +- ret = down_interruptible(&vc4->async_modeset); +- if (ret) { +- kfree(c); +- return ret; +- } ++ } ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(c); ++ return ret; + } + + ret = drm_atomic_helper_prepare_planes(dev, state); + +From e4b2cf7a156944353c7d08328fe38c1b879d3317 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:07 +0100 +Subject: [PATCH 163/187] drm/vc4: Fix ->clock_select setting for the VEC + encoder + +PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and +rework the vc4_set_crtc_possible_masks() to cover the full range of the +PV_CONTROL_CLK_SELECT field. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit ab8df60e3a3b68420d0d4477c5f07c00fbfb078b) +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++--------------- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_regs.h | 3 ++- + 3 files changed, 26 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index 61d64c9c4b0cd1aafc6451b0838cb203c1374a5a..bdf32c572fc2c46932daca934dfb002d05493883 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -83,8 +83,7 @@ struct vc4_crtc_data { + /* Which channel of the HVS this pixelvalve sources from. */ + int hvs_channel; + +- enum vc4_encoder_type encoder0_type; +- enum vc4_encoder_type encoder1_type; ++ enum vc4_encoder_type encoder_types[4]; + }; + + #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) +@@ -880,20 +879,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { + + static const struct vc4_crtc_data pv0_data = { + .hvs_channel = 0, +- .encoder0_type = VC4_ENCODER_TYPE_DSI0, +- .encoder1_type = VC4_ENCODER_TYPE_DPI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI, ++ }, + }; + + static const struct vc4_crtc_data pv1_data = { + .hvs_channel = 2, +- .encoder0_type = VC4_ENCODER_TYPE_DSI1, +- .encoder1_type = VC4_ENCODER_TYPE_SMI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI, ++ }, + }; + + static const struct vc4_crtc_data pv2_data = { + .hvs_channel = 1, +- .encoder0_type = VC4_ENCODER_TYPE_VEC, +- .encoder1_type = VC4_ENCODER_TYPE_HDMI, ++ .encoder_types = { ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, ++ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, ++ }, + }; + + static const struct of_device_id vc4_crtc_dt_match[] = { +@@ -907,17 +912,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, + struct drm_crtc *crtc) + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ const struct vc4_crtc_data *crtc_data = vc4_crtc->data; ++ const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types; + struct drm_encoder *encoder; + + drm_for_each_encoder(encoder, drm) { + struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); +- +- if (vc4_encoder->type == vc4_crtc->data->encoder0_type) { +- vc4_encoder->clock_select = 0; +- encoder->possible_crtcs |= drm_crtc_mask(crtc); +- } else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) { +- vc4_encoder->clock_select = 1; +- encoder->possible_crtcs |= drm_crtc_mask(crtc); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) { ++ if (vc4_encoder->type == encoder_types[i]) { ++ vc4_encoder->clock_select = i; ++ encoder->possible_crtcs |= drm_crtc_mask(crtc); ++ break; ++ } + } + } + } +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 47fa2987909642b244615ff6c642adb278bcd784..6d0688056aa2c75cc6b5bf9a6c50cc62e1b398e2 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -197,6 +197,7 @@ to_vc4_plane(struct drm_plane *plane) + } + + enum vc4_encoder_type { ++ VC4_ENCODER_TYPE_NONE, + VC4_ENCODER_TYPE_HDMI, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI0, +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 1aa44c2db5565ba126d2ceb65495a6c98c555860..39f6886b24100c43b590e47e0c7bc44846721d65 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -177,8 +177,9 @@ + # define PV_CONTROL_WAIT_HSTART BIT(12) + # define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4) + # define PV_CONTROL_PIXEL_REP_SHIFT 4 +-# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 ++# define PV_CONTROL_CLK_SELECT_DSI 0 + # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 ++# define PV_CONTROL_CLK_SELECT_VEC 2 + # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) + # define PV_CONTROL_CLK_SELECT_SHIFT 2 + # define PV_CONTROL_FIFO_CLR BIT(1) + +From c5802ef9279c71a69d2e07d537b7d9fbc8e05cd6 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:09 +0100 +Subject: [PATCH 164/187] drm: Add TV connector states to drm_connector_state + +Some generic TV connector properties are exposed in drm_mode_config, but +they are currently handled independently in each DRM encoder driver. + +Extend the drm_connector_state to store TV related states, and modify the +drm_atomic_connector_{set,get}_property() helpers to fill the connector +state accordingly. + +Each driver is then responsible for checking and applying the new config +in its ->atomic_mode_{check,set}() operations. + +Signed-off-by: Boris Brezillon +Reviewed-by: Daniel Vetter +Signed-off-by: Eric Anholt +(cherry picked from commit 299a16b163c95fbe1e3b1e142ba9c6ce9dab2c23) +--- + drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ + include/drm/drm_connector.h | 32 ++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c +index 4e19bde4bbffac08e700460b69db882f42d5463b..846da4f6416435221cb8d08a8c124f05852e93ca 100644 +--- a/drivers/gpu/drm/drm_atomic.c ++++ b/drivers/gpu/drm/drm_atomic.c +@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, + * now?) atomic writes to DPMS property: + */ + return -EINVAL; ++ } else if (property == config->tv_select_subconnector_property) { ++ state->tv.subconnector = val; ++ } else if (property == config->tv_left_margin_property) { ++ state->tv.margins.left = val; ++ } else if (property == config->tv_right_margin_property) { ++ state->tv.margins.right = val; ++ } else if (property == config->tv_top_margin_property) { ++ state->tv.margins.top = val; ++ } else if (property == config->tv_bottom_margin_property) { ++ state->tv.margins.bottom = val; ++ } else if (property == config->tv_mode_property) { ++ state->tv.mode = val; ++ } else if (property == config->tv_brightness_property) { ++ state->tv.brightness = val; ++ } else if (property == config->tv_contrast_property) { ++ state->tv.contrast = val; ++ } else if (property == config->tv_flicker_reduction_property) { ++ state->tv.flicker_reduction = val; ++ } else if (property == config->tv_overscan_property) { ++ state->tv.overscan = val; ++ } else if (property == config->tv_saturation_property) { ++ state->tv.saturation = val; ++ } else if (property == config->tv_hue_property) { ++ state->tv.hue = val; + } else if (connector->funcs->atomic_set_property) { + return connector->funcs->atomic_set_property(connector, + state, property, val); + } else { + return -EINVAL; + } ++ ++ return 0; + } + EXPORT_SYMBOL(drm_atomic_connector_set_property); + +@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector, + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->dpms_property) { + *val = connector->dpms; ++ } else if (property == config->tv_select_subconnector_property) { ++ *val = state->tv.subconnector; ++ } else if (property == config->tv_left_margin_property) { ++ *val = state->tv.margins.left; ++ } else if (property == config->tv_right_margin_property) { ++ *val = state->tv.margins.right; ++ } else if (property == config->tv_top_margin_property) { ++ *val = state->tv.margins.top; ++ } else if (property == config->tv_bottom_margin_property) { ++ *val = state->tv.margins.bottom; ++ } else if (property == config->tv_mode_property) { ++ *val = state->tv.mode; ++ } else if (property == config->tv_brightness_property) { ++ *val = state->tv.brightness; ++ } else if (property == config->tv_contrast_property) { ++ *val = state->tv.contrast; ++ } else if (property == config->tv_flicker_reduction_property) { ++ *val = state->tv.flicker_reduction; ++ } else if (property == config->tv_overscan_property) { ++ *val = state->tv.overscan; ++ } else if (property == config->tv_saturation_property) { ++ *val = state->tv.saturation; ++ } else if (property == config->tv_hue_property) { ++ *val = state->tv.hue; + } else if (connector->funcs->atomic_get_property) { + return connector->funcs->atomic_get_property(connector, + state, property, val); +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index ac9d7d8e0e43a807e9fc9a0b66de5f26b49d3348..2645e803857253ff98eb94aa1bacc8257f37ae76 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, + unsigned int num_formats); + + /** ++ * struct drm_tv_connector_state - TV connector related states ++ * @subconnector: selected subconnector ++ * @margins: left/right/top/bottom margins ++ * @mode: TV mode ++ * @brightness: brightness in percent ++ * @contrast: contrast in percent ++ * @flicker_reduction: flicker reduction in percent ++ * @overscan: overscan in percent ++ * @saturation: saturation in percent ++ * @hue: hue in percent ++ */ ++struct drm_tv_connector_state { ++ enum drm_mode_subconnector subconnector; ++ struct { ++ unsigned int left; ++ unsigned int right; ++ unsigned int top; ++ unsigned int bottom; ++ } margins; ++ unsigned int mode; ++ unsigned int brightness; ++ unsigned int contrast; ++ unsigned int flicker_reduction; ++ unsigned int overscan; ++ unsigned int saturation; ++ unsigned int hue; ++}; ++ ++/** + * struct drm_connector_state - mutable connector state + * @connector: backpointer to the connector + * @best_encoder: can be used by helpers and drivers to select the encoder + * @state: backpointer to global drm_atomic_state ++ * @tv: TV connector state + */ + struct drm_connector_state { + struct drm_connector *connector; +@@ -213,6 +243,8 @@ struct drm_connector_state { + struct drm_encoder *best_encoder; + + struct drm_atomic_state *state; ++ ++ struct drm_tv_connector_state tv; + }; + + /** + +From 30f28713c9444d1f2737718a3921f2bd1409e2b1 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:08 +0100 +Subject: [PATCH 165/187] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into + an enum + +List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better +represented with enums. + +Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum. + +Signed-off-by: Boris Brezillon +Suggested-by: Daniel Vetter +Reviewed-by: Daniel Vetter +Signed-off-by: Eric Anholt +(cherry picked from commit dee7a4fee730ca8908f335b6b66174cba4598ecd) +--- + include/uapi/drm/drm_mode.h | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h +index df0e3504c349a950bf41540fbcd6cd944cf11d2f..970bfc0d7107451e5bc4e29c524a764cbd10b39b 100644 +--- a/include/uapi/drm/drm_mode.h ++++ b/include/uapi/drm/drm_mode.h +@@ -220,14 +220,16 @@ struct drm_mode_get_encoder { + + /* This is for connectors with multiple signal types. */ + /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +-#define DRM_MODE_SUBCONNECTOR_Automatic 0 +-#define DRM_MODE_SUBCONNECTOR_Unknown 0 +-#define DRM_MODE_SUBCONNECTOR_DVID 3 +-#define DRM_MODE_SUBCONNECTOR_DVIA 4 +-#define DRM_MODE_SUBCONNECTOR_Composite 5 +-#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +-#define DRM_MODE_SUBCONNECTOR_Component 8 +-#define DRM_MODE_SUBCONNECTOR_SCART 9 ++enum drm_mode_subconnector { ++ DRM_MODE_SUBCONNECTOR_Automatic = 0, ++ DRM_MODE_SUBCONNECTOR_Unknown = 0, ++ DRM_MODE_SUBCONNECTOR_DVID = 3, ++ DRM_MODE_SUBCONNECTOR_DVIA = 4, ++ DRM_MODE_SUBCONNECTOR_Composite = 5, ++ DRM_MODE_SUBCONNECTOR_SVIDEO = 6, ++ DRM_MODE_SUBCONNECTOR_Component = 8, ++ DRM_MODE_SUBCONNECTOR_SCART = 9, ++}; + + #define DRM_MODE_CONNECTOR_Unknown 0 + #define DRM_MODE_CONNECTOR_VGA 1 + +From 9231fe3ff1b89ea5a3dce92b657ef9f6e8f064cc Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:10 +0100 +Subject: [PATCH 166/187] drm/vc4: Add support for the VEC (Video Encoder) IP + +The VEC IP is a TV DAC, providing support for PAL and NTSC standards. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit e4b81f8c74c82dbc0cb0e5ceb5ef9b713b325fc9) +--- + drivers/gpu/drm/vc4/Makefile | 1 + + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 5 + + drivers/gpu/drm/vc4/vc4_vec.c | 657 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 665 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c + +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +index c6dd06cca9830018c39b3b16afe4045e44d1ddf4..3358ec8775cf6e8738ea8cdb2246dad57bd29139 100644 +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -12,6 +12,7 @@ vc4-y := \ + vc4_kms.o \ + vc4_gem.o \ + vc4_hdmi.o \ ++ vc4_vec.o \ + vc4_hvs.o \ + vc4_irq.o \ + vc4_plane.o \ +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index 245115d49c46a1244ef3e460a03fde397f763de8..caf817bac8852c82f0d6a34b676a649c10e6e6cd 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, + {"dpi_regs", vc4_dpi_debugfs_regs, 0}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, ++ {"vec_regs", vc4_vec_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, + {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, + {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 3abaa0f85da194016c65f46509d4c64f8e2c8de2..281609353063435f9da33f81bdc09dbc3ebc89e9 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -294,6 +294,7 @@ static const struct component_master_ops vc4_drm_ops = { + + static struct platform_driver *const component_drivers[] = { + &vc4_hdmi_driver, ++ &vc4_vec_driver, + &vc4_dpi_driver, + &vc4_hvs_driver, + &vc4_crtc_driver, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 6d0688056aa2c75cc6b5bf9a6c50cc62e1b398e2..61a9b3e81823a3c96f36f710329844cc032e2628 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -20,6 +20,7 @@ struct vc4_dev { + struct vc4_crtc *crtc[3]; + struct vc4_v3d *v3d; + struct vc4_dpi *dpi; ++ struct vc4_vec *vec; + + struct drm_fbdev_cma *fbdev; + +@@ -494,6 +495,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev, + extern struct platform_driver vc4_hdmi_driver; + int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused); + ++/* vc4_hdmi.c */ ++extern struct platform_driver vc4_vec_driver; ++int vc4_vec_debugfs_regs(struct seq_file *m, void *unused); ++ + /* vc4_irq.c */ + irqreturn_t vc4_irq(int irq, void *arg); + void vc4_irq_preinstall(struct drm_device *dev); +diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c +new file mode 100644 +index 0000000000000000000000000000000000000000..32bb8ef985fbc6f39f9e5f459846bb779b80c9e8 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_vec.c +@@ -0,0 +1,657 @@ ++/* ++ * Copyright (C) 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++/** ++ * DOC: VC4 SDTV module ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++/* WSE Registers */ ++#define VEC_WSE_RESET 0xc0 ++ ++#define VEC_WSE_CONTROL 0xc4 ++#define VEC_WSE_WSS_ENABLE BIT(7) ++ ++#define VEC_WSE_WSS_DATA 0xc8 ++#define VEC_WSE_VPS_DATA1 0xcc ++#define VEC_WSE_VPS_CONTROL 0xd0 ++ ++/* VEC Registers */ ++#define VEC_REVID 0x100 ++ ++#define VEC_CONFIG0 0x104 ++#define VEC_CONFIG0_YDEL_MASK GENMASK(28, 26) ++#define VEC_CONFIG0_YDEL(x) ((x) << 26) ++#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24) ++#define VEC_CONFIG0_CDEL(x) ((x) << 24) ++#define VEC_CONFIG0_PBPR_FIL BIT(18) ++#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16) ++#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_32 (1 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_16 (2 << 16) ++#define VEC_CONFIG0_CHROMA_GAIN_1_8 (3 << 16) ++#define VEC_CONFIG0_CBURST_GAIN_MASK GENMASK(14, 13) ++#define VEC_CONFIG0_CBURST_GAIN_UNITY (0 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_128 (1 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_64 (2 << 13) ++#define VEC_CONFIG0_CBURST_GAIN_1_32 (3 << 13) ++#define VEC_CONFIG0_CHRBW1 BIT(11) ++#define VEC_CONFIG0_CHRBW0 BIT(10) ++#define VEC_CONFIG0_SYNCDIS BIT(9) ++#define VEC_CONFIG0_BURDIS BIT(8) ++#define VEC_CONFIG0_CHRDIS BIT(7) ++#define VEC_CONFIG0_PDEN BIT(6) ++#define VEC_CONFIG0_YCDELAY BIT(4) ++#define VEC_CONFIG0_RAMPEN BIT(2) ++#define VEC_CONFIG0_YCDIS BIT(2) ++#define VEC_CONFIG0_STD_MASK GENMASK(1, 0) ++#define VEC_CONFIG0_NTSC_STD 0 ++#define VEC_CONFIG0_PAL_BDGHI_STD 1 ++#define VEC_CONFIG0_PAL_N_STD 3 ++ ++#define VEC_SCHPH 0x108 ++#define VEC_SOFT_RESET 0x10c ++#define VEC_CLMP0_START 0x144 ++#define VEC_CLMP0_END 0x148 ++#define VEC_FREQ3_2 0x180 ++#define VEC_FREQ1_0 0x184 ++ ++#define VEC_CONFIG1 0x188 ++#define VEC_CONFIG_VEC_RESYNC_OFF BIT(18) ++#define VEC_CONFIG_RGB219 BIT(17) ++#define VEC_CONFIG_CBAR_EN BIT(16) ++#define VEC_CONFIG_TC_OBB BIT(15) ++#define VEC_CONFIG1_OUTPUT_MODE_MASK GENMASK(12, 10) ++#define VEC_CONFIG1_C_Y_CVBS (0 << 10) ++#define VEC_CONFIG1_CVBS_Y_C (1 << 10) ++#define VEC_CONFIG1_PR_Y_PB (2 << 10) ++#define VEC_CONFIG1_RGB (4 << 10) ++#define VEC_CONFIG1_Y_C_CVBS (5 << 10) ++#define VEC_CONFIG1_C_CVBS_Y (6 << 10) ++#define VEC_CONFIG1_C_CVBS_CVBS (7 << 10) ++#define VEC_CONFIG1_DIS_CHR BIT(9) ++#define VEC_CONFIG1_DIS_LUMA BIT(8) ++#define VEC_CONFIG1_YCBCR_IN BIT(6) ++#define VEC_CONFIG1_DITHER_TYPE_LFSR 0 ++#define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5) ++#define VEC_CONFIG1_DITHER_EN BIT(4) ++#define VEC_CONFIG1_CYDELAY BIT(3) ++#define VEC_CONFIG1_LUMADIS BIT(2) ++#define VEC_CONFIG1_COMPDIS BIT(1) ++#define VEC_CONFIG1_CUSTOM_FREQ BIT(0) ++ ++#define VEC_CONFIG2 0x18c ++#define VEC_CONFIG2_PROG_SCAN BIT(15) ++#define VEC_CONFIG2_SYNC_ADJ_MASK GENMASK(14, 12) ++#define VEC_CONFIG2_SYNC_ADJ(x) (((x) / 2) << 12) ++#define VEC_CONFIG2_PBPR_EN BIT(10) ++#define VEC_CONFIG2_UV_DIG_DIS BIT(6) ++#define VEC_CONFIG2_RGB_DIG_DIS BIT(5) ++#define VEC_CONFIG2_TMUX_MASK GENMASK(3, 2) ++#define VEC_CONFIG2_TMUX_DRIVE0 (0 << 2) ++#define VEC_CONFIG2_TMUX_RG_COMP (1 << 2) ++#define VEC_CONFIG2_TMUX_UV_YC (2 << 2) ++#define VEC_CONFIG2_TMUX_SYNC_YC (3 << 2) ++ ++#define VEC_INTERRUPT_CONTROL 0x190 ++#define VEC_INTERRUPT_STATUS 0x194 ++#define VEC_FCW_SECAM_B 0x198 ++#define VEC_SECAM_GAIN_VAL 0x19c ++ ++#define VEC_CONFIG3 0x1a0 ++#define VEC_CONFIG3_HORIZ_LEN_STD (0 << 0) ++#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0) ++#define VEC_CONFIG3_SHAPE_NON_LINEAR BIT(1) ++ ++#define VEC_STATUS0 0x200 ++#define VEC_MASK0 0x204 ++ ++#define VEC_CFG 0x208 ++#define VEC_CFG_SG_MODE_MASK GENMASK(6, 5) ++#define VEC_CFG_SG_MODE(x) ((x) << 5) ++#define VEC_CFG_SG_EN BIT(4) ++#define VEC_CFG_VEC_EN BIT(3) ++#define VEC_CFG_MB_EN BIT(2) ++#define VEC_CFG_ENABLE BIT(1) ++#define VEC_CFG_TB_EN BIT(0) ++ ++#define VEC_DAC_TEST 0x20c ++ ++#define VEC_DAC_CONFIG 0x210 ++#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24) ++#define VEC_DAC_CONFIG_DRIVER_CTRL(x) ((x) << 16) ++#define VEC_DAC_CONFIG_DAC_CTRL(x) (x) ++ ++#define VEC_DAC_MISC 0x214 ++#define VEC_DAC_MISC_VCD_CTRL_MASK GENMASK(31, 16) ++#define VEC_DAC_MISC_VCD_CTRL(x) ((x) << 16) ++#define VEC_DAC_MISC_VID_ACT BIT(8) ++#define VEC_DAC_MISC_VCD_PWRDN BIT(6) ++#define VEC_DAC_MISC_BIAS_PWRDN BIT(5) ++#define VEC_DAC_MISC_DAC_PWRDN BIT(2) ++#define VEC_DAC_MISC_LDO_PWRDN BIT(1) ++#define VEC_DAC_MISC_DAC_RST_N BIT(0) ++ ++ ++/* General VEC hardware state. */ ++struct vc4_vec { ++ struct platform_device *pdev; ++ ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ ++ void __iomem *regs; ++ ++ struct clk *clock; ++ ++ const struct vc4_vec_tv_mode *tv_mode; ++}; ++ ++#define VEC_READ(offset) readl(vec->regs + (offset)) ++#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset)) ++ ++/* VC4 VEC encoder KMS struct */ ++struct vc4_vec_encoder { ++ struct vc4_encoder base; ++ struct vc4_vec *vec; ++}; ++ ++static inline struct vc4_vec_encoder * ++to_vc4_vec_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_vec_encoder, base.base); ++} ++ ++/* VC4 VEC connector KMS struct */ ++struct vc4_vec_connector { ++ struct drm_connector base; ++ struct vc4_vec *vec; ++ ++ /* Since the connector is attached to just the one encoder, ++ * this is the reference to it so we can do the best_encoder() ++ * hook. ++ */ ++ struct drm_encoder *encoder; ++}; ++ ++static inline struct vc4_vec_connector * ++to_vc4_vec_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_vec_connector, base); ++} ++ ++enum vc4_vec_tv_mode_id { ++ VC4_VEC_TV_MODE_NTSC, ++ VC4_VEC_TV_MODE_NTSC_J, ++ VC4_VEC_TV_MODE_PAL, ++ VC4_VEC_TV_MODE_PAL_M, ++}; ++ ++struct vc4_vec_tv_mode { ++ const struct drm_display_mode *mode; ++ void (*mode_set)(struct vc4_vec *vec); ++}; ++ ++#define VEC_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} vec_regs[] = { ++ VEC_REG(VEC_WSE_CONTROL), ++ VEC_REG(VEC_WSE_WSS_DATA), ++ VEC_REG(VEC_WSE_VPS_DATA1), ++ VEC_REG(VEC_WSE_VPS_CONTROL), ++ VEC_REG(VEC_REVID), ++ VEC_REG(VEC_CONFIG0), ++ VEC_REG(VEC_SCHPH), ++ VEC_REG(VEC_CLMP0_START), ++ VEC_REG(VEC_CLMP0_END), ++ VEC_REG(VEC_FREQ3_2), ++ VEC_REG(VEC_FREQ1_0), ++ VEC_REG(VEC_CONFIG1), ++ VEC_REG(VEC_CONFIG2), ++ VEC_REG(VEC_INTERRUPT_CONTROL), ++ VEC_REG(VEC_INTERRUPT_STATUS), ++ VEC_REG(VEC_FCW_SECAM_B), ++ VEC_REG(VEC_SECAM_GAIN_VAL), ++ VEC_REG(VEC_CONFIG3), ++ VEC_REG(VEC_STATUS0), ++ VEC_REG(VEC_MASK0), ++ VEC_REG(VEC_CFG), ++ VEC_REG(VEC_DAC_TEST), ++ VEC_REG(VEC_DAC_CONFIG), ++ VEC_REG(VEC_DAC_MISC), ++}; ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_vec_debugfs_regs(struct seq_file *m, void *unused) ++{ ++ struct drm_info_node *node = (struct drm_info_node *)m->private; ++ struct drm_device *dev = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_vec *vec = vc4->vec; ++ int i; ++ ++ if (!vec) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(vec_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ vec_regs[i].name, vec_regs[i].reg, ++ VEC_READ(vec_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static const struct drm_display_mode ntsc_mode = { ++ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, ++ 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0, ++ DRM_MODE_FLAG_INTERLACE) ++}; ++ ++static void vc4_vec_pal_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); ++ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); ++} ++ ++static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec) ++{ ++ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); ++ VEC_WRITE(VEC_CONFIG1, ++ VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ); ++ VEC_WRITE(VEC_FREQ3_2, 0x223b); ++ VEC_WRITE(VEC_FREQ1_0, 0x61d1); ++} ++ ++static const struct drm_display_mode pal_mode = { ++ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, ++ 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0, ++ DRM_MODE_FLAG_INTERLACE) ++}; ++ ++static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { ++ [VC4_VEC_TV_MODE_NTSC] = { ++ .mode = &ntsc_mode, ++ .mode_set = vc4_vec_ntsc_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_NTSC_J] = { ++ .mode = &ntsc_mode, ++ .mode_set = vc4_vec_ntsc_j_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_PAL] = { ++ .mode = &pal_mode, ++ .mode_set = vc4_vec_pal_mode_set, ++ }, ++ [VC4_VEC_TV_MODE_PAL_M] = { ++ .mode = &pal_mode, ++ .mode_set = vc4_vec_pal_m_mode_set, ++ }, ++}; ++ ++static enum drm_connector_status ++vc4_vec_connector_detect(struct drm_connector *connector, bool force) ++{ ++ return connector_status_unknown; ++} ++ ++static void vc4_vec_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_vec_connector_get_modes(struct drm_connector *connector) ++{ ++ struct drm_connector_state *state = connector->state; ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, ++ vc4_vec_tv_modes[state->tv.mode].mode); ++ if (!mode) { ++ DRM_ERROR("Failed to create a new display mode\n"); ++ return -ENOMEM; ++ } ++ ++ drm_mode_probed_add(connector, mode); ++ ++ return 1; ++} ++ ++static const struct drm_connector_funcs vc4_vec_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_vec_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .set_property = drm_atomic_helper_connector_set_property, ++ .destroy = vc4_vec_connector_destroy, ++ .reset = drm_atomic_helper_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = { ++ .get_modes = vc4_vec_connector_get_modes, ++}; ++ ++static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, ++ struct vc4_vec *vec) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_vec_connector *vec_connector; ++ ++ vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector), ++ GFP_KERNEL); ++ if (!vec_connector) ++ return ERR_PTR(-ENOMEM); ++ ++ connector = &vec_connector->base; ++ connector->interlace_allowed = true; ++ ++ vec_connector->encoder = vec->encoder; ++ vec_connector->vec = vec; ++ ++ drm_connector_init(dev, connector, &vc4_vec_connector_funcs, ++ DRM_MODE_CONNECTOR_Composite); ++ drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs); ++ ++ drm_object_attach_property(&connector->base, ++ dev->mode_config.tv_mode_property, ++ VC4_VEC_TV_MODE_NTSC); ++ vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC]; ++ ++ drm_mode_connector_attach_encoder(connector, vec->encoder); ++ ++ return connector; ++} ++ ++static const struct drm_encoder_funcs vc4_vec_encoder_funcs = { ++ .destroy = drm_encoder_cleanup, ++}; ++ ++static void vc4_vec_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ int ret; ++ ++ VEC_WRITE(VEC_CFG, 0); ++ VEC_WRITE(VEC_DAC_MISC, ++ VEC_DAC_MISC_VCD_PWRDN | ++ VEC_DAC_MISC_BIAS_PWRDN | ++ VEC_DAC_MISC_DAC_PWRDN | ++ VEC_DAC_MISC_LDO_PWRDN); ++ ++ clk_disable_unprepare(vec->clock); ++ ++ ret = pm_runtime_put(&vec->pdev->dev); ++ if (ret < 0) { ++ DRM_ERROR("Failed to release power domain: %d\n", ret); ++ return; ++ } ++} ++ ++static void vc4_vec_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ int ret; ++ ++ ret = pm_runtime_get_sync(&vec->pdev->dev); ++ if (ret < 0) { ++ DRM_ERROR("Failed to retain power domain: %d\n", ret); ++ return; ++ } ++ ++ /* ++ * We need to set the clock rate each time we enable the encoder ++ * because there's a chance we share the same parent with the HDMI ++ * clock, and both drivers are requesting different rates. ++ * The good news is, these 2 encoders cannot be enabled at the same ++ * time, thus preventing incompatible rate requests. ++ */ ++ ret = clk_set_rate(vec->clock, 108000000); ++ if (ret) { ++ DRM_ERROR("Failed to set clock rate: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(vec->clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on core clock: %d\n", ret); ++ return; ++ } ++ ++ /* Reset the different blocks */ ++ VEC_WRITE(VEC_WSE_RESET, 1); ++ VEC_WRITE(VEC_SOFT_RESET, 1); ++ ++ /* Disable the CGSM-A and WSE blocks */ ++ VEC_WRITE(VEC_WSE_CONTROL, 0); ++ ++ /* Write config common to all modes. */ ++ ++ /* ++ * Color subcarrier phase: phase = 360 * SCHPH / 256. ++ * 0x28 <=> 39.375 deg. ++ */ ++ VEC_WRITE(VEC_SCHPH, 0x28); ++ ++ /* ++ * Reset to default values. ++ */ ++ VEC_WRITE(VEC_CLMP0_START, 0xac); ++ VEC_WRITE(VEC_CLMP0_END, 0xec); ++ VEC_WRITE(VEC_CONFIG2, ++ VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); ++ VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD); ++ VEC_WRITE(VEC_DAC_CONFIG, ++ VEC_DAC_CONFIG_DAC_CTRL(0xc) | ++ VEC_DAC_CONFIG_DRIVER_CTRL(0xc) | ++ VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46)); ++ ++ /* Mask all interrupts. */ ++ VEC_WRITE(VEC_MASK0, 0); ++ ++ vec->tv_mode->mode_set(vec); ++ ++ VEC_WRITE(VEC_DAC_MISC, ++ VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N); ++ VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN); ++} ++ ++ ++static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder, ++ const struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); ++ struct vc4_vec *vec = vc4_vec_encoder->vec; ++ ++ vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode]; ++} ++ ++static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ const struct vc4_vec_tv_mode *vec_mode; ++ ++ vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode]; ++ ++ if (conn_state->crtc && ++ !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = { ++ .disable = vc4_vec_encoder_disable, ++ .enable = vc4_vec_encoder_enable, ++ .mode_fixup = vc4_vec_encoder_mode_fixup, ++ .atomic_check = vc4_vec_encoder_atomic_check, ++ .atomic_mode_set = vc4_vec_encoder_atomic_mode_set, ++}; ++ ++static const struct of_device_id vc4_vec_dt_match[] = { ++ { .compatible = "brcm,bcm2835-vec", .data = NULL }, ++ { /* sentinel */ }, ++}; ++ ++static const char * const tv_mode_names[] = { ++ [VC4_VEC_TV_MODE_NTSC] = "NTSC", ++ [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J", ++ [VC4_VEC_TV_MODE_PAL] = "PAL", ++ [VC4_VEC_TV_MODE_PAL_M] = "PAL-M", ++}; ++ ++static int vc4_vec_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_vec *vec; ++ struct vc4_vec_encoder *vc4_vec_encoder; ++ int ret; ++ ++ ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names), ++ tv_mode_names); ++ if (ret) ++ return ret; ++ ++ vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL); ++ if (!vec) ++ return -ENOMEM; ++ ++ vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder), ++ GFP_KERNEL); ++ if (!vc4_vec_encoder) ++ return -ENOMEM; ++ vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC; ++ vc4_vec_encoder->vec = vec; ++ vec->encoder = &vc4_vec_encoder->base.base; ++ ++ vec->pdev = pdev; ++ vec->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(vec->regs)) ++ return PTR_ERR(vec->regs); ++ ++ vec->clock = devm_clk_get(dev, NULL); ++ if (IS_ERR(vec->clock)) { ++ ret = PTR_ERR(vec->clock); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Failed to get clock: %d\n", ret); ++ return ret; ++ } ++ ++ pm_runtime_enable(dev); ++ ++ drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs, ++ DRM_MODE_ENCODER_TVDAC, NULL); ++ drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs); ++ ++ vec->connector = vc4_vec_connector_init(drm, vec); ++ if (IS_ERR(vec->connector)) { ++ ret = PTR_ERR(vec->connector); ++ goto err_destroy_encoder; ++ } ++ ++ dev_set_drvdata(dev, vec); ++ ++ vc4->vec = vec; ++ ++ return 0; ++ ++err_destroy_encoder: ++ drm_encoder_cleanup(vec->encoder); ++ pm_runtime_disable(dev); ++ ++ return ret; ++} ++ ++static void vc4_vec_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_vec *vec = dev_get_drvdata(dev); ++ ++ vc4_vec_connector_destroy(vec->connector); ++ drm_encoder_cleanup(vec->encoder); ++ pm_runtime_disable(dev); ++ ++ vc4->vec = NULL; ++} ++ ++static const struct component_ops vc4_vec_ops = { ++ .bind = vc4_vec_bind, ++ .unbind = vc4_vec_unbind, ++}; ++ ++static int vc4_vec_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_vec_ops); ++} ++ ++static int vc4_vec_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_vec_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_vec_driver = { ++ .probe = vc4_vec_dev_probe, ++ .remove = vc4_vec_dev_remove, ++ .driver = { ++ .name = "vc4_vec", ++ .of_match_table = vc4_vec_dt_match, ++ }, ++}; + +From 5452c0c33ec0cf1a54fc06ae1cee9ec796755abc Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 15 Sep 2016 15:25:23 +0100 +Subject: [PATCH 167/187] drm/vc4: Set up SCALER_DISPCTRL at boot. + +We want the HVS on, obviously, and we also want DSP3 (PV1's source) to +be muxed from HVS channel 2 like we expect in vc4_crtc.c. The +firmware wasn't setting the DSP3 mux up when both the LCD and HDMI +were disabled. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++++++++ + drivers/gpu/drm/vc4/vc4_regs.h | 3 +++ + 2 files changed, 17 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c +index 6fbab1c82cb1089bde0834f3e0bf1fdf99f54221..fc68b1b4da5249ce3181d7eabb0a08bf8e4908cf 100644 +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -170,6 +170,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hvs *hvs = NULL; + int ret; ++ u32 dispctrl; + + hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); + if (!hvs) +@@ -211,6 +212,19 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + return ret; + + vc4->hvs = hvs; ++ ++ dispctrl = HVS_READ(SCALER_DISPCTRL); ++ ++ dispctrl |= SCALER_DISPCTRL_ENABLE; ++ ++ /* Set DSP3 (PV1) to use HVS channel 2, which would otherwise ++ * be unused. ++ */ ++ dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK; ++ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl); ++ + return 0; + } + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 39f6886b24100c43b590e47e0c7bc44846721d65..b3b297fba7097bc495fa8916292c547925720199 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -244,6 +244,9 @@ + # define SCALER_DISPCTRL_ENABLE BIT(31) + # define SCALER_DISPCTRL_DSP2EISLUR BIT(15) + # define SCALER_DISPCTRL_DSP1EISLUR BIT(14) ++# define SCALER_DISPCTRL_DSP3_MUX_MASK VC4_MASK(19, 18) ++# define SCALER_DISPCTRL_DSP3_MUX_SHIFT 18 ++ + /* Enables Display 0 short line and underrun contribution to + * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are + * always enabled. + +From 9d2402dc77e1f6e54af937611ddefb06b1abcaeb Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 10 Feb 2016 16:17:29 -0800 +Subject: [PATCH 168/187] drm/vc4: Add support for feeding DSI encoders from + the pixel valve. + +We have to set a different pixel format, which tells the hardware to +use the pix_width field that's fed in sideband from the DSI encoder to +divide the "pixel" clock. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 33 +++++++++++++++++++-------------- + drivers/gpu/drm/vc4/vc4_regs.h | 2 ++ + 2 files changed, 21 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +index bdf32c572fc2c46932daca934dfb002d05493883..0a861158740586836d2d47cccae4109ad4ec968d 100644 +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -352,38 +352,40 @@ static u32 vc4_get_fifo_full_level(u32 format) + } + + /* +- * Returns the clock select bit for the connector attached to the +- * CRTC. ++ * Returns the encoder attached to the CRTC. ++ * ++ * VC4 can only scan out to one encoder at a time, while the DRM core ++ * allows drivers to push pixels to more than one encoder from the ++ * same CRTC. + */ +-static int vc4_get_clock_select(struct drm_crtc *crtc) ++static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc) + { + struct drm_connector *connector; + + drm_for_each_connector(connector, crtc->dev) { + if (connector->state->crtc == crtc) { +- struct drm_encoder *encoder = connector->encoder; +- struct vc4_encoder *vc4_encoder = +- to_vc4_encoder(encoder); +- +- return vc4_encoder->clock_select; ++ return connector->encoder; + } + } + +- return -1; ++ return NULL; + } + + static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + { + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc); ++ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_crtc_state *state = crtc->state; + struct drm_display_mode *mode = &state->adjusted_mode; + bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; + u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; +- u32 format = PV_CONTROL_FORMAT_24; ++ bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || ++ vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); ++ u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; + bool debug_dump_regs = false; +- int clock_select = vc4_get_clock_select(crtc); + + if (debug_dump_regs) { + DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); +@@ -439,17 +441,19 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (is_dsi ? PV_VCONTROL_DSI : 0) | + PV_VCONTROL_INTERLACE | + VC4_SET_FIELD(mode->htotal * pixel_rep / 2, + PV_VCONTROL_ODD_DELAY)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } else { +- CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS); ++ CRTC_WRITE(PV_V_CONTROL, ++ PV_VCONTROL_CONTINUOUS | ++ (is_dsi ? PV_VCONTROL_DSI : 0)); + } + + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + +- + CRTC_WRITE(PV_CONTROL, + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | + VC4_SET_FIELD(vc4_get_fifo_full_level(format), +@@ -458,7 +462,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + PV_CONTROL_CLR_AT_START | + PV_CONTROL_TRIGGER_UNDERFLOW | + PV_CONTROL_WAIT_HSTART | +- VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | ++ VC4_SET_FIELD(vc4_encoder->clock_select, ++ PV_CONTROL_CLK_SELECT) | + PV_CONTROL_FIFO_CLR | + PV_CONTROL_EN); + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index b3b297fba7097bc495fa8916292c547925720199..385405a2df05eb3dd86d4f687aa8205331bec3cc 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -190,6 +190,8 @@ + # define PV_VCONTROL_ODD_DELAY_SHIFT 6 + # define PV_VCONTROL_ODD_FIRST BIT(5) + # define PV_VCONTROL_INTERLACE BIT(4) ++# define PV_VCONTROL_DSI BIT(3) ++# define PV_VCONTROL_COMMAND BIT(2) + # define PV_VCONTROL_CONTINUOUS BIT(1) + # define PV_VCONTROL_VIDEN BIT(0) + + +From 959631c073334693d310cef939854fa6dea82cd0 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 10 Feb 2016 11:42:32 -0800 +Subject: [PATCH 169/187] drm/vc4: Add DSI driver + +The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. +Some registers move around, and the featureset is slightly different, +as DSI1 (the 4-lane DSI) is a later version of the hardware block. +This driver doesn't yet enable DSI0, since we don't have any hardware +to test against, but it does put a lot of the register definitions and +code in place. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/Kconfig | 2 + + drivers/gpu/drm/vc4/Makefile | 1 + + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 5 + + drivers/gpu/drm/vc4/vc4_dsi.c | 1725 +++++++++++++++++++++++++++++++++++++ + 6 files changed, 1735 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/vc4_dsi.c + +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +index e53df59cb139f25f8e6ae916bca93abf0c49e063..e1517d07cb7d22776ca164a5d2d9b87e55a5563a 100644 +--- a/drivers/gpu/drm/vc4/Kconfig ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -2,10 +2,12 @@ config DRM_VC4 + tristate "Broadcom VC4 Graphics" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on DRM ++ depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select DRM_PANEL ++ select DRM_MIPI_DSI + help + Choose this option if you have a system that has a Broadcom + VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +index 3358ec8775cf6e8738ea8cdb2246dad57bd29139..897f658bee287f84f7dde8dca43090ad5541495b 100644 +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -8,6 +8,7 @@ vc4-y := \ + vc4_crtc.o \ + vc4_drv.o \ + vc4_dpi.o \ ++ vc4_dsi.o \ + vc4_firmware_kms.o \ + vc4_kms.o \ + vc4_gem.o \ +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index caf817bac8852c82f0d6a34b676a649c10e6e6cd..3ca476c6e0578e5fbe60d4fd623b09f8f937c0b7 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -18,6 +18,7 @@ + static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, + {"dpi_regs", vc4_dpi_debugfs_regs, 0}, ++ {"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, + {"vec_regs", vc4_vec_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +index 281609353063435f9da33f81bdc09dbc3ebc89e9..457e5e79ec8dc863fc66759662232c7160592f6e 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -296,6 +296,7 @@ static struct platform_driver *const component_drivers[] = { + &vc4_hdmi_driver, + &vc4_vec_driver, + &vc4_dpi_driver, ++ &vc4_dsi_driver, + &vc4_hvs_driver, + &vc4_crtc_driver, + &vc4_firmware_kms_driver, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 61a9b3e81823a3c96f36f710329844cc032e2628..44a8e6fda2b576fed63d93ef34e076cebf90d64c 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -20,6 +20,7 @@ struct vc4_dev { + struct vc4_crtc *crtc[3]; + struct vc4_v3d *v3d; + struct vc4_dpi *dpi; ++ struct vc4_dsi *dsi1; + struct vc4_vec *vec; + + struct drm_fbdev_cma *fbdev; +@@ -468,6 +469,10 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); + extern struct platform_driver vc4_dpi_driver; + int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); + ++/* vc4_dsi.c */ ++extern struct platform_driver vc4_dsi_driver; ++int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); ++ + /* vc4_firmware_kms.c */ + extern struct platform_driver vc4_firmware_kms_driver; + void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); +diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c +new file mode 100644 +index 0000000000000000000000000000000000000000..17fcac381dbb37cd9a5ff210ad8578f480177039 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_dsi.c +@@ -0,0 +1,1725 @@ ++/* ++ * Copyright (C) 2016 Broadcom ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++/** ++ * DOC: VC4 DSI0/DSI1 module ++ * ++ * BCM2835 contains two DSI modules, DSI0 and DSI1. DSI0 is a ++ * single-lane DSI controller, while DSI1 is a more modern 4-lane DSI ++ * controller. ++ * ++ * Most Raspberry Pi boards expose DSI1 as their "DISPLAY" connector, ++ * while the compute module brings both DSI0 and DSI1 out. ++ * ++ * This driver has been tested for DSI1 video-mode display only ++ * currently, with most of the information necessary for DSI0 ++ * hopefully present. ++ */ ++ ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_edid.h" ++#include "drm_mipi_dsi.h" ++#include "drm_panel.h" ++#include "linux/clk.h" ++#include "linux/clk-provider.h" ++#include "linux/completion.h" ++#include "linux/component.h" ++#include "linux/dmaengine.h" ++#include "linux/i2c.h" ++#include "linux/of_address.h" ++#include "linux/of_platform.h" ++#include "linux/pm_runtime.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define DSI_CMD_FIFO_DEPTH 16 ++#define DSI_PIX_FIFO_DEPTH 256 ++#define DSI_PIX_FIFO_WIDTH 4 ++ ++#define DSI0_CTRL 0x00 ++ ++/* Command packet control. */ ++#define DSI0_TXPKT1C 0x04 /* AKA PKTC */ ++#define DSI1_TXPKT1C 0x04 ++# define DSI_TXPKT1C_TRIG_CMD_MASK VC4_MASK(31, 24) ++# define DSI_TXPKT1C_TRIG_CMD_SHIFT 24 ++# define DSI_TXPKT1C_CMD_REPEAT_MASK VC4_MASK(23, 10) ++# define DSI_TXPKT1C_CMD_REPEAT_SHIFT 10 ++ ++# define DSI_TXPKT1C_DISPLAY_NO_MASK VC4_MASK(9, 8) ++# define DSI_TXPKT1C_DISPLAY_NO_SHIFT 8 ++/* Short, trigger, BTA, or a long packet that fits all in CMDFIFO. */ ++# define DSI_TXPKT1C_DISPLAY_NO_SHORT 0 ++/* Primary display where cmdfifo provides part of the payload and ++ * pixelvalve the rest. ++ */ ++# define DSI_TXPKT1C_DISPLAY_NO_PRIMARY 1 ++/* Secondary display where cmdfifo provides part of the payload and ++ * pixfifo the rest. ++ */ ++# define DSI_TXPKT1C_DISPLAY_NO_SECONDARY 2 ++ ++# define DSI_TXPKT1C_CMD_TX_TIME_MASK VC4_MASK(7, 6) ++# define DSI_TXPKT1C_CMD_TX_TIME_SHIFT 6 ++ ++# define DSI_TXPKT1C_CMD_CTRL_MASK VC4_MASK(5, 4) ++# define DSI_TXPKT1C_CMD_CTRL_SHIFT 4 ++/* Command only. Uses TXPKT1H and DISPLAY_NO */ ++# define DSI_TXPKT1C_CMD_CTRL_TX 0 ++/* Command with BTA for either ack or read data. */ ++# define DSI_TXPKT1C_CMD_CTRL_RX 1 ++/* Trigger according to TRIG_CMD */ ++# define DSI_TXPKT1C_CMD_CTRL_TRIG 2 ++/* BTA alone for getting error status after a command, or a TE trigger ++ * without a previous command. ++ */ ++# define DSI_TXPKT1C_CMD_CTRL_BTA 3 ++ ++# define DSI_TXPKT1C_CMD_MODE_LP BIT(3) ++# define DSI_TXPKT1C_CMD_TYPE_LONG BIT(2) ++# define DSI_TXPKT1C_CMD_TE_EN BIT(1) ++# define DSI_TXPKT1C_CMD_EN BIT(0) ++ ++/* Command packet header. */ ++#define DSI0_TXPKT1H 0x08 /* AKA PKTH */ ++#define DSI1_TXPKT1H 0x08 ++# define DSI_TXPKT1H_BC_CMDFIFO_MASK VC4_MASK(31, 24) ++# define DSI_TXPKT1H_BC_CMDFIFO_SHIFT 24 ++# define DSI_TXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_TXPKT1H_BC_PARAM_SHIFT 8 ++# define DSI_TXPKT1H_BC_DT_MASK VC4_MASK(7, 0) ++# define DSI_TXPKT1H_BC_DT_SHIFT 0 ++ ++#define DSI0_RXPKT1H 0x0c /* AKA RX1_PKTH */ ++#define DSI1_RXPKT1H 0x14 ++# define DSI_RXPKT1H_CRC_ERR BIT(31) ++# define DSI_RXPKT1H_DET_ERR BIT(30) ++# define DSI_RXPKT1H_ECC_ERR BIT(29) ++# define DSI_RXPKT1H_COR_ERR BIT(28) ++# define DSI_RXPKT1H_INCOMP_PKT BIT(25) ++# define DSI_RXPKT1H_PKT_TYPE_LONG BIT(24) ++/* Byte count if DSI_RXPKT1H_PKT_TYPE_LONG */ ++# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 ++/* Short return bytes if !DSI_RXPKT1H_PKT_TYPE_LONG */ ++# define DSI_RXPKT1H_SHORT_1_MASK VC4_MASK(23, 16) ++# define DSI_RXPKT1H_SHORT_1_SHIFT 16 ++# define DSI_RXPKT1H_SHORT_0_MASK VC4_MASK(15, 8) ++# define DSI_RXPKT1H_SHORT_0_SHIFT 8 ++# define DSI_RXPKT1H_DT_LP_CMD_MASK VC4_MASK(7, 0) ++# define DSI_RXPKT1H_DT_LP_CMD_SHIFT 0 ++ ++#define DSI0_RXPKT2H 0x10 /* AKA RX2_PKTH */ ++#define DSI1_RXPKT2H 0x18 ++# define DSI_RXPKT1H_DET_ERR BIT(30) ++# define DSI_RXPKT1H_ECC_ERR BIT(29) ++# define DSI_RXPKT1H_COR_ERR BIT(28) ++# define DSI_RXPKT1H_INCOMP_PKT BIT(25) ++# define DSI_RXPKT1H_BC_PARAM_MASK VC4_MASK(23, 8) ++# define DSI_RXPKT1H_BC_PARAM_SHIFT 8 ++# define DSI_RXPKT1H_DT_MASK VC4_MASK(7, 0) ++# define DSI_RXPKT1H_DT_SHIFT 0 ++ ++#define DSI0_TXPKT_CMD_FIFO 0x14 /* AKA CMD_DATAF */ ++#define DSI1_TXPKT_CMD_FIFO 0x1c ++ ++#define DSI0_DISP0_CTRL 0x18 ++# define DSI_DISP0_PIX_CLK_DIV_MASK VC4_MASK(21, 13) ++# define DSI_DISP0_PIX_CLK_DIV_SHIFT 13 ++# define DSI_DISP0_LP_STOP_CTRL_MASK VC4_MASK(12, 11) ++# define DSI_DISP0_LP_STOP_CTRL_SHIFT 11 ++# define DSI_DISP0_LP_STOP_DISABLE 0 ++# define DSI_DISP0_LP_STOP_PERLINE 1 ++# define DSI_DISP0_LP_STOP_PERFRAME 2 ++ ++/* Transmit RGB pixels and null packets only during HACTIVE, instead ++ * of going to LP-STOP. ++ */ ++# define DSI_DISP_HACTIVE_NULL BIT(10) ++/* Transmit blanking packet only during vblank, instead of allowing LP-STOP. */ ++# define DSI_DISP_VBLP_CTRL BIT(9) ++/* Transmit blanking packet only during HFP, instead of allowing LP-STOP. */ ++# define DSI_DISP_HFP_CTRL BIT(8) ++/* Transmit blanking packet only during HBP, instead of allowing LP-STOP. */ ++# define DSI_DISP_HBP_CTRL BIT(7) ++# define DSI_DISP0_CHANNEL_MASK VC4_MASK(6, 5) ++# define DSI_DISP0_CHANNEL_SHIFT 5 ++/* Enables end events for HSYNC/VSYNC, not just start events. */ ++# define DSI_DISP0_ST_END BIT(4) ++# define DSI_DISP0_PFORMAT_MASK VC4_MASK(3, 2) ++# define DSI_DISP0_PFORMAT_SHIFT 2 ++# define DSI_PFORMAT_RGB565 0 ++# define DSI_PFORMAT_RGB666_PACKED 1 ++# define DSI_PFORMAT_RGB666 2 ++# define DSI_PFORMAT_RGB888 3 ++/* Default is VIDEO mode. */ ++# define DSI_DISP0_COMMAND_MODE BIT(1) ++# define DSI_DISP0_ENABLE BIT(0) ++ ++#define DSI0_DISP1_CTRL 0x1c ++#define DSI1_DISP1_CTRL 0x2c ++/* Format of the data written to TXPKT_PIX_FIFO. */ ++# define DSI_DISP1_PFORMAT_MASK VC4_MASK(2, 1) ++# define DSI_DISP1_PFORMAT_SHIFT 1 ++# define DSI_DISP1_PFORMAT_16BIT 0 ++# define DSI_DISP1_PFORMAT_24BIT 1 ++# define DSI_DISP1_PFORMAT_32BIT_LE 2 ++# define DSI_DISP1_PFORMAT_32BIT_BE 3 ++ ++/* DISP1 is always command mode. */ ++# define DSI_DISP1_ENABLE BIT(0) ++ ++#define DSI0_TXPKT_PIX_FIFO 0x20 /* AKA PIX_FIFO */ ++ ++#define DSI0_INT_STAT 0x24 ++#define DSI0_INT_EN 0x28 ++# define DSI1_INT_PHY_D3_ULPS BIT(30) ++# define DSI1_INT_PHY_D3_STOP BIT(29) ++# define DSI1_INT_PHY_D2_ULPS BIT(28) ++# define DSI1_INT_PHY_D2_STOP BIT(27) ++# define DSI1_INT_PHY_D1_ULPS BIT(26) ++# define DSI1_INT_PHY_D1_STOP BIT(25) ++# define DSI1_INT_PHY_D0_ULPS BIT(24) ++# define DSI1_INT_PHY_D0_STOP BIT(23) ++# define DSI1_INT_FIFO_ERR BIT(22) ++# define DSI1_INT_PHY_DIR_RTF BIT(21) ++# define DSI1_INT_PHY_RXLPDT BIT(20) ++# define DSI1_INT_PHY_RXTRIG BIT(19) ++# define DSI1_INT_PHY_D0_LPDT BIT(18) ++# define DSI1_INT_PHY_DIR_FTR BIT(17) ++ ++/* Signaled when the clock lane enters the given state. */ ++# define DSI1_INT_PHY_CLOCK_ULPS BIT(16) ++# define DSI1_INT_PHY_CLOCK_HS BIT(15) ++# define DSI1_INT_PHY_CLOCK_STOP BIT(14) ++ ++/* Signaled on timeouts */ ++# define DSI1_INT_PR_TO BIT(13) ++# define DSI1_INT_TA_TO BIT(12) ++# define DSI1_INT_LPRX_TO BIT(11) ++# define DSI1_INT_HSTX_TO BIT(10) ++ ++/* Contention on a line when trying to drive the line low */ ++# define DSI1_INT_ERR_CONT_LP1 BIT(9) ++# define DSI1_INT_ERR_CONT_LP0 BIT(8) ++ ++/* Control error: incorrect line state sequence on data lane 0. */ ++# define DSI1_INT_ERR_CONTROL BIT(7) ++/* LPDT synchronization error (bits received not a multiple of 8. */ ++ ++# define DSI1_INT_ERR_SYNC_ESC BIT(6) ++/* Signaled after receiving an error packet from the display in ++ * response to a read. ++ */ ++# define DSI1_INT_RXPKT2 BIT(5) ++/* Signaled after receiving a packet. The header and optional short ++ * response will be in RXPKT1H, and a long response will be in the ++ * RXPKT_FIFO. ++ */ ++# define DSI1_INT_RXPKT1 BIT(4) ++# define DSI1_INT_TXPKT2_DONE BIT(3) ++# define DSI1_INT_TXPKT2_END BIT(2) ++/* Signaled after all repeats of TXPKT1 are transferred. */ ++# define DSI1_INT_TXPKT1_DONE BIT(1) ++/* Signaled after each TXPKT1 repeat is scheduled. */ ++# define DSI1_INT_TXPKT1_END BIT(0) ++ ++#define DSI1_INTERRUPTS_ALWAYS_ENABLED (DSI1_INT_ERR_SYNC_ESC | \ ++ DSI1_INT_ERR_CONTROL | \ ++ DSI1_INT_ERR_CONT_LP0 | \ ++ DSI1_INT_ERR_CONT_LP1 | \ ++ DSI1_INT_HSTX_TO | \ ++ DSI1_INT_LPRX_TO | \ ++ DSI1_INT_TA_TO | \ ++ DSI1_INT_PR_TO) ++ ++#define DSI0_STAT 0x2c ++#define DSI0_HSTX_TO_CNT 0x30 ++#define DSI0_LPRX_TO_CNT 0x34 ++#define DSI0_TA_TO_CNT 0x38 ++#define DSI0_PR_TO_CNT 0x3c ++#define DSI0_PHYC 0x40 ++# define DSI1_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(25, 20) ++# define DSI1_PHYC_ESC_CLK_LPDT_SHIFT 20 ++# define DSI1_PHYC_HS_CLK_CONTINUOUS BIT(18) ++# define DSI0_PHYC_ESC_CLK_LPDT_MASK VC4_MASK(17, 12) ++# define DSI0_PHYC_ESC_CLK_LPDT_SHIFT 12 ++# define DSI1_PHYC_CLANE_ULPS BIT(17) ++# define DSI1_PHYC_CLANE_ENABLE BIT(16) ++# define DSI_PHYC_DLANE3_ULPS BIT(13) ++# define DSI_PHYC_DLANE3_ENABLE BIT(12) ++# define DSI0_PHYC_HS_CLK_CONTINUOUS BIT(10) ++# define DSI0_PHYC_CLANE_ULPS BIT(9) ++# define DSI_PHYC_DLANE2_ULPS BIT(9) ++# define DSI0_PHYC_CLANE_ENABLE BIT(8) ++# define DSI_PHYC_DLANE2_ENABLE BIT(8) ++# define DSI_PHYC_DLANE1_ULPS BIT(5) ++# define DSI_PHYC_DLANE1_ENABLE BIT(4) ++# define DSI_PHYC_DLANE0_FORCE_STOP BIT(2) ++# define DSI_PHYC_DLANE0_ULPS BIT(1) ++# define DSI_PHYC_DLANE0_ENABLE BIT(0) ++ ++#define DSI0_HS_CLT0 0x44 ++#define DSI0_HS_CLT1 0x48 ++#define DSI0_HS_CLT2 0x4c ++#define DSI0_HS_DLT3 0x50 ++#define DSI0_HS_DLT4 0x54 ++#define DSI0_HS_DLT5 0x58 ++#define DSI0_HS_DLT6 0x5c ++#define DSI0_HS_DLT7 0x60 ++ ++#define DSI0_PHY_AFEC0 0x64 ++# define DSI0_PHY_AFEC0_DDR2CLK_EN BIT(26) ++# define DSI0_PHY_AFEC0_DDRCLK_EN BIT(25) ++# define DSI0_PHY_AFEC0_LATCH_ULPS BIT(24) ++# define DSI1_PHY_AFEC0_IDR_DLANE3_MASK VC4_MASK(31, 29) ++# define DSI1_PHY_AFEC0_IDR_DLANE3_SHIFT 29 ++# define DSI1_PHY_AFEC0_IDR_DLANE2_MASK VC4_MASK(28, 26) ++# define DSI1_PHY_AFEC0_IDR_DLANE2_SHIFT 26 ++# define DSI1_PHY_AFEC0_IDR_DLANE1_MASK VC4_MASK(27, 23) ++# define DSI1_PHY_AFEC0_IDR_DLANE1_SHIFT 23 ++# define DSI1_PHY_AFEC0_IDR_DLANE0_MASK VC4_MASK(22, 20) ++# define DSI1_PHY_AFEC0_IDR_DLANE0_SHIFT 20 ++# define DSI1_PHY_AFEC0_IDR_CLANE_MASK VC4_MASK(19, 17) ++# define DSI1_PHY_AFEC0_IDR_CLANE_SHIFT 17 ++# define DSI0_PHY_AFEC0_ACTRL_DLANE1_MASK VC4_MASK(23, 20) ++# define DSI0_PHY_AFEC0_ACTRL_DLANE1_SHIFT 20 ++# define DSI0_PHY_AFEC0_ACTRL_DLANE0_MASK VC4_MASK(19, 16) ++# define DSI0_PHY_AFEC0_ACTRL_DLANE0_SHIFT 16 ++# define DSI0_PHY_AFEC0_ACTRL_CLANE_MASK VC4_MASK(15, 12) ++# define DSI0_PHY_AFEC0_ACTRL_CLANE_SHIFT 12 ++# define DSI1_PHY_AFEC0_DDR2CLK_EN BIT(16) ++# define DSI1_PHY_AFEC0_DDRCLK_EN BIT(15) ++# define DSI1_PHY_AFEC0_LATCH_ULPS BIT(14) ++# define DSI1_PHY_AFEC0_RESET BIT(13) ++# define DSI1_PHY_AFEC0_PD BIT(12) ++# define DSI0_PHY_AFEC0_RESET BIT(11) ++# define DSI1_PHY_AFEC0_PD_BG BIT(11) ++# define DSI0_PHY_AFEC0_PD BIT(10) ++# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(10) ++# define DSI0_PHY_AFEC0_PD_BG BIT(9) ++# define DSI1_PHY_AFEC0_PD_DLANE2 BIT(9) ++# define DSI0_PHY_AFEC0_PD_DLANE1 BIT(8) ++# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(8) ++# define DSI_PHY_AFEC0_PTATADJ_MASK VC4_MASK(7, 4) ++# define DSI_PHY_AFEC0_PTATADJ_SHIFT 4 ++# define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) ++# define DSI_PHY_AFEC0_CTATADJ_SHIFT 0 ++ ++#define DSI0_PHY_AFEC1 0x68 ++# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8) ++# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8 ++# define DSI0_PHY_AFEC1_IDR_DLANE0_MASK VC4_MASK(6, 4) ++# define DSI0_PHY_AFEC1_IDR_DLANE0_SHIFT 4 ++# define DSI0_PHY_AFEC1_IDR_CLANE_MASK VC4_MASK(2, 0) ++# define DSI0_PHY_AFEC1_IDR_CLANE_SHIFT 0 ++ ++#define DSI0_TST_SEL 0x6c ++#define DSI0_TST_MON 0x70 ++#define DSI0_ID 0x74 ++# define DSI_ID_VALUE 0x00647369 ++ ++#define DSI1_CTRL 0x00 ++# define DSI_CTRL_HS_CLKC_MASK VC4_MASK(15, 14) ++# define DSI_CTRL_HS_CLKC_SHIFT 14 ++# define DSI_CTRL_HS_CLKC_BYTE 0 ++# define DSI_CTRL_HS_CLKC_DDR2 1 ++# define DSI_CTRL_HS_CLKC_DDR 2 ++ ++# define DSI_CTRL_RX_LPDT_EOT_DISABLE BIT(13) ++# define DSI_CTRL_LPDT_EOT_DISABLE BIT(12) ++# define DSI_CTRL_HSDT_EOT_DISABLE BIT(11) ++# define DSI_CTRL_SOFT_RESET_CFG BIT(10) ++# define DSI_CTRL_CAL_BYTE BIT(9) ++# define DSI_CTRL_INV_BYTE BIT(8) ++# define DSI_CTRL_CLR_LDF BIT(7) ++# define DSI0_CTRL_CLR_PBCF BIT(6) ++# define DSI1_CTRL_CLR_RXF BIT(6) ++# define DSI0_CTRL_CLR_CPBCF BIT(5) ++# define DSI1_CTRL_CLR_PDF BIT(5) ++# define DSI0_CTRL_CLR_PDF BIT(4) ++# define DSI1_CTRL_CLR_CDF BIT(4) ++# define DSI0_CTRL_CLR_CDF BIT(3) ++# define DSI0_CTRL_CTRL2 BIT(2) ++# define DSI1_CTRL_DISABLE_DISP_CRCC BIT(2) ++# define DSI0_CTRL_CTRL1 BIT(1) ++# define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1) ++# define DSI0_CTRL_CTRL0 BIT(0) ++# define DSI1_CTRL_EN BIT(0) ++# define DSI0_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ ++ DSI0_CTRL_CLR_PBCF | \ ++ DSI0_CTRL_CLR_CPBCF | \ ++ DSI0_CTRL_CLR_PDF | \ ++ DSI0_CTRL_CLR_CDF) ++# define DSI1_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \ ++ DSI1_CTRL_CLR_RXF | \ ++ DSI1_CTRL_CLR_PDF | \ ++ DSI1_CTRL_CLR_CDF) ++ ++#define DSI1_TXPKT2C 0x0c ++#define DSI1_TXPKT2H 0x10 ++#define DSI1_TXPKT_PIX_FIFO 0x20 ++#define DSI1_RXPKT_FIFO 0x24 ++#define DSI1_DISP0_CTRL 0x28 ++#define DSI1_INT_STAT 0x30 ++#define DSI1_INT_EN 0x34 ++/* State reporting bits. These mostly behave like INT_STAT, where ++ * writing a 1 clears the bit. ++ */ ++#define DSI1_STAT 0x38 ++# define DSI1_STAT_PHY_D3_ULPS BIT(31) ++# define DSI1_STAT_PHY_D3_STOP BIT(30) ++# define DSI1_STAT_PHY_D2_ULPS BIT(29) ++# define DSI1_STAT_PHY_D2_STOP BIT(28) ++# define DSI1_STAT_PHY_D1_ULPS BIT(27) ++# define DSI1_STAT_PHY_D1_STOP BIT(26) ++# define DSI1_STAT_PHY_D0_ULPS BIT(25) ++# define DSI1_STAT_PHY_D0_STOP BIT(24) ++# define DSI1_STAT_FIFO_ERR BIT(23) ++# define DSI1_STAT_PHY_RXLPDT BIT(22) ++# define DSI1_STAT_PHY_RXTRIG BIT(21) ++# define DSI1_STAT_PHY_D0_LPDT BIT(20) ++/* Set when in forward direction */ ++# define DSI1_STAT_PHY_DIR BIT(19) ++# define DSI1_STAT_PHY_CLOCK_ULPS BIT(18) ++# define DSI1_STAT_PHY_CLOCK_HS BIT(17) ++# define DSI1_STAT_PHY_CLOCK_STOP BIT(16) ++# define DSI1_STAT_PR_TO BIT(15) ++# define DSI1_STAT_TA_TO BIT(14) ++# define DSI1_STAT_LPRX_TO BIT(13) ++# define DSI1_STAT_HSTX_TO BIT(12) ++# define DSI1_STAT_ERR_CONT_LP1 BIT(11) ++# define DSI1_STAT_ERR_CONT_LP0 BIT(10) ++# define DSI1_STAT_ERR_CONTROL BIT(9) ++# define DSI1_STAT_ERR_SYNC_ESC BIT(8) ++# define DSI1_STAT_RXPKT2 BIT(7) ++# define DSI1_STAT_RXPKT1 BIT(6) ++# define DSI1_STAT_TXPKT2_BUSY BIT(5) ++# define DSI1_STAT_TXPKT2_DONE BIT(4) ++# define DSI1_STAT_TXPKT2_END BIT(3) ++# define DSI1_STAT_TXPKT1_BUSY BIT(2) ++# define DSI1_STAT_TXPKT1_DONE BIT(1) ++# define DSI1_STAT_TXPKT1_END BIT(0) ++ ++#define DSI1_HSTX_TO_CNT 0x3c ++#define DSI1_LPRX_TO_CNT 0x40 ++#define DSI1_TA_TO_CNT 0x44 ++#define DSI1_PR_TO_CNT 0x48 ++#define DSI1_PHYC 0x4c ++ ++#define DSI1_HS_CLT0 0x50 ++# define DSI_HS_CLT0_CZERO_MASK VC4_MASK(26, 18) ++# define DSI_HS_CLT0_CZERO_SHIFT 18 ++# define DSI_HS_CLT0_CPRE_MASK VC4_MASK(17, 9) ++# define DSI_HS_CLT0_CPRE_SHIFT 9 ++# define DSI_HS_CLT0_CPREP_MASK VC4_MASK(8, 0) ++# define DSI_HS_CLT0_CPREP_SHIFT 0 ++ ++#define DSI1_HS_CLT1 0x54 ++# define DSI_HS_CLT1_CTRAIL_MASK VC4_MASK(17, 9) ++# define DSI_HS_CLT1_CTRAIL_SHIFT 9 ++# define DSI_HS_CLT1_CPOST_MASK VC4_MASK(8, 0) ++# define DSI_HS_CLT1_CPOST_SHIFT 0 ++ ++#define DSI1_HS_CLT2 0x58 ++# define DSI_HS_CLT2_WUP_MASK VC4_MASK(23, 0) ++# define DSI_HS_CLT2_WUP_SHIFT 0 ++ ++#define DSI1_HS_DLT3 0x5c ++# define DSI_HS_DLT3_EXIT_MASK VC4_MASK(26, 18) ++# define DSI_HS_DLT3_EXIT_SHIFT 18 ++# define DSI_HS_DLT3_ZERO_MASK VC4_MASK(17, 9) ++# define DSI_HS_DLT3_ZERO_SHIFT 9 ++# define DSI_HS_DLT3_PRE_MASK VC4_MASK(8, 0) ++# define DSI_HS_DLT3_PRE_SHIFT 0 ++ ++#define DSI1_HS_DLT4 0x60 ++# define DSI_HS_DLT4_ANLAT_MASK VC4_MASK(22, 18) ++# define DSI_HS_DLT4_ANLAT_SHIFT 18 ++# define DSI_HS_DLT4_TRAIL_MASK VC4_MASK(17, 9) ++# define DSI_HS_DLT4_TRAIL_SHIFT 9 ++# define DSI_HS_DLT4_LPX_MASK VC4_MASK(8, 0) ++# define DSI_HS_DLT4_LPX_SHIFT 0 ++ ++#define DSI1_HS_DLT5 0x64 ++# define DSI_HS_DLT5_INIT_MASK VC4_MASK(23, 0) ++# define DSI_HS_DLT5_INIT_SHIFT 0 ++ ++#define DSI1_HS_DLT6 0x68 ++# define DSI_HS_DLT6_TA_GET_MASK VC4_MASK(31, 24) ++# define DSI_HS_DLT6_TA_GET_SHIFT 24 ++# define DSI_HS_DLT6_TA_SURE_MASK VC4_MASK(23, 16) ++# define DSI_HS_DLT6_TA_SURE_SHIFT 16 ++# define DSI_HS_DLT6_TA_GO_MASK VC4_MASK(15, 8) ++# define DSI_HS_DLT6_TA_GO_SHIFT 8 ++# define DSI_HS_DLT6_LP_LPX_MASK VC4_MASK(7, 0) ++# define DSI_HS_DLT6_LP_LPX_SHIFT 0 ++ ++#define DSI1_HS_DLT7 0x6c ++# define DSI_HS_DLT7_LP_WUP_MASK VC4_MASK(23, 0) ++# define DSI_HS_DLT7_LP_WUP_SHIFT 0 ++ ++#define DSI1_PHY_AFEC0 0x70 ++ ++#define DSI1_PHY_AFEC1 0x74 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE3_MASK VC4_MASK(19, 16) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE3_SHIFT 16 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE2_MASK VC4_MASK(15, 12) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE2_SHIFT 12 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE1_MASK VC4_MASK(11, 8) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE1_SHIFT 8 ++# define DSI1_PHY_AFEC1_ACTRL_DLANE0_MASK VC4_MASK(7, 4) ++# define DSI1_PHY_AFEC1_ACTRL_DLANE0_SHIFT 4 ++# define DSI1_PHY_AFEC1_ACTRL_CLANE_MASK VC4_MASK(3, 0) ++# define DSI1_PHY_AFEC1_ACTRL_CLANE_SHIFT 0 ++ ++#define DSI1_TST_SEL 0x78 ++#define DSI1_TST_MON 0x7c ++#define DSI1_PHY_TST1 0x80 ++#define DSI1_PHY_TST2 0x84 ++#define DSI1_PHY_FIFO_STAT 0x88 ++/* Actually, all registers in the range that aren't otherwise claimed ++ * will return the ID. ++ */ ++#define DSI1_ID 0x8c ++ ++/* General DSI hardware state. */ ++struct vc4_dsi { ++ struct platform_device *pdev; ++ ++ struct mipi_dsi_host dsi_host; ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ struct drm_panel *panel; ++ ++ void __iomem *regs; ++ ++ struct dma_chan *reg_dma_chan; ++ dma_addr_t reg_dma_paddr; ++ u32 *reg_dma_mem; ++ dma_addr_t reg_paddr; ++ ++ /* Whether we're on bcm2835's DSI0 or DSI1. */ ++ int port; ++ ++ /* DSI channel for the panel we're connected to. */ ++ u32 channel; ++ u32 lanes; ++ enum mipi_dsi_pixel_format format; ++ u32 mode_flags; ++ ++ /* Input clock from CPRMAN to the digital PHY, for the DSI ++ * escape clock. ++ */ ++ struct clk *escape_clock; ++ ++ /* Input clock to the analog PHY, used to generate the DSI bit ++ * clock. ++ */ ++ struct clk *pll_phy_clock; ++ ++ /* HS Clocks generated within the DSI analog PHY. */ ++ struct clk_fixed_factor phy_clocks[3]; ++ ++ struct clk_onecell_data clk_onecell; ++ ++ /* Pixel clock output to the pixelvalve, generated from the HS ++ * clock. ++ */ ++ struct clk *pixel_clock; ++ ++ struct completion xfer_completion; ++ int xfer_result; ++}; ++ ++#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) ++ ++static inline void ++dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) ++{ ++ struct dma_chan *chan = dsi->reg_dma_chan; ++ struct dma_async_tx_descriptor *tx; ++ dma_cookie_t cookie; ++ int ret; ++ ++ /* DSI0 should be able to write normally. */ ++ if (!chan) { ++ writel(val, dsi->regs + offset); ++ return; ++ } ++ ++ *dsi->reg_dma_mem = val; ++ ++ tx = chan->device->device_prep_dma_memcpy(chan, ++ dsi->reg_paddr + offset, ++ dsi->reg_dma_paddr, ++ 4, 0); ++ if (!tx) { ++ DRM_ERROR("Failed to set up DMA register write\n"); ++ return; ++ } ++ ++ cookie = tx->tx_submit(tx); ++ ret = dma_submit_error(cookie); ++ if (ret) { ++ DRM_ERROR("Failed to submit DMA: %d\n", ret); ++ return; ++ } ++ ret = dma_sync_wait(chan, cookie); ++ if (ret) ++ DRM_ERROR("Failed to wait for DMA: %d\n", ret); ++} ++ ++#define DSI_READ(offset) readl(dsi->regs + (offset)) ++#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) ++#define DSI_PORT_READ(offset) \ ++ DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset) ++#define DSI_PORT_WRITE(offset, val) \ ++ DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) ++#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) ++ ++/* VC4 DSI encoder KMS struct */ ++struct vc4_dsi_encoder { ++ struct vc4_encoder base; ++ struct vc4_dsi *dsi; ++}; ++ ++static inline struct vc4_dsi_encoder * ++to_vc4_dsi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_dsi_encoder, base.base); ++} ++ ++/* VC4 DSI connector KMS struct */ ++struct vc4_dsi_connector { ++ struct drm_connector base; ++ struct vc4_dsi *dsi; ++}; ++ ++static inline struct vc4_dsi_connector * ++to_vc4_dsi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_dsi_connector, base); ++} ++ ++#define DSI_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} dsi0_regs[] = { ++ DSI_REG(DSI0_CTRL), ++ DSI_REG(DSI0_STAT), ++ DSI_REG(DSI0_HSTX_TO_CNT), ++ DSI_REG(DSI0_LPRX_TO_CNT), ++ DSI_REG(DSI0_TA_TO_CNT), ++ DSI_REG(DSI0_PR_TO_CNT), ++ DSI_REG(DSI0_DISP0_CTRL), ++ DSI_REG(DSI0_DISP1_CTRL), ++ DSI_REG(DSI0_INT_STAT), ++ DSI_REG(DSI0_INT_EN), ++ DSI_REG(DSI0_PHYC), ++ DSI_REG(DSI0_HS_CLT0), ++ DSI_REG(DSI0_HS_CLT1), ++ DSI_REG(DSI0_HS_CLT2), ++ DSI_REG(DSI0_HS_DLT3), ++ DSI_REG(DSI0_HS_DLT4), ++ DSI_REG(DSI0_HS_DLT5), ++ DSI_REG(DSI0_HS_DLT6), ++ DSI_REG(DSI0_HS_DLT7), ++ DSI_REG(DSI0_PHY_AFEC0), ++ DSI_REG(DSI0_PHY_AFEC1), ++ DSI_REG(DSI0_ID), ++}; ++ ++static const struct { ++ u32 reg; ++ const char *name; ++} dsi1_regs[] = { ++ DSI_REG(DSI1_CTRL), ++ DSI_REG(DSI1_STAT), ++ DSI_REG(DSI1_HSTX_TO_CNT), ++ DSI_REG(DSI1_LPRX_TO_CNT), ++ DSI_REG(DSI1_TA_TO_CNT), ++ DSI_REG(DSI1_PR_TO_CNT), ++ DSI_REG(DSI1_DISP0_CTRL), ++ DSI_REG(DSI1_DISP1_CTRL), ++ DSI_REG(DSI1_INT_STAT), ++ DSI_REG(DSI1_INT_EN), ++ DSI_REG(DSI1_PHYC), ++ DSI_REG(DSI1_HS_CLT0), ++ DSI_REG(DSI1_HS_CLT1), ++ DSI_REG(DSI1_HS_CLT2), ++ DSI_REG(DSI1_HS_DLT3), ++ DSI_REG(DSI1_HS_DLT4), ++ DSI_REG(DSI1_HS_DLT5), ++ DSI_REG(DSI1_HS_DLT6), ++ DSI_REG(DSI1_HS_DLT7), ++ DSI_REG(DSI1_PHY_AFEC0), ++ DSI_REG(DSI1_PHY_AFEC1), ++ DSI_REG(DSI1_ID), ++}; ++ ++static void vc4_dsi_dump_regs(struct vc4_dsi *dsi) ++{ ++ int i; ++ ++ if (dsi->port == 0) { ++ for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ dsi0_regs[i].reg, dsi0_regs[i].name, ++ DSI_READ(dsi0_regs[i].reg)); ++ } ++ } else { ++ for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ dsi1_regs[i].reg, dsi1_regs[i].name, ++ DSI_READ(dsi1_regs[i].reg)); ++ } ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused) ++{ ++ struct drm_info_node *node = (struct drm_info_node *)m->private; ++ struct drm_device *drm = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ int dsi_index = (uintptr_t)node->info_ent->data; ++ struct vc4_dsi *dsi = (dsi_index == 1 ? vc4->dsi1 : NULL); ++ int i; ++ ++ if (!dsi) ++ return 0; ++ ++ if (dsi->port == 0) { ++ for (i = 0; i < ARRAY_SIZE(dsi0_regs); i++) { ++ seq_printf(m, "0x%04x (%s): 0x%08x\n", ++ dsi0_regs[i].reg, dsi0_regs[i].name, ++ DSI_READ(dsi0_regs[i].reg)); ++ } ++ } else { ++ for (i = 0; i < ARRAY_SIZE(dsi1_regs); i++) { ++ seq_printf(m, "0x%04x (%s): 0x%08x\n", ++ dsi1_regs[i].reg, dsi1_regs[i].name, ++ DSI_READ(dsi1_regs[i].reg)); ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static enum drm_connector_status ++vc4_dsi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct vc4_dsi_connector *vc4_connector = ++ to_vc4_dsi_connector(connector); ++ struct vc4_dsi *dsi = vc4_connector->dsi; ++ ++ if (dsi->panel) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++} ++ ++static void vc4_dsi_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_dsi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct vc4_dsi_connector *vc4_connector = ++ to_vc4_dsi_connector(connector); ++ struct vc4_dsi *dsi = vc4_connector->dsi; ++ ++ if (dsi->panel) ++ return drm_panel_get_modes(dsi->panel); ++ ++ return 0; ++} ++ ++static const struct drm_connector_funcs vc4_dsi_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_dsi_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = vc4_dsi_connector_destroy, ++ .reset = drm_atomic_helper_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_connector_helper_funcs vc4_dsi_connector_helper_funcs = { ++ .get_modes = vc4_dsi_connector_get_modes, ++}; ++ ++static struct drm_connector *vc4_dsi_connector_init(struct drm_device *dev, ++ struct vc4_dsi *dsi) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_dsi_connector *dsi_connector; ++ int ret = 0; ++ ++ dsi_connector = devm_kzalloc(dev->dev, sizeof(*dsi_connector), ++ GFP_KERNEL); ++ if (!dsi_connector) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ connector = &dsi_connector->base; ++ ++ dsi_connector->dsi = dsi; ++ ++ drm_connector_init(dev, connector, &vc4_dsi_connector_funcs, ++ DRM_MODE_CONNECTOR_DSI); ++ drm_connector_helper_add(connector, &vc4_dsi_connector_helper_funcs); ++ ++ connector->polled = 0; ++ connector->interlace_allowed = 0; ++ connector->doublescan_allowed = 0; ++ ++ drm_mode_connector_attach_encoder(connector, dsi->encoder); ++ ++ return connector; ++ ++fail: ++ if (connector) ++ vc4_dsi_connector_destroy(connector); ++ ++ return ERR_PTR(ret); ++} ++ ++static void vc4_dsi_encoder_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++} ++ ++static const struct drm_encoder_funcs vc4_dsi_encoder_funcs = { ++ .destroy = vc4_dsi_encoder_destroy, ++}; ++ ++static void vc4_dsi_latch_ulps(struct vc4_dsi *dsi, bool latch) ++{ ++ u32 afec0 = DSI_PORT_READ(PHY_AFEC0); ++ ++ if (latch) ++ afec0 |= DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); ++ else ++ afec0 &= ~DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS); ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++} ++ ++/* Enters or exits Ultra Low Power State. */ ++static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) ++{ ++ bool continuous = dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS; ++ u32 phyc_ulps = ((continuous ? DSI_PORT_BIT(PHYC_CLANE_ULPS) : 0) | ++ DSI_PHYC_DLANE0_ULPS | ++ (dsi->lanes > 1 ? DSI_PHYC_DLANE1_ULPS : 0) | ++ (dsi->lanes > 2 ? DSI_PHYC_DLANE2_ULPS : 0) | ++ (dsi->lanes > 3 ? DSI_PHYC_DLANE3_ULPS : 0)); ++ u32 stat_ulps = ((continuous ? DSI1_STAT_PHY_CLOCK_ULPS : 0) | ++ DSI1_STAT_PHY_D0_ULPS | ++ (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_ULPS : 0) | ++ (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_ULPS : 0) | ++ (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_ULPS : 0)); ++ u32 stat_stop = ((continuous ? DSI1_STAT_PHY_CLOCK_STOP : 0) | ++ DSI1_STAT_PHY_D0_STOP | ++ (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) | ++ (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) | ++ (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0)); ++ int ret; ++ ++ DSI_PORT_WRITE(STAT, stat_ulps); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) | phyc_ulps); ++ ret = wait_for((DSI_PORT_READ(STAT) & stat_ulps) == stat_ulps, 200); ++ if (ret) { ++ dev_warn(&dsi->pdev->dev, ++ "Timeout waiting for DSI ULPS entry: STAT 0x%08x", ++ DSI_PORT_READ(STAT)); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ vc4_dsi_latch_ulps(dsi, false); ++ return; ++ } ++ ++ /* The DSI module can't be disabled while the module is ++ * generating ULPS state. So, to be able to disable the ++ * module, we have the AFE latch the ULPS state and continue ++ * on to having the module enter STOP. ++ */ ++ vc4_dsi_latch_ulps(dsi, ulps); ++ ++ DSI_PORT_WRITE(STAT, stat_stop); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200); ++ if (ret) { ++ dev_warn(&dsi->pdev->dev, ++ "Timeout waiting for DSI STOP entry: STAT 0x%08x", ++ DSI_PORT_READ(STAT)); ++ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); ++ return; ++ } ++} ++ ++static u32 ++dsi_hs_timing(u32 ui_ns, u32 ns, u32 ui) ++{ ++ /* The HS timings have to be rounded up to a multiple of 8 ++ * because we're using the byte clock. ++ */ ++ return roundup(ui + DIV_ROUND_UP(ns, ui_ns), 8); ++} ++ ++/* ESC always runs at 100Mhz. */ ++#define ESC_TIME_NS 10 ++ ++static u32 ++dsi_esc_timing(u32 ns) ++{ ++ return DIV_ROUND_UP(ns, ESC_TIME_NS); ++} ++ ++static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); ++ struct vc4_dsi *dsi = vc4_encoder->dsi; ++ struct device *dev = &dsi->pdev->dev; ++ ++ drm_panel_disable(dsi->panel); ++ ++ vc4_dsi_ulps(dsi, true); ++ ++ drm_panel_unprepare(dsi->panel); ++ ++ clk_disable_unprepare(dsi->pll_phy_clock); ++ clk_disable_unprepare(dsi->escape_clock); ++ clk_disable_unprepare(dsi->pixel_clock); ++ ++ pm_runtime_put(dev); ++} ++ ++static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct drm_display_mode *mode = &encoder->crtc->mode; ++ struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); ++ struct vc4_dsi *dsi = vc4_encoder->dsi; ++ struct device *dev = &dsi->pdev->dev; ++ u32 format = 0, divider = 0; ++ bool debug_dump_regs = false; ++ unsigned long hs_clock; ++ u32 ui_ns; ++ /* Minimum LP state duration in escape clock cycles. */ ++ u32 lpx = dsi_esc_timing(60); ++ unsigned long pixel_clock_hz = mode->clock * 1000; ++ unsigned long dsip_clock; ++ unsigned long phy_clock; ++ int ret; ++ ++ ret = pm_runtime_get_sync(dev); ++ if (ret) { ++ DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port); ++ return; ++ } ++ ++ ret = drm_panel_prepare(dsi->panel); ++ if (ret) { ++ DRM_ERROR("Panel failed to prepare\n"); ++ return; ++ } ++ ++ if (debug_dump_regs) { ++ DRM_INFO("DSI regs before:\n"); ++ vc4_dsi_dump_regs(dsi); ++ } ++ ++ switch (dsi->format) { ++ case MIPI_DSI_FMT_RGB888: ++ format = DSI_PFORMAT_RGB888; ++ divider = 24 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB666: ++ format = DSI_PFORMAT_RGB666; ++ divider = 24 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ format = DSI_PFORMAT_RGB666_PACKED; ++ divider = 18 / dsi->lanes; ++ break; ++ case MIPI_DSI_FMT_RGB565: ++ format = DSI_PFORMAT_RGB565; ++ divider = 16 / dsi->lanes; ++ break; ++ } ++ ++ phy_clock = pixel_clock_hz * divider; ++ ret = clk_set_rate(dsi->pll_phy_clock, phy_clock); ++ if (ret) { ++ dev_err(&dsi->pdev->dev, ++ "Failed to set phy clock to %ld: %d\n", phy_clock, ret); ++ } ++ ++ /* Reset the DSI and all its fifos. */ ++ DSI_PORT_WRITE(CTRL, ++ DSI_CTRL_SOFT_RESET_CFG | ++ DSI_PORT_BIT(CTRL_RESET_FIFOS)); ++ ++ DSI_PORT_WRITE(CTRL, ++ DSI_CTRL_HSDT_EOT_DISABLE | ++ DSI_CTRL_RX_LPDT_EOT_DISABLE); ++ ++ /* Clear all stat bits so we see what has happened during enable. */ ++ DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); ++ ++ /* Set AFE CTR00/CTR1 to release powerdown of analog. */ ++ if (dsi->port == 0) { ++ u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | ++ VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); ++ ++ if (dsi->lanes < 2) ++ afec0 |= DSI0_PHY_AFEC0_PD_DLANE1; ++ ++ if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) ++ afec0 |= DSI0_PHY_AFEC0_RESET; ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++ ++ DSI_PORT_WRITE(PHY_AFEC1, ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE1) | ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE0) | ++ VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_CLANE)); ++ } else { ++ u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | ++ VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_CLANE) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE0) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE1) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE2) | ++ VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE3)); ++ ++ if (dsi->lanes < 4) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE3; ++ if (dsi->lanes < 3) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE2; ++ if (dsi->lanes < 2) ++ afec0 |= DSI1_PHY_AFEC0_PD_DLANE1; ++ ++ afec0 |= DSI1_PHY_AFEC0_RESET; ++ ++ DSI_PORT_WRITE(PHY_AFEC0, afec0); ++ ++ DSI_PORT_WRITE(PHY_AFEC1, 0); ++ ++ /* AFEC reset hold time */ ++ mdelay(1); ++ } ++ ++ ret = clk_prepare_enable(dsi->escape_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(dsi->pll_phy_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret); ++ return; ++ } ++ ++ hs_clock = clk_get_rate(dsi->pll_phy_clock); ++ ++ /* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate, ++ * not the pixel clock rate. DSIxP take from the APHY's byte, ++ * DDR2, or DDR4 clock (we use byte) and feed into the PV at ++ * that rate. Separately, a value derived from PIX_CLK_DIV ++ * and HS_CLKC is fed into the PV to divide down to the actual ++ * pixel clock for pushing pixels into DSI. ++ */ ++ dsip_clock = phy_clock / 8; ++ ret = clk_set_rate(dsi->pixel_clock, dsip_clock); ++ if (ret) { ++ dev_err(dev, "Failed to set pixel clock to %ldHz: %d\n", ++ dsip_clock, ret); ++ } ++ ++ ret = clk_prepare_enable(dsi->pixel_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on DSI pixel clock: %d\n", ret); ++ return; ++ } ++ ++ /* How many ns one DSI unit interval is. Note that the clock ++ * is DDR, so there's an extra divide by 2. ++ */ ++ ui_ns = DIV_ROUND_UP(500000000, hs_clock); ++ ++ DSI_PORT_WRITE(HS_CLT0, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 262, 0), ++ DSI_HS_CLT0_CZERO) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 0, 8), ++ DSI_HS_CLT0_CPRE) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 38, 0), ++ DSI_HS_CLT0_CPREP)); ++ ++ DSI_PORT_WRITE(HS_CLT1, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 0), ++ DSI_HS_CLT1_CTRAIL) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 52), ++ DSI_HS_CLT1_CPOST)); ++ ++ DSI_PORT_WRITE(HS_CLT2, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000000, 0), ++ DSI_HS_CLT2_WUP)); ++ ++ DSI_PORT_WRITE(HS_DLT3, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 100, 0), ++ DSI_HS_DLT3_EXIT) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 105, 6), ++ DSI_HS_DLT3_ZERO) | ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, 40, 4), ++ DSI_HS_DLT3_PRE)); ++ ++ DSI_PORT_WRITE(HS_DLT4, ++ VC4_SET_FIELD(dsi_hs_timing(ui_ns, lpx * ESC_TIME_NS, 0), ++ DSI_HS_DLT4_LPX) | ++ VC4_SET_FIELD(max(dsi_hs_timing(ui_ns, 0, 8), ++ dsi_hs_timing(ui_ns, 60, 4)), ++ DSI_HS_DLT4_TRAIL) | ++ VC4_SET_FIELD(0, DSI_HS_DLT4_ANLAT)); ++ ++ DSI_PORT_WRITE(HS_DLT5, VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000, 5000), ++ DSI_HS_DLT5_INIT)); ++ ++ DSI_PORT_WRITE(HS_DLT6, ++ VC4_SET_FIELD(lpx * 5, DSI_HS_DLT6_TA_GET) | ++ VC4_SET_FIELD(lpx, DSI_HS_DLT6_TA_SURE) | ++ VC4_SET_FIELD(lpx * 4, DSI_HS_DLT6_TA_GO) | ++ VC4_SET_FIELD(lpx, DSI_HS_DLT6_LP_LPX)); ++ ++ DSI_PORT_WRITE(HS_DLT7, ++ VC4_SET_FIELD(dsi_esc_timing(1000000), ++ DSI_HS_DLT7_LP_WUP)); ++ ++ DSI_PORT_WRITE(PHYC, ++ DSI_PHYC_DLANE0_ENABLE | ++ (dsi->lanes >= 2 ? DSI_PHYC_DLANE1_ENABLE : 0) | ++ (dsi->lanes >= 3 ? DSI_PHYC_DLANE2_ENABLE : 0) | ++ (dsi->lanes >= 4 ? DSI_PHYC_DLANE3_ENABLE : 0) | ++ DSI_PORT_BIT(PHYC_CLANE_ENABLE) | ++ ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? ++ 0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) | ++ (dsi->port == 0 ? ++ VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) : ++ VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); ++ ++ DSI_PORT_WRITE(CTRL, ++ DSI_PORT_READ(CTRL) | ++ DSI_CTRL_CAL_BYTE); ++ ++ /* HS timeout in HS clock cycles: disabled. */ ++ DSI_PORT_WRITE(HSTX_TO_CNT, 0); ++ /* LP receive timeout in HS clocks. */ ++ DSI_PORT_WRITE(LPRX_TO_CNT, 0xffffff); ++ /* Bus turnaround timeout */ ++ DSI_PORT_WRITE(TA_TO_CNT, 100000); ++ /* Display reset sequence timeout */ ++ DSI_PORT_WRITE(PR_TO_CNT, 100000); ++ ++ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { ++ DSI_PORT_WRITE(DISP0_CTRL, ++ VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) | ++ VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) | ++ VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, ++ DSI_DISP0_LP_STOP_CTRL) | ++ DSI_DISP0_ST_END | ++ DSI_DISP0_ENABLE); ++ } else { ++ DSI_PORT_WRITE(DISP0_CTRL, ++ DSI_DISP0_COMMAND_MODE | ++ DSI_DISP0_ENABLE); ++ } ++ ++ /* Set up DISP1 for transferring long command payloads through ++ * the pixfifo. ++ */ ++ DSI_PORT_WRITE(DISP1_CTRL, ++ VC4_SET_FIELD(DSI_DISP1_PFORMAT_32BIT_LE, ++ DSI_DISP1_PFORMAT) | ++ DSI_DISP1_ENABLE); ++ ++ /* Ungate the block. */ ++ if (dsi->port == 0) ++ DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); ++ else ++ DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); ++ ++ /* Bring AFE out of reset. */ ++ if (dsi->port == 0) { ++ } else { ++ DSI_PORT_WRITE(PHY_AFEC0, ++ DSI_PORT_READ(PHY_AFEC0) & ++ ~DSI1_PHY_AFEC0_RESET); ++ } ++ ++ vc4_dsi_ulps(dsi, false); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("DSI regs after:\n"); ++ vc4_dsi_dump_regs(dsi); ++ } ++ ++ ret = drm_panel_enable(dsi->panel); ++ if (ret) { ++ DRM_ERROR("Panel failed to enable\n"); ++ drm_panel_unprepare(dsi->panel); ++ return; ++ } ++} ++ ++static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, ++ const struct mipi_dsi_msg *msg) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ struct mipi_dsi_packet packet; ++ u32 pkth = 0, pktc = 0; ++ int i, ret; ++ bool is_long = mipi_dsi_packet_format_is_long(msg->type); ++ u32 cmd_fifo_len = 0, pix_fifo_len = 0; ++ ++ mipi_dsi_create_packet(&packet, msg); ++ ++ pkth |= VC4_SET_FIELD(packet.header[0], DSI_TXPKT1H_BC_DT); ++ pkth |= VC4_SET_FIELD(packet.header[1] | ++ (packet.header[2] << 8), ++ DSI_TXPKT1H_BC_PARAM); ++ if (is_long) { ++ /* Divide data across the various FIFOs we have available. ++ * The command FIFO takes byte-oriented data, but is of ++ * limited size. The pixel FIFO (never actually used for ++ * pixel data in reality) is word oriented, and substantially ++ * larger. So, we use the pixel FIFO for most of the data, ++ * sending the residual bytes in the command FIFO at the start. ++ * ++ * With this arrangement, the command FIFO will never get full. ++ */ ++ if (packet.payload_length <= 16) { ++ cmd_fifo_len = packet.payload_length; ++ pix_fifo_len = 0; ++ } else { ++ cmd_fifo_len = (packet.payload_length % ++ DSI_PIX_FIFO_WIDTH); ++ pix_fifo_len = ((packet.payload_length - cmd_fifo_len) / ++ DSI_PIX_FIFO_WIDTH); ++ } ++ ++ WARN_ON_ONCE(pix_fifo_len >= DSI_PIX_FIFO_DEPTH); ++ ++ pkth |= VC4_SET_FIELD(cmd_fifo_len, DSI_TXPKT1H_BC_CMDFIFO); ++ } ++ ++ if (msg->rx_len) { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_RX, ++ DSI_TXPKT1C_CMD_CTRL); ++ } else { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_TX, ++ DSI_TXPKT1C_CMD_CTRL); ++ } ++ ++ for (i = 0; i < cmd_fifo_len; i++) ++ DSI_PORT_WRITE(TXPKT_CMD_FIFO, packet.payload[i]); ++ for (i = 0; i < pix_fifo_len; i++) { ++ const u8 *pix = packet.payload + cmd_fifo_len + i * 4; ++ ++ DSI_PORT_WRITE(TXPKT_PIX_FIFO, ++ pix[0] | ++ pix[1] << 8 | ++ pix[2] << 16 | ++ pix[3] << 24); ++ } ++ ++ if (msg->flags & MIPI_DSI_MSG_USE_LPM) ++ pktc |= DSI_TXPKT1C_CMD_MODE_LP; ++ if (is_long) ++ pktc |= DSI_TXPKT1C_CMD_TYPE_LONG; ++ ++ /* Send one copy of the packet. Larger repeats are used for pixel ++ * data in command mode. ++ */ ++ pktc |= VC4_SET_FIELD(1, DSI_TXPKT1C_CMD_REPEAT); ++ ++ pktc |= DSI_TXPKT1C_CMD_EN; ++ if (pix_fifo_len) { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SECONDARY, ++ DSI_TXPKT1C_DISPLAY_NO); ++ } else { ++ pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SHORT, ++ DSI_TXPKT1C_DISPLAY_NO); ++ } ++ ++ /* Enable the appropriate interrupt for the transfer completion. */ ++ dsi->xfer_result = 0; ++ reinit_completion(&dsi->xfer_completion); ++ DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF); ++ if (msg->rx_len) { ++ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | ++ DSI1_INT_PHY_DIR_RTF)); ++ } else { ++ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED | ++ DSI1_INT_TXPKT1_DONE)); ++ } ++ ++ /* Send the packet. */ ++ DSI_PORT_WRITE(TXPKT1H, pkth); ++ DSI_PORT_WRITE(TXPKT1C, pktc); ++ ++ if (!wait_for_completion_timeout(&dsi->xfer_completion, ++ msecs_to_jiffies(1000))) { ++ dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); ++ dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", ++ DSI_PORT_READ(INT_STAT)); ++ ret = -ETIMEDOUT; ++ } else { ++ ret = dsi->xfer_result; ++ } ++ ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ ++ if (ret) ++ goto reset_fifo_and_return; ++ ++ if (ret == 0 && msg->rx_len) { ++ u32 rxpkt1h = DSI_PORT_READ(RXPKT1H); ++ u8 *msg_rx = msg->rx_buf; ++ ++ if (rxpkt1h & DSI_RXPKT1H_PKT_TYPE_LONG) { ++ u32 rxlen = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_BC_PARAM); ++ ++ if (rxlen != msg->rx_len) { ++ DRM_ERROR("DSI returned %db, expecting %db\n", ++ rxlen, (int)msg->rx_len); ++ ret = -ENXIO; ++ goto reset_fifo_and_return; ++ } ++ ++ for (i = 0; i < msg->rx_len; i++) ++ msg_rx[i] = DSI_READ(DSI1_RXPKT_FIFO); ++ } else { ++ /* FINISHME: Handle AWER */ ++ ++ msg_rx[0] = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_SHORT_0); ++ if (msg->rx_len > 1) { ++ msg_rx[1] = VC4_GET_FIELD(rxpkt1h, ++ DSI_RXPKT1H_SHORT_1); ++ } ++ } ++ } ++ ++ return ret; ++ ++reset_fifo_and_return: ++ DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); ++ ++ DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); ++ udelay(1); ++ DSI_PORT_WRITE(CTRL, ++ DSI_PORT_READ(CTRL) | ++ DSI_PORT_BIT(CTRL_RESET_FIFOS)); ++ ++ DSI_PORT_WRITE(TXPKT1C, 0); ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ return ret; ++} ++ ++static int vc4_dsi_host_attach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ int ret = 0; ++ ++ dsi->lanes = device->lanes; ++ dsi->channel = device->channel; ++ dsi->format = device->format; ++ dsi->mode_flags = device->mode_flags; ++ ++ if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { ++ dev_err(&dsi->pdev->dev, ++ "Only VIDEO mode panels supported currently.\n"); ++ return 0; ++ } ++ ++ dsi->panel = of_drm_find_panel(device->dev.of_node); ++ if (!dsi->panel) ++ return 0; ++ ++ ret = drm_panel_attach(dsi->panel, dsi->connector); ++ if (ret != 0) ++ return ret; ++ ++ drm_helper_hpd_irq_event(dsi->connector->dev); ++ ++ return 0; ++} ++ ++static int vc4_dsi_host_detach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ ++ if (dsi->panel) { ++ int ret = drm_panel_detach(dsi->panel); ++ ++ if (ret) ++ return ret; ++ ++ dsi->panel = NULL; ++ ++ drm_helper_hpd_irq_event(dsi->connector->dev); ++ } ++ ++ return 0; ++} ++ ++static const struct mipi_dsi_host_ops vc4_dsi_host_ops = { ++ .attach = vc4_dsi_host_attach, ++ .detach = vc4_dsi_host_detach, ++ .transfer = vc4_dsi_host_transfer, ++}; ++ ++static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { ++ .disable = vc4_dsi_encoder_disable, ++ .enable = vc4_dsi_encoder_enable, ++}; ++ ++static const struct of_device_id vc4_dsi_dt_match[] = { ++ { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 }, ++ {} ++}; ++ ++static void dsi_handle_error(struct vc4_dsi *dsi, ++ irqreturn_t *ret, u32 stat, u32 bit, ++ const char *type) ++{ ++ if (!(stat & bit)) ++ return; ++ ++ DRM_ERROR("DSI%d: %s error\n", dsi->port, type); ++ *ret = IRQ_HANDLED; ++} ++ ++static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) ++{ ++ struct vc4_dsi *dsi = data; ++ u32 stat = DSI_PORT_READ(INT_STAT); ++ irqreturn_t ret = IRQ_NONE; ++ ++ DSI_PORT_WRITE(INT_STAT, stat); ++ ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_SYNC_ESC, "LPDT sync"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONTROL, "data lane 0 sequence"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONT_LP0, "LP0 contention"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_ERR_CONT_LP1, "LP1 contention"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_HSTX_TO, "HSTX timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_LPRX_TO, "LPRX timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_TA_TO, "turnaround timeout"); ++ dsi_handle_error(dsi, &ret, stat, ++ DSI1_INT_PR_TO, "peripheral reset timeout"); ++ ++ if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) { ++ complete(&dsi->xfer_completion); ++ ret = IRQ_HANDLED; ++ } else if (stat & DSI1_INT_HSTX_TO) { ++ complete(&dsi->xfer_completion); ++ dsi->xfer_result = -ETIMEDOUT; ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++/** ++ * Exposes clocks generated by the analog PHY that are consumed by ++ * CPRMAN (clk-bcm2835.c). ++ */ ++static int ++vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) ++{ ++ struct device *dev = &dsi->pdev->dev; ++ const char *parent_name = __clk_get_name(dsi->pll_phy_clock); ++ static const struct { ++ const char *dsi0_name, *dsi1_name; ++ int div; ++ } phy_clocks[] = { ++ { "dsi0_byte", "dsi1_byte", 8 }, ++ { "dsi0_ddr2", "dsi1_ddr2", 4 }, ++ { "dsi0_ddr", "dsi1_ddr", 2 }, ++ }; ++ int i; ++ ++ dsi->clk_onecell.clk_num = ARRAY_SIZE(phy_clocks); ++ dsi->clk_onecell.clks = devm_kcalloc(dev, ++ dsi->clk_onecell.clk_num, ++ sizeof(*dsi->clk_onecell.clks), ++ GFP_KERNEL); ++ if (!dsi->clk_onecell.clks) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { ++ struct clk_fixed_factor *fix = &dsi->phy_clocks[i]; ++ struct clk_init_data init; ++ struct clk *clk; ++ ++ /* We just use core fixed factor clock ops for the PHY ++ * clocks. The clocks are actually gated by the ++ * PHY_AFEC0_DDRCLK_EN bits, which we should be ++ * setting if we use the DDR/DDR2 clocks. However, ++ * vc4_dsi_encoder_enable() is setting up both AFEC0, ++ * setting both our parent DSI PLL's rate and this ++ * clock's rate, so it knows if DDR/DDR2 are going to ++ * be used and could enable the gates itself. ++ */ ++ fix->mult = 1; ++ fix->div = phy_clocks[i].div; ++ fix->hw.init = &init; ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &parent_name; ++ init.num_parents = 1; ++ if (dsi->port == 1) ++ init.name = phy_clocks[i].dsi1_name; ++ else ++ init.name = phy_clocks[i].dsi0_name; ++ init.ops = &clk_fixed_factor_ops; ++ init.flags = CLK_IS_BASIC; ++ ++ clk = devm_clk_register(dev, &fix->hw); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ dsi->clk_onecell.clks[i] = clk; ++ } ++ ++ return of_clk_add_provider(dev->of_node, ++ of_clk_src_onecell_get, ++ &dsi->clk_onecell); ++} ++ ++static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_dsi *dsi; ++ struct vc4_dsi_encoder *vc4_dsi_encoder; ++ const struct of_device_id *match; ++ dma_cap_mask_t dma_mask; ++ int ret; ++ ++ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); ++ if (!dsi) ++ return -ENOMEM; ++ ++ match = of_match_device(vc4_dsi_dt_match, dev); ++ if (!match) ++ return -ENODEV; ++ ++ dsi->port = (uintptr_t)match->data; ++ ++ vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), ++ GFP_KERNEL); ++ if (!vc4_dsi_encoder) ++ return -ENOMEM; ++ vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1; ++ vc4_dsi_encoder->dsi = dsi; ++ dsi->encoder = &vc4_dsi_encoder->base.base; ++ ++ dsi->pdev = pdev; ++ dsi->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(dsi->regs)) ++ return PTR_ERR(dsi->regs); ++ ++ if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { ++ dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", ++ DSI_PORT_READ(ID), DSI_ID_VALUE); ++ return -ENODEV; ++ } ++ ++ /* DSI1 has a broken AXI slave that doesn't respond to writes ++ * from the ARM. It does handle writes from the DMA engine, ++ * so set up a channel for talking to it. ++ */ ++ if (dsi->port == 1) { ++ dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, ++ &dsi->reg_dma_paddr, ++ GFP_KERNEL); ++ if (!dsi->reg_dma_mem) { ++ DRM_ERROR("Failed to get DMA memory\n"); ++ return -ENOMEM; ++ } ++ ++ dma_cap_zero(dma_mask); ++ dma_cap_set(DMA_MEMCPY, dma_mask); ++ dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask); ++ if (IS_ERR(dsi->reg_dma_chan)) { ++ ret = PTR_ERR(dsi->reg_dma_chan); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Failed to get DMA channel: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Get the physical address of the device's registers. The ++ * struct resource for the regs gives us the bus address ++ * instead. ++ */ ++ dsi->reg_paddr = be32_to_cpup(of_get_address(dev->of_node, ++ 0, NULL, NULL)); ++ } ++ ++ init_completion(&dsi->xfer_completion); ++ /* At startup enable error-reporting interrupts and nothing else. */ ++ DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED); ++ /* Clear any existing interrupt state. */ ++ DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT)); ++ ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_dsi_irq_handler, 0, "vc4 dsi", dsi); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get interrupt: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->escape_clock = devm_clk_get(dev, "escape"); ++ if (IS_ERR(dsi->escape_clock)) { ++ ret = PTR_ERR(dsi->escape_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get escape clock: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->pll_phy_clock = devm_clk_get(dev, "phy"); ++ if (IS_ERR(dsi->pll_phy_clock)) { ++ ret = PTR_ERR(dsi->pll_phy_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get phy clock: %d\n", ret); ++ return ret; ++ } ++ ++ dsi->pixel_clock = devm_clk_get(dev, "pixel"); ++ if (IS_ERR(dsi->pixel_clock)) { ++ ret = PTR_ERR(dsi->pixel_clock); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get pixel clock: %d\n", ret); ++ return ret; ++ } ++ ++ /* The esc clock rate is supposed to always be 100Mhz. */ ++ ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); ++ if (ret) { ++ dev_err(dev, "Failed to set esc clock: %d\n", ret); ++ return ret; ++ } ++ ++ ret = vc4_dsi_init_phy_clocks(dsi); ++ if (ret) ++ return ret; ++ ++ if (dsi->port == 1) ++ vc4->dsi1 = dsi; ++ ++ drm_encoder_init(drm, dsi->encoder, &vc4_dsi_encoder_funcs, ++ DRM_MODE_ENCODER_DSI, NULL); ++ drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); ++ ++ dsi->connector = vc4_dsi_connector_init(drm, dsi); ++ if (IS_ERR(dsi->connector)) { ++ ret = PTR_ERR(dsi->connector); ++ goto err_destroy_encoder; ++ } ++ ++ dsi->dsi_host.ops = &vc4_dsi_host_ops; ++ dsi->dsi_host.dev = dev; ++ ++ mipi_dsi_host_register(&dsi->dsi_host); ++ ++ dev_set_drvdata(dev, dsi); ++ ++ pm_runtime_enable(dev); ++ ++ return 0; ++ ++err_destroy_encoder: ++ vc4_dsi_encoder_destroy(dsi->encoder); ++ ++ return ret; ++} ++ ++static void vc4_dsi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_dsi *dsi = dev_get_drvdata(dev); ++ ++ pm_runtime_disable(dev); ++ ++ vc4_dsi_connector_destroy(dsi->connector); ++ vc4_dsi_encoder_destroy(dsi->encoder); ++ ++ mipi_dsi_host_unregister(&dsi->dsi_host); ++ ++ clk_disable_unprepare(dsi->pll_phy_clock); ++ clk_disable_unprepare(dsi->escape_clock); ++ ++ if (dsi->port == 1) ++ vc4->dsi1 = NULL; ++} ++ ++static const struct component_ops vc4_dsi_ops = { ++ .bind = vc4_dsi_bind, ++ .unbind = vc4_dsi_unbind, ++}; ++ ++static int vc4_dsi_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_dsi_ops); ++} ++ ++static int vc4_dsi_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_dsi_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_dsi_driver = { ++ .probe = vc4_dsi_dev_probe, ++ .remove = vc4_dsi_dev_remove, ++ .driver = { ++ .name = "vc4_dsi", ++ .of_match_table = vc4_dsi_dt_match, ++ }, ++}; + +From 58727f518ad71b875066c26f68e82c3c521f1337 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:12 +0100 +Subject: [PATCH 170/187] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi + +Add the VEC (Video EnCoder) node definition in bcm283x.dtsi. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit b899c45208d6f204a6da9a1132577993eeecf0fb) +--- + arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 41776b97b4b6b1c053d07fd357fac4ba4787ac53..d3cc586661f903e67a840189c0446aa80e16a44e 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -310,6 +310,14 @@ + status = "disabled"; + }; + ++ vec: vec@7e806000 { ++ compatible = "brcm,bcm2835-vec"; ++ reg = <0x7e806000 0x1000>; ++ clocks = <&clocks BCM2835_CLOCK_VEC>; ++ interrupts = <2 27>; ++ status = "disabled"; ++ }; ++ + pixelvalve@7e807000 { + compatible = "brcm,bcm2835-pixelvalve2"; + reg = <0x7e807000 0x100>; + +From 8142ae28587b1f8ec8ea0297a6e51445642bbba6 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Fri, 2 Dec 2016 14:48:13 +0100 +Subject: [PATCH 171/187] ARM: dts: bcm283x: Enable the VEC IP on all + RaspberryPi boards + +Enable the VEC IP on all RaspberryPi boards. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit 5ab1a37c6027c114a87a1ae32cfc5ef303d643c5) +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi +index 365648898f3acc4f82dc6cb58e4bbebbe249be94..d4577a51e678cb600b475d3d3395ca4e67593cf6 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -92,3 +92,8 @@ + &dsi1 { + power-domains = <&power RPI_POWER_DOMAIN_DSI1>; + }; ++ ++&vec { ++ power-domains = <&power RPI_POWER_DOMAIN_VEC>; ++ status = "okay"; ++}; + +From d04e3ecbc1e8605d4a165b25abdeb7a6dec4f541 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 23 Jan 2017 11:41:54 -0800 +Subject: [PATCH 172/187] BCM270X: Disable VEC unless vc4-kms-v3d is present. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708-rpi.dtsi | 4 ++++ + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 7 +++++++ + 2 files changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi.dtsi b/arch/arm/boot/dts/bcm2708-rpi.dtsi +index 46cf8602c3b96e477b05b57dbfe5e349930c9d9a..1f5f40b9c7cbd574f12a42d8c3fa5344138d155e 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi +@@ -107,3 +107,7 @@ + &usb { + power-domains = <&power RPI_POWER_DOMAIN_USB>; + }; ++ ++&vec { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index f25cd9a3936861920b0d518ff2d773ee467e2f49..a8ef8c9051668a7477dea30aa262568c8e7f221c 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -148,6 +148,13 @@ + }; + }; + ++ fragment@18 { ++ target = <&vec>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; + +From 8491a96b1dcd7a0e838560cd1cbf5eb28866ddf2 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 1 Feb 2017 17:09:18 -0800 +Subject: [PATCH 173/187] drm/vc4: Name the primary and cursor planes in fkms. + +This makes debugging nicer, compared to trying to remember what the +IDs are. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index d18a1dae51a2275846c9826b5bf1ba57ae97b55c..e49ce68b607a7ffc2329e3235362f3bc21ed5cbb 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -267,7 +267,7 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, + primary ? &xrgb8888 : &argb8888, 1, +- type, NULL); ++ type, primary ? "primary" : "cursor"); + + if (type == DRM_PLANE_TYPE_PRIMARY) { + vc4_plane->fbinfo = + +From 5f1bdfa494cedc463f8fb2666986ff175afa9ec4 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 1 Feb 2017 17:10:09 -0800 +Subject: [PATCH 174/187] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of + fkms. + +Trying to debug weston on fkms involved figuring out what calls I was +making to the firmware. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index e49ce68b607a7ffc2329e3235362f3bc21ed5cbb..dbf065677202fbebf8e3a0cffbe880aa42daef3f 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -102,6 +102,11 @@ static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank) + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + + u32 packet = blank; ++ ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s", ++ plane->base.id, plane->name, ++ blank ? "blank" : "unblank"); ++ + return rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_FRAMEBUFFER_BLANK, + &packet, sizeof(packet)); +@@ -149,6 +154,16 @@ static void vc4_primary_plane_atomic_update(struct drm_plane *plane, + WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); + } + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n", ++ plane->base.id, plane->name, ++ state->crtc_w, ++ state->crtc_h, ++ bpp, ++ state->crtc_x, ++ state->crtc_y, ++ bo->paddr + fb->offsets[0], ++ fb->pitches[0]); ++ + ret = rpi_firmware_transaction(vc4->firmware, + RPI_FIRMWARE_CHAN_FB, + vc4_plane->fbinfo_bus_addr); +@@ -178,6 +193,15 @@ static void vc4_cursor_plane_atomic_update(struct drm_plane *plane, + WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); + WARN_ON_ONCE(fb->bits_per_pixel != 32); + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)", ++ plane->base.id, plane->name, ++ state->crtc_w, ++ state->crtc_h, ++ state->crtc_x, ++ state->crtc_y, ++ bo->paddr + fb->offsets[0], ++ fb->pitches[0]); ++ + ret = rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_SET_CURSOR_STATE, + &packet_state, +@@ -200,6 +224,8 @@ static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane, + u32 packet_state[] = { false, 0, 0, 0 }; + int ret; + ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name); ++ + ret = rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_SET_CURSOR_STATE, + &packet_state, + +From d464fabeba2314b595ee9ff7fde7f65d03b747ca Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 Feb 2017 09:42:18 -0800 +Subject: [PATCH 175/187] drm/vc4: Fix sending of page flip completion events + in FKMS mode. + +In the rewrite of vc4_crtc.c for fkms, I dropped the part of the +CRTC's atomic flush handler that moved the completion event from the +proposed atomic state change to the CRTC's current state. That meant +that when full screen pageflipping happened (glxgears -fullscreen in +X, compton, por weston), the app would end up blocked firever waiting +to draw its next frame. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +index dbf065677202fbebf8e3a0cffbe880aa42daef3f..da818a207bfa639b8cea48d94bcf4566f97db816 100644 +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -338,6 +338,21 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, + static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) + { ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ ++ if (crtc->state->event) { ++ unsigned long flags; ++ ++ crtc->state->event->pipe = drm_crtc_index(crtc); ++ ++ WARN_ON(drm_crtc_vblank_get(crtc) != 0); ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ vc4_crtc->event = crtc->state->event; ++ crtc->state->event = NULL; ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } + } + + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) + +From 7e9e22730f563aabfd467d2fda9b89be3b0fd496 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 8 Feb 2017 15:00:54 -0800 +Subject: [PATCH 176/187] drm/vc4: Fulfill user BO creation requests from the + kernel BO cache. + +The from_cache flag was actually "the BO is invisible to userspace", +so we can repurpose to just zero out a cached BO and return it to +userspace. + +Improves wall time for a loop of 5 glsl-algebraic-add-add-1 by +-1.44989% +/- 0.862891% (n=28, 1 outlier removed from each that +appeared to be other system noise) + +Note that there's an intel-gpu-tools test to check for the proper +zeroing behavior here, which we continue to pass. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_bo.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 3f6704cf6608d7be47637c6aa585de087b7f74ee..5ec14f25625dde6fd61e10415092fa25527cc151 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -208,21 +208,22 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) + } + + struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, +- bool from_cache) ++ bool allow_unzeroed) + { + size_t size = roundup(unaligned_size, PAGE_SIZE); + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_gem_cma_object *cma_obj; ++ struct vc4_bo *bo; + + if (size == 0) + return ERR_PTR(-EINVAL); + + /* First, try to get a vc4_bo from the kernel BO cache. */ +- if (from_cache) { +- struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size); +- +- if (bo) +- return bo; ++ bo = vc4_bo_get_from_cache(dev, size); ++ if (bo) { ++ if (!allow_unzeroed) ++ memset(bo->base.vaddr, 0, bo->base.base.size); ++ return bo; + } + + cma_obj = drm_gem_cma_create(dev, size); + +From 8c1a0bfae9ef4725fb4e794cd40eeb6a0c45cbe6 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 9 Feb 2017 09:23:34 -0800 +Subject: [PATCH 177/187] drm/vc4: Fix OOPSes from trying to cache a partially + constructed BO. + +If a CMA allocation failed, the partially constructed BO would be +unreferenced through the normal path, and we might choose to put it in +the BO cache. If we then reused it before it expired from the cache, +the kernel would OOPS. + +Signed-off-by: Eric Anholt +Fixes: c826a6e10644 ("drm/vc4: Add a BO cache.") +--- + drivers/gpu/drm/vc4/vc4_bo.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 5ec14f25625dde6fd61e10415092fa25527cc151..fd83a28076564b9ea5cf0f2ba29b884ee3c5af43 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -314,6 +314,14 @@ void vc4_free_object(struct drm_gem_object *gem_bo) + goto out; + } + ++ /* If this object was partially constructed but CMA allocation ++ * had failed, just free it. ++ */ ++ if (!bo->base.vaddr) { ++ vc4_bo_destroy(bo); ++ goto out; ++ } ++ + cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size); + if (!cache_list) { + vc4_bo_destroy(bo); + +From 0111b8ac9e24f072185d6789f16fe96687b599bd Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 12 Oct 2015 08:58:08 -0700 +Subject: [PATCH 178/187] drm/vc4: Verify at boot that CMA doesn't cross a + 256MB boundary. + +I've seen lots of users cranking CMA up higher, so throw an error if +they do. + +Signed-off-by: Eric Anholt +--- + drivers/base/dma-contiguous.c | 1 + + drivers/gpu/drm/vc4/vc4_v3d.c | 18 ++++++++++++++++++ + mm/cma.c | 2 ++ + 3 files changed, 21 insertions(+) + +diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c +index e167a1e1bccb062efef2595fcd5299301a97df80..60f5c2591ccdb0202461458eab4035cfba731b8b 100644 +--- a/drivers/base/dma-contiguous.c ++++ b/drivers/base/dma-contiguous.c +@@ -35,6 +35,7 @@ + #endif + + struct cma *dma_contiguous_default_area; ++EXPORT_SYMBOL(dma_contiguous_default_area); + + /* + * Default global CMA area size can be defined in kernel's .config. +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index 7cc346ad9b0baed63701d1fae8f0306aa7713129..1d9e5a6edd22c29ce8b2990c9c35627aa1af2bd8 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -16,7 +16,10 @@ + * this program. If not, see . + */ + ++#include "linux/init.h" ++#include "linux/cma.h" + #include "linux/component.h" ++#include "linux/dma-contiguous.h" + #include "linux/pm_runtime.h" + #include "vc4_drv.h" + #include "vc4_regs.h" +@@ -185,8 +188,23 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_v3d *v3d = NULL; ++ struct cma *cma; + int ret; + ++ cma = dev_get_cma_area(dev); ++ if (!cma) ++ return -EINVAL; ++ ++ if ((cma_get_base(cma) & 0xf0000000) != ++ ((cma_get_base(cma) + cma_get_size(cma) - 1) & 0xf0000000)) { ++ DRM_ERROR("V3D requires that the CMA area (0x%08lx - 0x%08lx) " ++ "not span a 256MB boundary, or memory corruption " ++ "would happen.\n", ++ (long)cma_get_base(cma), ++ cma_get_base(cma) + cma_get_size(cma)); ++ return -EINVAL; ++ } ++ + v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); + if (!v3d) + return -ENOMEM; +diff --git a/mm/cma.c b/mm/cma.c +index c960459eda7e640ea55be1d4ed80c6a9125a8877..b50245282a18bc790da0f901944c2e670ffac2d2 100644 +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -47,11 +47,13 @@ phys_addr_t cma_get_base(const struct cma *cma) + { + return PFN_PHYS(cma->base_pfn); + } ++EXPORT_SYMBOL(cma_get_base); + + unsigned long cma_get_size(const struct cma *cma) + { + return cma->count << PAGE_SHIFT; + } ++EXPORT_SYMBOL(cma_get_size); + + static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, + int align_order) + +From cae9a83b6256c761439d161f0525a4a8d3536003 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Feb 2017 09:47:11 +0000 +Subject: [PATCH 179/187] BCM270X_DT: Add SMSC ethernet controller to DT + +With an ethernet node in the DT, a suitable firmware can populate the +local-mac-address property, removing the need for a downstream patch +to the driver to read its MAC address from a module parameter. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 + + arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 + + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 + + arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 1 + + 4 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index 51f575e5d201fdfc1632e9bc8ed3bbd3e55dddcb..08bf838fab551638e898930fba7ba49b3aeefbb3 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2708.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi Model B+"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 028ef91a6c4f5d6573204635a03b912284505baa..4e6b4dd6a8d9c4f13bc865bb8ced68264162cb6c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2708.dtsi" ++#include "bcm283x-rpi-smsc9512.dtsi" + + / { + model = "Raspberry Pi Model B"; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index a4ffeff9fda62da830e674ff06c3a5394bd9d8cf..2dc0e1204e6374bbc6924e26dc4a04b68718559a 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + + #include "bcm2709.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi 2 Model B"; +diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +index d29ba72de727fe26b5a586e0bd0a41181c68ae04..78101849441679baf3624cf67a0ff7a2f1b34581 100644 +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +@@ -5,6 +5,7 @@ + #endif + + #include "bcm2710.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + model = "Raspberry Pi 3 Model B"; + +From 8ea4ba72ff44fad758eef3756cdaf823f7005033 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Feb 2017 15:26:13 +0000 +Subject: [PATCH 180/187] brcmfmac: Mute expected startup 'errors' + +The brcmfmac WiFi driver always complains about the '00' country code +and the firmware version is reported as an error. Modify the driver to +ignore '00' silently and display firmware version at INFO level. + +Signed-off-by: Phil Elwell +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 ++ + drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 3fcb1887b2d312e050c02e9fe66ea20f48f0abcb..e2a459f7a2003cb316f29b6dace3ca975f4d7a95 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6804,6 +6804,8 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { ++ if (req->alpha2[0] == '0' && req->alpha2[1] == '0') ++ return; + brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + req->alpha2[0], req->alpha2[1]); + return; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index 4051780f64f44a5ce522babe6c371a1beb79a824..b081673abcb4aa72d70d8e0834b608f65fea16e8 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -161,7 +161,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + strsep(&ptr, "\n"); + + /* Print fw version info */ +- brcmf_err("Firmware version = %s\n", buf); ++ pr_info("Firmware version = %s\n", buf); + + /* locate firmware version number for ethtool */ + ptr = strrchr(buf, ' ') + 1; + +From 112f8f716394909b4890f754d9782067c36f76c2 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 13 Feb 2017 17:20:08 +0000 +Subject: [PATCH 181/187] clk-bcm2835: Mark used PLLs and dividers CRITICAL + +The VPU configures and relies on several PLLs and dividers. Mark all +enabled dividers and their PLLs as CRITICAL to prevent the kernel from +switching them off. + +Signed-off-by: Phil Elwell +--- + drivers/clk/bcm/clk-bcm2835.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 136e5d28f9eaeaa10d45382a0f31da9f4adb91ef..4192863778c8009aacfc9a49ee38ad1ca62a01e4 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1366,6 +1366,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + divider->div.hw.init = &init; + divider->div.table = NULL; + ++ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { ++ init.flags |= CLK_IS_CRITICAL; ++ divider->div.flags |= CLK_IS_CRITICAL; ++ } ++ + divider->cprman = cprman; + divider->data = data; + + +From 76f825cc6b7fdd30451cbb775b7cfee6921dbef4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 13 Feb 2017 17:20:08 +0000 +Subject: [PATCH 182/187] clk-bcm2835: Add claim-clocks property + +The claim-clocks property can be used to prevent PLLs and dividers +from being marked as critical. It contains a vector of clock IDs, +as defined by dt-bindings/clock/bcm2835.h. + +Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and +PLLH_PIX for the vc4_kms_v3d driver. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 14 +++++++++ + drivers/clk/bcm/clk-bcm2835.c | 34 ++++++++++++++++++++-- + 2 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +index a8ef8c9051668a7477dea30aa262568c8e7f221c..c57e795824e9261e0f60bcb40d6a57241019fd91 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -5,6 +5,8 @@ + /dts-v1/; + /plugin/; + ++#include ++ + / { + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + +@@ -155,6 +157,18 @@ + }; + }; + ++ fragment@19 { ++ target = <&clocks>; ++ __overlay__ { ++ claim-clocks = < ++ BCM2835_PLLD_DSI0 ++ BCM2835_PLLD_DSI1 ++ BCM2835_PLLH_AUX ++ BCM2835_PLLH_PIX ++ >; ++ }; ++ }; ++ + __overrides__ { + cma-256 = <0>,"+0-1-2-3-4"; + cma-192 = <0>,"-0+1-2-3-4"; +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 4192863778c8009aacfc9a49ee38ad1ca62a01e4..6b245357e4e93c19a839eee92a82f95aec996e4e 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1298,6 +1298,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { + .debug_init = bcm2835_clock_debug_init, + }; + ++static bool bcm2835_clk_is_claimed(const char *name); ++ + static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + const struct bcm2835_pll_data *data) + { +@@ -1314,6 +1316,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + init.ops = &bcm2835_pll_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + ++ if (!bcm2835_clk_is_claimed(data->name)) ++ init.flags |= CLK_IS_CRITICAL; ++ + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return NULL; +@@ -1367,8 +1372,10 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, + divider->div.table = NULL; + + if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { +- init.flags |= CLK_IS_CRITICAL; +- divider->div.flags |= CLK_IS_CRITICAL; ++ if (!bcm2835_clk_is_claimed(data->source_pll)) ++ init.flags |= CLK_IS_CRITICAL; ++ if (!bcm2835_clk_is_claimed(data->name)) ++ divider->div.flags |= CLK_IS_CRITICAL; + } + + divider->cprman = cprman; +@@ -2104,6 +2111,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { + .ctl_reg = CM_PERIICTL), + }; + ++static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)]; ++ + /* + * Permanently take a reference on the parent of the SDRAM clock. + * +@@ -2123,6 +2132,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) + return clk_prepare_enable(parent); + } + ++static bool bcm2835_clk_is_claimed(const char *name) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { ++ const char *clk_name = *(const char **)(clk_desc_array[i].data); ++ if (!strcmp(name, clk_name)) ++ return bcm2835_clk_claimed[i]; ++ } ++ ++ return false; ++} ++ + static int bcm2835_clk_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -2132,6 +2154,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + const struct bcm2835_clk_desc *desc; + const size_t asize = ARRAY_SIZE(clk_desc_array); + size_t i; ++ u32 clk_id; + int ret; + + cprman = devm_kzalloc(dev, sizeof(*cprman) + +@@ -2147,6 +2170,13 @@ static int bcm2835_clk_probe(struct platform_device *pdev) + if (IS_ERR(cprman->regs)) + return PTR_ERR(cprman->regs); + ++ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); ++ for (i = 0; ++ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", ++ i, &clk_id); ++ i++) ++ bcm2835_clk_claimed[clk_id]= true; ++ + memcpy(cprman->real_parent_names, cprman_parent_names, + sizeof(cprman_parent_names)); + of_clk_parent_fill(dev->of_node, cprman->real_parent_names, + +From 31bb9062dbef3f4899cc3479f467b3dcf1d2658b Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 20 Feb 2017 20:01:16 +0100 +Subject: [PATCH 183/187] dmaengine: bcm2835: Fix cyclic DMA period splitting + +The code responsible for splitting periods into chunks that +can be handled by the DMA controller missed to update total_len, +the number of bytes processed in the current period, when there +are more chunks to follow. + +Therefore total_len was stuck at 0 and the code didn't work at all. +This resulted in a wrong control block layout and audio issues because +the cyclic DMA callback wasn't executing on period boundaries. + +Fix this by adding the missing total_len update. + +Signed-off-by: Matthias Reichl +Signed-off-by: Martin Sperl +Tested-by: Clive Messer +Reviewed-by: Eric Anholt +--- + drivers/dma/bcm2835-dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c +index 80d35f760b4a4a51e60c355a84d538bac3892a4d..599c218dc8a73172dd4bd4a058fc8f95a73f982f 100644 +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -253,8 +253,11 @@ static void bcm2835_dma_create_cb_set_length( + */ + + /* have we filled in period_length yet? */ +- if (*total_len + control_block->length < period_len) ++ if (*total_len + control_block->length < period_len) { ++ /* update number of bytes in this period so far */ ++ *total_len += control_block->length; + return; ++ } + + /* calculate the length that remains to reach period_length */ + control_block->length = period_len - *total_len; + +From c283874273d029c659a834d2c598a76e43f2dce1 Mon Sep 17 00:00:00 2001 +From: Scott Ellis +Date: Thu, 23 Feb 2017 11:56:20 -0500 +Subject: [PATCH 184/187] Add ads1015 driver to config + +--- + arch/arm/configs/bcm2709_defconfig | 3 ++- + arch/arm/configs/bcmrpi_defconfig | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 669edd7544d79838d9471fbe11b803c342f195df..f251cf76bb080e19fba11d3900a8e81c79c4f67a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -653,6 +653,7 @@ CONFIG_HWMON=m + CONFIG_SENSORS_LM75=m + CONFIG_SENSORS_SHT21=m + CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_ADS1015=m + CONFIG_SENSORS_INA2XX=m + CONFIG_THERMAL=y + CONFIG_THERMAL_BCM2835=y +@@ -833,9 +834,9 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_UDL=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +-CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 9a9cd1cdcb2f76d4408568681ec80885293bae48..554fed3a4fbfd1940422b808046c6d2b1f508394 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -647,6 +647,7 @@ CONFIG_HWMON=m + CONFIG_SENSORS_LM75=m + CONFIG_SENSORS_SHT21=m + CONFIG_SENSORS_SHTC1=m ++CONFIG_SENSORS_ADS1015=m + CONFIG_SENSORS_INA2XX=m + CONFIG_THERMAL=y + CONFIG_THERMAL_BCM2835=y +@@ -827,9 +828,9 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_DRM=m + CONFIG_DRM_LOAD_EDID_FIRMWARE=y ++CONFIG_DRM_UDL=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +-CONFIG_DRM_UDL=m + CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + +From e4a1aa30f5d5f63f6833a7d0a4729cb77cff2299 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 27 Jan 2017 18:49:30 +0000 +Subject: [PATCH 185/187] config: add slcan kernel module + +See: https://github.com/raspberrypi/linux/issues/1819 +--- + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index f251cf76bb080e19fba11d3900a8e81c79c4f67a..843d8fdb6cc95720267ea5ec7edb8802d10a77f0 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -361,6 +361,7 @@ CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m + CONFIG_CAN=m + CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m + CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 554fed3a4fbfd1940422b808046c6d2b1f508394..99888182259b280790a7506b248a8130e1041d41 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -357,6 +357,7 @@ CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m + CONFIG_CAN=m + CONFIG_CAN_VCAN=m ++CONFIG_CAN_SLCAN=m + CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + +From d71f78106b46a879302ccebab9cd45b05d11fb14 Mon Sep 17 00:00:00 2001 +From: Miquel +Date: Fri, 24 Feb 2017 20:51:06 +0100 +Subject: [PATCH 186/187] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT + +Signed-off-by: Miquel Blauw +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 19 +++++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + sound/soc/bcm/Kconfig | 7 ++ + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/dionaudio_loco-v2.c | 140 ++++++++++++++++++++++++++++++++++++ + 7 files changed, 171 insertions(+) + create mode 100644 sound/soc/bcm/dionaudio_loco-v2.c + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 0a7d30cd573060964bb081ee6617d5b77a17b974..8856139d061472311b7cead0641b5645ef33caad 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -13,6 +13,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + bmp085_i2c-sensor.dtbo \ + dht11.dtbo \ + dionaudio-loco.dtbo \ ++ dionaudio-loco-v2.dtbo \ + dpi18.dtbo \ + dpi24.dtbo \ + dwc-otg.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 46228fd324fc4c52eb0ba50316b4c02f8245bf04..c9845ba37018b821d7e5093e15a06721318b558f 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -308,6 +308,25 @@ Load: dtoverlay=dionaudio-loco + Params: + + ++Name: dionaudio-loco-v2 ++Info: Configures the Dion Audio LOCO-V2 DAC-AMP ++Load: dtoverlay=dionaudio-loco-v2,= ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ Digital volume control. Enable with ++ "dtoverlay=hifiberry-dacplus,24db_digital_gain" ++ (The default behaviour is that the Digital ++ volume control is limited to a maximum of ++ 0dB. ie. it can attenuate but not provide ++ gain. For most users, this will be desired ++ as it will prevent clipping. By appending ++ the 24dB_digital_gain parameter, the Digital ++ volume control will allow up to 24dB of ++ gain. If this parameter is enabled, it is the ++ responsibility of the user to ensure that ++ the Digital volume control is set to a value ++ that does not result in clipping/distortion!) ++ ++ + Name: dpi18 + Info: Overlay for a generic 18-bit DPI display + This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 843d8fdb6cc95720267ea5ec7edb8802d10a77f0..7d31052cfd1d87f7488d3b8ffa1a476d8dc9f275 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -889,6 +889,7 @@ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m + CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m + CONFIG_SND_DIGIDAC1_SOUNDCARD=m + CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m ++CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m + CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m + CONFIG_SND_PISOUND=m + CONFIG_SND_SOC_ADAU1701=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 99888182259b280790a7506b248a8130e1041d41..2abbcad49833dc2fb1bf98f3258d625ee58577f9 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -883,6 +883,7 @@ CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m + CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m + CONFIG_SND_DIGIDAC1_SOUNDCARD=m + CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m ++CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m + CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m + CONFIG_SND_PISOUND=m + CONFIG_SND_SOC_ADAU1701=m +diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig +index 10f6b201777946af8e8e78d2ffb0b0cff38093df..ba5cb8eed455962cc9840e7a8088fddadd49f5e3 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -133,6 +133,13 @@ config SND_BCM2708_SOC_DIONAUDIO_LOCO + help + Say Y or M if you want to add support for Dion Audio LOCO. + ++config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2 ++ tristate "Support for Dion Audio LOCO-V2 DAC-AMP" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_PCM5122 ++ help ++ Say Y or M if you want to add support for Dion Audio LOCO-V2. ++ + config SND_BCM2708_SOC_ALLO_PIANO_DAC + tristate "Support for Allo Piano DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index 84c2b20ce2e51b525797ee58de95734ee7847e15..4d8adf691021a974310589e92e599924811f22cb 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -25,6 +25,7 @@ snd-soc-raspidac3-objs := raspidac3.o + snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o + snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o + snd-soc-dionaudio-loco-objs := dionaudio_loco.o ++snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o + snd-soc-allo-piano-dac-objs := allo-piano-dac.o + snd-soc-pisound-objs := pisound.o + +@@ -44,5 +45,6 @@ obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o + obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o + obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o + obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o ++obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o + obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o + obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o +diff --git a/sound/soc/bcm/dionaudio_loco-v2.c b/sound/soc/bcm/dionaudio_loco-v2.c +new file mode 100644 +index 0000000000000000000000000000000000000000..a009c49477972a9832175d86f201b0357a08f7c0 +--- /dev/null ++++ b/sound/soc/bcm/dionaudio_loco-v2.c +@@ -0,0 +1,140 @@ ++/* ++ * ASoC Driver for Dion Audio LOCO-V2 DAC-AMP ++ * ++ * Author: Miquel Blauw ++ * Copyright 2017 ++ * ++ * Based on the software of the RPi-DAC writen by Florian Meier ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static bool digital_gain_0db_limit = true; ++ ++static int snd_rpi_dionaudio_loco_v2_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ if (digital_gain_0db_limit) { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ ++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_dionaudio_loco_v2_hw_params( ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ unsigned int sample_bits = ++ snd_pcm_format_physical_width(params_format(params)); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_dionaudio_loco_v2_ops = { ++ .hw_params = snd_rpi_dionaudio_loco_v2_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_dionaudio_loco_v2_dai[] = { ++{ ++ .name = "DionAudio LOCO-V2", ++ .stream_name = "DionAudio LOCO-V2 DAC-AMP", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "pcm512x-hifi", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "pcm512x.1-004d", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_dionaudio_loco_v2_ops, ++ .init = snd_rpi_dionaudio_loco_v2_init, ++},}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_dionaudio_loco_v2 = { ++ .name = "Dion Audio LOCO-V2", ++ .dai_link = snd_rpi_dionaudio_loco_v2_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_v2_dai), ++}; ++ ++static int snd_rpi_dionaudio_loco_v2_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_dionaudio_loco_v2.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai = ++ &snd_rpi_dionaudio_loco_v2_dai[0]; ++ ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpu_dai_name = NULL; ++ dai->cpu_of_node = i2s_node; ++ dai->platform_name = NULL; ++ dai->platform_of_node = i2s_node; ++ } ++ ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "dionaudio,24db_digital_gain"); ++ } ++ ++ ret = snd_soc_register_card(&snd_rpi_dionaudio_loco_v2); ++ if (ret) ++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ++ ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_dionaudio_loco_v2_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_dionaudio_loco_v2); ++} ++ ++static const struct of_device_id dionaudio_of_match[] = { ++ { .compatible = "dionaudio,dionaudio-loco-v2", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dionaudio_of_match); ++ ++static struct platform_driver snd_rpi_dionaudio_loco_v2_driver = { ++ .driver = { ++ .name = "snd-rpi-dionaudio-loco-v2", ++ .owner = THIS_MODULE, ++ .of_match_table = dionaudio_of_match, ++ }, ++ .probe = snd_rpi_dionaudio_loco_v2_probe, ++ .remove = snd_rpi_dionaudio_loco_v2_remove, ++}; ++ ++module_platform_driver(snd_rpi_dionaudio_loco_v2_driver); ++ ++MODULE_AUTHOR("Miquel Blauw "); ++MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2"); ++MODULE_LICENSE("GPL v2"); + +From 77bd32f0f2f58e714ba250a1a4c6b51d3fcb3361 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sun, 26 Feb 2017 01:13:02 +0000 +Subject: [PATCH 187/187] SQUASH: Add LOCO-V2 overlay from last commit + +--- + .../dts/overlays/dionaudio-loco-v2-overlay.dts | 49 ++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..a1af93de30119734e8d14cbd454589d365a3ba10 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts +@@ -0,0 +1,49 @@ ++/* ++ * Definitions for Dion Audio LOCO-V2 DAC-AMP ++ * eg. dtoverlay=dionaudio-loco-v2 ++ * ++ * PCM5242 DAC (in software mode) and TPA3255 AMP. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&sound>; ++ frag0: __overlay__ { ++ compatible = "dionaudio,dionaudio-loco-v2"; ++ i2s-controller = <&i2s>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pcm5122@4c { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm5122"; ++ reg = <0x4d>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag0>,"dionaudio,24db_digital_gain?"; ++ }; ++};