diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index 32cf12da6a..73e7b4fab8 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 5e9c268f96c85ea7722958b1f6f73c8d13a822dc Mon Sep 17 00:00:00 2001 +From ffd06bc2da1c5a433250de4013263bcd4f0da46e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/204] Main bcm2708/bcm2709 linux port +Subject: [PATCH 001/278] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -181,10 +181,10 @@ index 19f4cc6..3ec1319 100644 source "arch/arm/mach-alpine/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 0c12ffb..18db6c4 100644 +index f775d71..5b29257 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -1197,6 +1197,14 @@ choice +@@ -1196,6 +1196,14 @@ choice options; the platform specific options are deprecated and will be soon removed. @@ -7002,10 +7002,10 @@ index b5bedae..b0258e8 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From 7408b83b52329a004068c5749e1733d8cb9028cb Mon Sep 17 00:00:00 2001 +From 948ac9440c4e80652fc31e3ff88280d43d9f1bb9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 002/204] Add bcm2708_gpio driver +Subject: [PATCH 002/278] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -7635,10 +7635,10 @@ index 0000000..fb69624 + +#endif -From d86df54c296ad49447cb90e8c9ea1d2c8bd2b82b Mon Sep 17 00:00:00 2001 +From 16d13e64d51ee66289f7bc61126e4a751895a880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 1 May 2015 19:11:03 +0200 -Subject: [PATCH 003/204] mailbox: bcm2708: Add bcm2708-vcio +Subject: [PATCH 003/278] mailbox: bcm2708: Add bcm2708-vcio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -8269,10 +8269,10 @@ index 0000000..cc284ed + +#endif -From a01bebe2f26586b5b8021847cc12f83f9fd0a27f Mon Sep 17 00:00:00 2001 +From 92e60879b7ea380f2d9becfb0b606a3ceb6c2d13 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/204] Add dwc_otg driver +Subject: [PATCH 004/278] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -9180,10 +9180,10 @@ index 358ca8d..abaac7c 100644 return i; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 1e9a8c9..7e9f79f 100644 +index e56ad83..2574b3e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -4906,7 +4906,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -4927,7 +4927,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; @@ -9441,7 +9441,7 @@ index a6315ab..165dd53 100644 diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c new file mode 100644 -index 0000000..a896d73 +index 0000000..a896d73f --- /dev/null +++ b/drivers/usb/gadget/file_storage.c @@ -0,0 +1,3676 @@ @@ -13146,10 +13146,10 @@ index 197a6a3..5496cd0 100644 tristate "i.MX21 HCD support" depends on ARM && ARCH_MXC diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 65b0b6a..49399f2 100644 +index da03d8b..bda597d 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile -@@ -68,6 +68,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o +@@ -67,6 +67,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o @@ -17280,7 +17280,7 @@ index 0000000..b802042 +#endif /* DWC_LIBMODULE */ diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c new file mode 100644 -index 0000000..49b07e1 +index 0000000..49b07e17 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c @@ -0,0 +1,1275 @@ @@ -29807,7 +29807,7 @@ index 0000000..bbb3d32 +#endif //DWC_UTE_CFI diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.h b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h new file mode 100644 -index 0000000..55fd337 +index 0000000..55fd337a --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h @@ -0,0 +1,320 @@ @@ -59769,7 +59769,7 @@ index 0000000..c8d2e0e +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c new file mode 100644 -index 0000000..c8590b5 +index 0000000..c8590b52 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c @@ -0,0 +1,5147 @@ @@ -69546,10 +69546,10 @@ index 0000000..cdc9963 +test_main(); +0; -From a7a65674af3af5dcc29121afaae50c0cf6b2e13b Mon Sep 17 00:00:00 2001 +From 405ca74b632474bdab6ef5a2b799f10faecbf950 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/204] bcm2708 watchdog driver +Subject: [PATCH 005/278] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -69986,10 +69986,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); -From d2d531d448b63465a680fb3e15c0e843267ff50f Mon Sep 17 00:00:00 2001 +From 6b76bbd2a9a4053ded1573cb3a4c0c0687181acc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 006/204] bcm2708 framebuffer driver +Subject: [PATCH 006/278] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -73428,10 +73428,10 @@ index 3c14e43..7626beb6a 100644 +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 7b98bf652df7771dd8eb79528dd7e276f2038585 Mon Sep 17 00:00:00 2001 +From da2171b008b0082775a7b690a0e77282405976f4 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 007/204] dmaengine: Add support for BCM2708 +Subject: [PATCH 007/278] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75199,10 +75199,10 @@ index 0000000..2310e34 + +#endif /* _PLAT_BCM2708_DMA_H */ -From 44cbf9ce5089b224b53fa45eade2bfb7111bc2db Mon Sep 17 00:00:00 2001 +From 3f8f3a9418ada97a4279e71fbe7bc14fca3266fd Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 008/204] MMC: added alternative MMC driver +Subject: [PATCH 008/278] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -77018,10 +77018,10 @@ index 0000000..b7c4883 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From b0a083aa54f21ac74e866d9c016653d247e6d2b7 Mon Sep 17 00:00:00 2001 +From 6fc9ed66cfea50cfca82e4590d515b38f8bb1515 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 009/204] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 009/278] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -78791,10 +78791,10 @@ index 0000000..eef8a24 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From a48f15d3cdee3004a03d04e296247625130dcbf7 Mon Sep 17 00:00:00 2001 +From 23e9f454193f3ab369e9d0eda3674e241e437d27 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 010/204] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 010/278] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix @@ -80119,10 +80119,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From ebd29c2fcd995ebe287b4d9e771bd1f6730e6e13 Mon Sep 17 00:00:00 2001 +From e71e3228c8bc7181b31a7e2881f9358e6f53dc05 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 011/204] bcm2708: alsa sound driver +Subject: [PATCH 011/278] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -82964,10 +82964,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From 4978dc22bb85d1c218085aa253224bdaea6f89fc Mon Sep 17 00:00:00 2001 +From 41131d689f4ed20636685d602c658e543542fdbb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 012/204] bcm2708 vchiq driver +Subject: [PATCH 012/278] bcm2708 vchiq driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -96221,10 +96221,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From 5c91907c6aec2d89bf1d57ab85e01bfdab1f0801 Mon Sep 17 00:00:00 2001 +From 8c6b124a066e8b865779a968653844c2f7ba4d44 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 16:07:06 +0100 -Subject: [PATCH 013/204] vc_mem: Add vc_mem driver +Subject: [PATCH 013/278] vc_mem: Add vc_mem driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -97230,10 +97230,10 @@ index 0000000..20a4753 + +#endif /* _VC_MEM_H */ -From 40c1f77329886c79e9ac40afe3dee52dec5a0f5f Mon Sep 17 00:00:00 2001 +From 0465331ab045339e339d6df2dab587c4d97e641e Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 014/204] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 014/278] vcsm: VideoCore shared memory service for BCM2835 Add experimental support for the VideoCore shared memory service. This allows user processes to allocate memory from VideoCore's @@ -101643,10 +101643,10 @@ index 0000000..0bfb42e +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 89476e1e5132eb053f40bcad4d31903c2660d737 Mon Sep 17 00:00:00 2001 +From fa4f1898341f37f413e0482d047740c4a1249dba Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 015/204] Add hwrng (hardware random number generator) driver +Subject: [PATCH 015/278] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 13 +++- @@ -101823,10 +101823,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From 0f09a4b263925916b493657ad19334d1b62ee299 Mon Sep 17 00:00:00 2001 +From c66d7e987408cc8921ca9d426142212ce64a181e Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 016/204] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 016/278] 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 @@ -102679,10 +102679,10 @@ index 0000000..24563ec +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 7dc35f47e29f40755b9a66b6c1b8f693d0a7e414 Mon Sep 17 00:00:00 2001 +From 3b17bb7823c2b8a43cb85a8633382684a786cf8f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 017/204] Add cpufreq driver +Subject: [PATCH 017/278] Add cpufreq driver Signed-off-by: popcornmix --- @@ -102955,10 +102955,10 @@ index 0000000..6735da9 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From d8057ff6ba5dece8ae393713e563362dc53bbde4 Mon Sep 17 00:00:00 2001 +From 9c00340088fe26bd04a11c9b2aca62245912f04c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 018/204] Added hwmon/thermal driver for reporting core +Subject: [PATCH 018/278] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -103255,10 +103255,10 @@ index 0000000..3bc80f1 + +module_platform_driver(bcm2835_thermal_driver); -From 320c58bca444bc390f7eccfebbb529fe8e98ed10 Mon Sep 17 00:00:00 2001 +From adfdb7dbb59687542d233ff56f453e1580c0890f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:41:33 +0100 -Subject: [PATCH 019/204] Add Chris Boot's spi driver. +Subject: [PATCH 019/278] Add Chris Boot's spi driver. spi: bcm2708: add device tree support @@ -104170,10 +104170,10 @@ index 0000000..041b5e2 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From db4e6f4abd7eb95d3224be99d7f04c791f4ceb8d Mon Sep 17 00:00:00 2001 +From 36e25710ce594f2f0e6c5ad00f750fd50cc098ac Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 020/204] Add Chris Boot's i2c driver +Subject: [PATCH 020/278] Add Chris Boot's i2c driver i2c-bcm2708: fixed baudrate @@ -104974,10 +104974,10 @@ index 0000000..8773203 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From fb0599a8dc95e605fe75e510c39a99e77fe627f8 Mon Sep 17 00:00:00 2001 +From 26b716f6035f208f954627d06e8580875d713f63 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 021/204] bcm2835: add v4l2 camera device +Subject: [PATCH 021/278] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -112304,10 +112304,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From 55141e6e23fd7c2f2b98d6f472dd4e1f11fcdb50 Mon Sep 17 00:00:00 2001 +From 4ea8726fc5f8574c73f4534f633012794926dfd2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 022/204] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 022/278] scripts/dtc: Update to upstream version with overlay patches --- @@ -117520,10 +117520,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 8bddbe464074570457bca032ebee779eb9814d13 Mon Sep 17 00:00:00 2001 +From cc34f5b569f58526b93a28d202c3e07e600fcd83 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 023/204] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 023/278] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -118008,10 +118008,10 @@ index 0000000..3dff948 + return (($val eq 'y') || ($val eq '1')); +} -From febe480850daa451009a87a3b86278f3d7dbaa10 Mon Sep 17 00:00:00 2001 +From 377ebe45a8b20a9a44e1c53f00f7cbc0b3667f08 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 024/204] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 024/278] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -118066,10 +118066,10 @@ index d91f721..02feb00 100644 pr_debug("Command line is: %s\n", (char*)data); -From 35658cc32f834e0bad12e6206b7ffb6af9eddbe6 Mon Sep 17 00:00:00 2001 +From fb27a2784f3557a053b7d0afd66517523d7a6970 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 025/204] BCM2708: Add core Device Tree support +Subject: [PATCH 025/278] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -120252,7 +120252,7 @@ index 0000000..2c81448 +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts new file mode 100644 -index 0000000..5e7633a +index 0000000..5e7633ae --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts @@ -0,0 +1,34 @@ @@ -121328,7 +121328,7 @@ index 0000000..40bf0e1 +}; diff --git a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts new file mode 100644 -index 0000000..7fc6ac9 +index 0000000..7fc6ac99 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts @@ -0,0 +1,34 @@ @@ -121946,10 +121946,10 @@ index 0000000..66a98f6 + }; +}; -From 7c4a63015f03594469922e65ae613bbc4e54c4cf Mon Sep 17 00:00:00 2001 +From df318861bb615aeccab05e3adfe9afbedc990046 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 026/204] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 026/278] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -122026,7 +122026,7 @@ index 0705d88..771992a 100644 case FBIOBLANK: ret = do_fb_ioctl(info, cmd, arg); diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h -index fb795c3..fa72af0 100644 +index fb795c3..fa72af0c 100644 --- a/include/uapi/linux/fb.h +++ b/include/uapi/linux/fb.h @@ -34,6 +34,11 @@ @@ -122042,10 +122042,11 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 4f1485790c96ee05b7fd08c23905f8957c8f2b61 Mon Sep 17 00:00:00 2001 + +From c45570b46933912e967c3065fc22c8ba667ba12d Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 029/204] Speed up console framebuffer imageblit function +Subject: [PATCH 029/278] 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 @@ -122254,10 +122255,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From efd2fa9ef6e7848d0494f1a66d46e9280d507f4e Mon Sep 17 00:00:00 2001 +From 5028743160d3d29afd26eac7998617c90a349205 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 030/204] Allow mac address to be set in smsc95xx +Subject: [PATCH 030/278] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -122348,10 +122349,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 625c18792c5c8272af5237599d44d852e0996bdf Mon Sep 17 00:00:00 2001 +From e5eb9a45c70ee50e76e136eaddcc3f71db1fa27b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 031/204] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 031/278] 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 @@ -122749,10 +122750,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 8b7527453528e339a4586eec937857f1b994daae Mon Sep 17 00:00:00 2001 +From 7a7604c7f5e332d2f5f694165a5c74e06442fe17 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 033/204] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 033/278] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -122795,10 +122796,10 @@ index 4d65b66..dd258ff 100644 { printk("cgroup: using legacy files on the default hierarchy\n"); diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 68dea90..6fd0c4f 100644 +index aac1c98..d25efbc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -5389,6 +5389,7 @@ struct cgroup_subsys memory_cgrp_subsys = { +@@ -5390,6 +5390,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .dfl_cftypes = memory_files, .legacy_cftypes = mem_cgroup_legacy_files, .early_init = 0, @@ -122807,10 +122808,10 @@ index 68dea90..6fd0c4f 100644 /** -From 727594aaa8ab739ea1c22eca69bf5400948af0d1 Mon Sep 17 00:00:00 2001 +From d9d47cc54a8e9bd7862e2bc5faaf5ad596607902 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 034/204] ASoC: Add support for BCM2708 +Subject: [PATCH 034/278] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -123953,10 +123954,10 @@ index 0000000..6fdcbc1 + +#endif -From c0c7b62d38423b62ad3223b79f7f60802c6c1e5c Mon Sep 17 00:00:00 2001 +From ae4d28cda5572ee772f9b13b2a0bb5e65692d3e5 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 035/204] ASoC: Add support for PCM5102A codec +Subject: [PATCH 035/278] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -124081,10 +124082,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 0f2fff9145ec3742650115b422b3fa4983002668 Mon Sep 17 00:00:00 2001 +From 665cab7a61982780599002ad9cc7a4f31448f5fc Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 036/204] BCM2708: Add I2S support to board file +Subject: [PATCH 036/278] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -124173,10 +124174,10 @@ index a3b65dc..a515992 100644 for (i = 0; i <= 1; i++) { void __iomem *base; -From b7db156b7135bd8023bc2e553fa802f10b33df21 Mon Sep 17 00:00:00 2001 +From 70d231945fafd27ceee934ff71d56793e7798eae Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 037/204] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 037/278] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -124325,10 +124326,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From c48e1b97199c72f611b2f0937d36bc98a7169bba Mon Sep 17 00:00:00 2001 +From 251ca1c8fbb88f0aec430199c7e14bead17c026f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 038/204] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 038/278] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -124376,10 +124377,10 @@ index 01f2de7..1d9b788 100644 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; -From 46355bc118b045051f833c56844bba4b71b6b666 Mon Sep 17 00:00:00 2001 +From 032100077129e77cbff9cae10adaaa5ecb3b05f2 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 039/204] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 039/278] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -124674,10 +124675,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 81991e83d009ef30b23b0f7190042479293aa418 Mon Sep 17 00:00:00 2001 +From da878ad7d43c9aed76026e4cf0bef31a0f2b8ffd Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 040/204] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 040/278] 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 @@ -124717,10 +124718,10 @@ index 1e403f6..d4efa85 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From bf20cf45c9c208ff4a47465f3297196806b95da7 Mon Sep 17 00:00:00 2001 +From c1c7d648404af9015fa1013b6a4b07e3423610b5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 041/204] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 041/278] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -124985,10 +124986,10 @@ index 0000000..92e9e46 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From ebfceb0a7d6a4854618c00339d571421b7a18b68 Mon Sep 17 00:00:00 2001 +From 189af09ac6a681842d1c75b6652e5e066997c8d8 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 042/204] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 042/278] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -125035,10 +125036,10 @@ index 6d53beb..a062d7f 100644 bcm_register_device_dt(&snd_rpi_dac_device); bcm_register_device_dt(&snd_pcm1794a_codec_device); -From b9597317ed9afa6fe3712758c0ad5d1b11766d60 Mon Sep 17 00:00:00 2001 +From 30fa17f1cb4328667047e63a1ac54cab62a3555f Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 043/204] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 043/278] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -125060,10 +125061,10 @@ index d4efa85..f3f26a2 100644 .dapm_widgets = wm8804_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets), -From 098e66a4235451ad64c8bc1349496fc68a0e16fc Mon Sep 17 00:00:00 2001 +From 7610b8a6d167550ae9dbeda954db51c2ed4134ba Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 044/204] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 044/278] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -125271,10 +125272,10 @@ index 0000000..aff7377 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From a2878cc4a414348ab3b5be3ad44f04ae8e77e3ab Mon Sep 17 00:00:00 2001 +From 79f174399444552afe7d42382e54d202507b7271 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 045/204] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 045/278] vmstat: Workaround for issue where dirty page count goes negative See: @@ -125301,10 +125302,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 0fb0113068c3d68d396dff09129369bd7719bb41 Mon Sep 17 00:00:00 2001 +From 42230f1cba840d81df5cd35bdbd48c45df9ca589 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 046/204] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 046/278] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -125340,10 +125341,10 @@ index eab5bd6..ca47de9 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From b5950dd391670c2090ca047af33ba1f5b330b272 Mon Sep 17 00:00:00 2001 +From b085ae1eafc7cdcfe97089a86727ea30c8d349e0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 047/204] Added support for HiFiBerry DAC+ +Subject: [PATCH 047/278] 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. @@ -125554,10 +125555,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 83ead1b240ffde9c9c592533b4b116ae721e6893 Mon Sep 17 00:00:00 2001 +From 5f3d09ef343808fcb4eaea246a183c2a17f9b08e Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 048/204] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 048/278] 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. @@ -126426,10 +126427,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From d78d9b666c8a7fb477945825a161505701e11b28 Mon Sep 17 00:00:00 2001 +From a84d873c468d6174228a76577eba1147927daa86 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Apr 2015 19:14:18 +0100 -Subject: [PATCH 049/204] bcm2708: Allow option card devices to be configured +Subject: [PATCH 049/278] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -126454,10 +126455,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 0cf6cbc05769deca2546837472623fc4e7b56c11 Mon Sep 17 00:00:00 2001 +From 42c8b50f6678c4f59c2204d1d7c0ec912cd32772 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:45:39 +0100 -Subject: [PATCH 050/204] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 050/278] Adding Device Tree support for some RPi audio cards --- arch/arm/mach-bcm2709/bcm2709.c | 143 ++++++++++++++++++++++++++++++++++++++ @@ -126820,10 +126821,10 @@ index 126f1e9..7c6598e 100644 }; -From 1548b70b26d3607e2f51c46f98c09f704911e4ae Mon Sep 17 00:00:00 2001 +From 7de01b445ffa2aa4e91ed15ea47c72d174206639 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 051/204] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 051/278] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -126959,10 +126960,10 @@ index 57e1f3d..721559b 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); -From c7e1fd615565779916e66d987595521dcefc691c Mon Sep 17 00:00:00 2001 +From b13179f136708067775cb241b279261905560f99 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 052/204] Update ds1307 driver for device-tree support +Subject: [PATCH 052/278] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -126989,10 +126990,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From 5d7ba67c43373946a8b3c8bed5f2e6e23090a09d Mon Sep 17 00:00:00 2001 +From d50a101ba1069645a4c2c038b3fb95323df00cec Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 053/204] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 053/278] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -127103,10 +127104,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From dfc29014435e46cbc28a4cdcdf1bff215964e13b Mon Sep 17 00:00:00 2001 +From f8756b0e5c80a63f1c1c173a84da775321150744 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 054/204] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 054/278] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -127325,10 +127326,10 @@ index d08591b..08d184c 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From ee705807744ab8001d5ae997102c0c8c9785dafe Mon Sep 17 00:00:00 2001 +From a1bf8f355612aa4e1c096d1be7c1f197defbf431 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 055/204] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 055/278] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -127415,10 +127416,10 @@ index 9a2b000..60accc5 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 27e98ca305c67ee354c42983a43f09b2e59ce5b5 Mon Sep 17 00:00:00 2001 +From e57a92eb3b4c6fd8934cca427af2f1bd2b2e42ff Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 056/204] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 056/278] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -127440,10 +127441,10 @@ index 8d908e3..7a1900d 100644 .can_sleep = false, }; -From e4022c2c7ada3dc69da92db183132c86cdc7d730 Mon Sep 17 00:00:00 2001 +From befbd426f62340bb92fbd3d2e48fbe2612d9b9a7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 057/204] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 057/278] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -127471,10 +127472,10 @@ index 7a1900d..62f85aa 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From d1c711959d41518b10f7c2797cac744c543468ad Mon Sep 17 00:00:00 2001 +From fc1edd9bb24b7b4df3b282e5ee27ed04185e8639 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 058/204] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 058/278] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -127620,10 +127621,10 @@ index 62f85aa..c7cf266 100644 }, }; -From 3c62244d144a37b12b9af16a34eb67b4b7cf48ba Mon Sep 17 00:00:00 2001 +From b1db004a2b8fdb0bfe2f81423d5005e400e6e9b4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 059/204] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 059/278] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -127650,10 +127651,10 @@ index c7cf266..986779a 100644 pc->irq_data[i].irqgroup = i; -From f8391406e17d282f010b8deebe0ccd26f8ea2e49 Mon Sep 17 00:00:00 2001 +From 83ac9da37cc24d10d043483504598d5a7b8b0579 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Feb 2015 15:10:24 +0000 -Subject: [PATCH 060/204] enc28j60: Add device tree compatible string and an +Subject: [PATCH 060/278] enc28j60: Add device tree compatible string and an overlay --- @@ -127687,10 +127688,10 @@ index b1b5f66..c6b6e1a 100644 .probe = enc28j60_probe, .remove = enc28j60_remove, -From eb2703ff418ab3b72d09375f7c2aa49aee9f4a0e Mon Sep 17 00:00:00 2001 +From 5175ca5355ce497abc7f20547e1c196c6340b6ae Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 061/204] Add driver for rpi-proto +Subject: [PATCH 061/278] 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 @@ -127905,10 +127906,10 @@ index 0000000..c6e45a0 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From d3d38e562e57db9c529f93aedfe9fca8b5c70a38 Mon Sep 17 00:00:00 2001 +From 6e9afafe59c9218786dcb17ad4fa0c3d7b9f7098 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Thu, 2 Apr 2015 12:22:55 +0100 -Subject: [PATCH 062/204] Add Device Tree support for RPi-DAC. +Subject: [PATCH 062/278] Add Device Tree support for RPi-DAC. --- sound/soc/bcm/rpi-dac.c | 21 +++++++++++++++++++++ @@ -127983,10 +127984,10 @@ index b4eaa44..afe1b41 100644 }; -From b15b358e11a817bcc7c3d8354c8a2f6f7d30a806 Mon Sep 17 00:00:00 2001 +From 8aeb303a194b5462abfcc948d3caf7591b20b7c0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 063/204] config: Add default configs +Subject: [PATCH 063/278] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1204 ++++++++++++++++++++++++++++++++++++ @@ -130411,10 +130412,10 @@ index 0000000..6a41231 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From 97b84b787de84ad70a3a3a2d7faa9c898c89077c Mon Sep 17 00:00:00 2001 +From 731be886de4b348da553b902006c3f6789af8f82 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 064/204] smsx95xx: fix crimes against truesize +Subject: [PATCH 064/278] 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. @@ -130449,10 +130450,10 @@ index e29a323..aff63dc usbnet_skb_return(dev, ax_skb); } -From f00f1c85db60369955c57b255c2588ff56d59fa7 Mon Sep 17 00:00:00 2001 +From 515f9ddee95bc0b06c48f55b6400923dc94923eb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 17 Apr 2015 16:58:45 +0100 -Subject: [PATCH 065/204] smsc95xx: Disable turbo mode by default +Subject: [PATCH 065/278] smsc95xx: Disable turbo mode by default --- drivers/net/usb/smsc95xx.c | 2 +- @@ -130472,10 +130473,10 @@ index aff63dc..08a8a8c 100755 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); -From 122b539270dc7e0d8ee3b6926c77f5aedb06fb67 Mon Sep 17 00:00:00 2001 +From 9b347c3aeefea0d450ea8247689d422686026086 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Apr 2015 19:30:22 +0100 -Subject: [PATCH 066/204] Add blk_pos parameter to mmc multi_io_quirk callback +Subject: [PATCH 066/278] Add blk_pos parameter to mmc multi_io_quirk callback --- drivers/mmc/card/block.c | 1 + @@ -130558,10 +130559,10 @@ index b0258e8..d3cdad9 100644 struct mmc_card; -From ec8a45bdc3e0afbf5ab8ba7735608e7ca11feca7 Mon Sep 17 00:00:00 2001 +From 0e99a42d44b7ab980a2aeceb0b5f0c84b12ab36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Apr 2015 17:24:02 +0200 -Subject: [PATCH 067/204] bcm2835: bcm2835_defconfig +Subject: [PATCH 067/278] bcm2835: bcm2835_defconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -131891,10 +131892,10 @@ index 31cb073..2e8a95a 100644 # CONFIG_XZ_DEC_ARM is not set # CONFIG_XZ_DEC_ARMTHUMB is not set -From af1868e02b629a2e2092bf358540d6ca4dcdff6c Mon Sep 17 00:00:00 2001 +From cd8f18b0cda05e394d92dadff530f1a719ba86ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 1 May 2015 23:00:15 +0200 -Subject: [PATCH 068/204] BCM270x_DT: Add mailbox bcm2708-vcio +Subject: [PATCH 068/278] BCM270x_DT: Add mailbox bcm2708-vcio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -131935,10 +131936,10 @@ index 721559b..4a00561 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); -From ab35f5a7f3921cd9d5d9f09f4bd82675822048dc Mon Sep 17 00:00:00 2001 +From cb26b0e8f2122493e80b261b2da19e4c415face3 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 069/204] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 069/278] rpi-ft5406: Add touchscreen driver for pi LCD display --- drivers/input/touchscreen/Kconfig | 7 + @@ -132255,10 +132256,10 @@ index cc284ed..d3ea839 100644 VCMSG_SET_CURSOR_STATE = 0x00008011, }; -From f12bdfa033dd3c639b037c3acefc6df99e51936d Mon Sep 17 00:00:00 2001 +From cd11b6897bc01c2adf21962394c9f42bfb54c37d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Oct 2014 11:47:53 +0100 -Subject: [PATCH 070/204] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 070/278] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -133783,10 +133784,10 @@ index 3e58d71..0622891 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) -From b52da83347f05007471699518545f3c8827d762a Mon Sep 17 00:00:00 2001 +From 1770dea7a8120ee58efed780c332c930b014d3dc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 27 May 2015 17:22:15 +0100 -Subject: [PATCH 071/204] bcm2835-audio: Create the platform device if the DT +Subject: [PATCH 071/278] bcm2835-audio: Create the platform device if the DT node is disabled For backwards compatibility, allow the built-in ALSA driver to be enabled @@ -133840,10 +133841,10 @@ index 4a00561..dec8043 100644 bcm_register_device_dt(&bcm2708_spi_device); -From 1b9a56248747ddcba15df7f60cf739eea2977349 Mon Sep 17 00:00:00 2001 +From 4cf804c9a4fa1fc254408c0d46e8c44e248dbcbb 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 072/204] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 072/278] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -133902,10 +133903,10 @@ index 70f2f39..f7fdacd 100644 static const char * const bcm2835_compat[] = { -From 6c1d2a6d20e29c2fb1809297925045701d8a4a2a Mon Sep 17 00:00:00 2001 +From d835ceec34bffd5a6698fcbdeece1956c79e7a24 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 16 Jun 2015 17:47:27 +0100 -Subject: [PATCH 073/204] platform: Add force_core command line setting to boot +Subject: [PATCH 073/278] platform: Add force_core command line setting to boot from a different core number --- @@ -133976,10 +133977,10 @@ index dec8043..fe71c50 100644 module_param(serial, uint, 0644); module_param(uart_clock, uint, 0644); -From fbedbf309c2ee139e3eace31eb388fc0c8c75301 Mon Sep 17 00:00:00 2001 +From 50b10764be01dcdb6edd986b748241fbbd7073db Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Jun 2015 17:46:17 +0100 -Subject: [PATCH 074/204] mach-bcm270x: Enable the building of pinctrl-bcm2835 +Subject: [PATCH 074/278] mach-bcm270x: Enable the building of pinctrl-bcm2835 --- drivers/pinctrl/Makefile | 1 + @@ -133998,10 +133999,10 @@ index 6eadf04..9119513 100644 obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ -From 697b347118f88f65839dbf93dfc583b06407e791 Mon Sep 17 00:00:00 2001 +From 65003cc7d24bd4923a53f99867947d9853982868 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 19 Jun 2015 16:41:39 +0100 -Subject: [PATCH 075/204] BCM270X_DT: Document the i2s-mmap overlay +Subject: [PATCH 075/278] BCM270X_DT: Document the i2s-mmap overlay --- arch/arm/boot/dts/overlays/README | 6 ++++++ @@ -134025,10 +134026,10 @@ index 3e08f98..7fa6d33 100644 Info: Configures the IQaudio DAC audio card Load: dtoverlay=iqaudio-dac -From 459023e570ec920d21cf3d01988a595f9027c87c Mon Sep 17 00:00:00 2001 +From 9144d4795d200ac8b0a8b7758490536a07ab85f7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 17 Jun 2015 11:36:53 +0100 -Subject: [PATCH 076/204] bcm2835-sdhost: Improve error handling and recovery +Subject: [PATCH 076/278] bcm2835-sdhost: Improve error handling and recovery 1) Expose the hw_reset method to the MMC framework, removing many internal calls by the driver. @@ -135120,10 +135121,10 @@ index eef8a24..6277e43 100644 if (host->allow_dma) { -From 1b37e961ff949769a09160dcc9567c47f8d093e6 Mon Sep 17 00:00:00 2001 +From eb34bef3eb5d52fbffdafa4effc8ccfda4485169 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 4 Jun 2015 13:11:46 -0700 -Subject: [PATCH 077/204] ARM: bcm2835: Add the Raspberry Pi firmware driver +Subject: [PATCH 077/278] ARM: bcm2835: Add the Raspberry Pi firmware driver This gives us a function for making mailbox property channel requests of the firmware, which is most notable in that it will let us get and @@ -135158,7 +135159,7 @@ index 6517132..564aa5b 100644 source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile -index 3fdd391..ee101a2 100644 +index 3fdd3912..ee101a2 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o @@ -135557,10 +135558,10 @@ index 0000000..9d9efb7 + void *data, size_t tag_size); +struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); -From 9666e309b64fbf73d945c934dc3e991e25218fba Mon Sep 17 00:00:00 2001 +From 075b2d72e1264fc04af611bc41eee436ceaff7f9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 22 Mar 2015 13:33:23 +0000 -Subject: [PATCH 078/204] config: Enable ZSMALLOC, ZRAM and PGTABLE_MAPPING +Subject: [PATCH 078/278] config: Enable ZSMALLOC, ZRAM and PGTABLE_MAPPING --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -135612,10 +135613,10 @@ index 6a41231..cacde14 100644 CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_DRBD=m -From a767c3cb4c6604ad27b92a36644de098f8bdcabb Mon Sep 17 00:00:00 2001 +From cbdda3d7b1a65d7c6632d8f16cf04a0d5cbf4098 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Mon, 22 Jun 2015 16:27:07 +0100 -Subject: [PATCH 079/204] Add rpi-ft5406 overlay Add rpi-ft5406 driver as +Subject: [PATCH 079/278] Add rpi-ft5406 overlay Add rpi-ft5406 driver as module --- @@ -135702,10 +135703,10 @@ index cacde14..f952ff2 100644 CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y -From f13481ed18c0a520fc1776890d1066c1397b358f Mon Sep 17 00:00:00 2001 +From 4ab37825009c6c16ecb6a9c2a7df1a345f26264c Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 23 Jun 2015 09:53:40 +0100 -Subject: [PATCH 080/204] Fix driver detection failure Check that the buffer +Subject: [PATCH 080/278] Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected --- @@ -135726,10 +135727,10 @@ index f55151b..d41851d 100644 dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", request.tag.val); } -From 7b53303429e40fddef7ffeb405f898af16adf578 Mon Sep 17 00:00:00 2001 +From b01066ab66dca860c9945c684f7e47c57487812d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Jun 2015 13:24:01 +0100 -Subject: [PATCH 081/204] config: Enable 8250 serial port +Subject: [PATCH 081/278] config: Enable 8250 serial port --- arch/arm/configs/bcm2709_defconfig | 7 +++++++ @@ -135777,10 +135778,10 @@ index f952ff2..0c25d8b 100644 CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_BCM2835=m -From 1ae977a7312c852775ea4bd9da294d7010e42dff Mon Sep 17 00:00:00 2001 +From 412a2aa22a41480a5cd8c8a9e4d04a53ef7e7215 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Jun 2015 14:10:58 +0100 -Subject: [PATCH 082/204] config: Enable POWER_RESET_GPIO +Subject: [PATCH 082/278] config: Enable POWER_RESET_GPIO --- arch/arm/configs/bcm2709_defconfig | 2 ++ @@ -135814,10 +135815,10 @@ index 0c25d8b..e757db6 100644 CONFIG_THERMAL=y CONFIG_THERMAL_BCM2835=y -From 5c8ef44617382fa1fa35577714eb1d4e2e17b647 Mon Sep 17 00:00:00 2001 +From 98d15d42c04280aef66aff4046f56c5e3318c132 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 26 Jun 2015 17:37:38 +0100 -Subject: [PATCH 083/204] bcm2708-vcio: Remove restriction of only a single +Subject: [PATCH 083/278] bcm2708-vcio: Remove restriction of only a single instance being open We need more than one process to be able to use mailbox interface (e.g. HW cursor in fbturbo and hello_fft). @@ -135862,10 +135863,10 @@ index d91672b..06fb2c2f 100644 return 0; -From cc364b46f26d4d8fc925ab96616e2443f29a0a60 Mon Sep 17 00:00:00 2001 +From a71bb19d93713b3c541c083c24e86eb6d45c28c4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 26 Jun 2015 08:39:19 +0100 -Subject: [PATCH 084/204] BCM270X_DT: Create a "core" clock, use it for SPI and +Subject: [PATCH 084/278] BCM270X_DT: Create a "core" clock, use it for SPI and sdhost --- @@ -136016,10 +136017,10 @@ index b408ab4..897204a 100644 }; }; -From 18fdf653ca9b05f1e30a4e1cb6bb9320b6642ea9 Mon Sep 17 00:00:00 2001 +From c401db2817365906fc115b0dfc072c8da716e155 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 09:24:31 +0100 -Subject: [PATCH 085/204] BCM270X_DT: Add MCP7941X to i2c-rtc overlay +Subject: [PATCH 085/278] BCM270X_DT: Add MCP7941X to i2c-rtc overlay --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -136072,10 +136073,10 @@ index 6bccfdc..7052c71 100644 pcf8523 = <&pcf8523>,"status"; pcf8563 = <&pcf8563>,"status"; -From 4b29016b330d96063fcb94f935b2c0a18a3a3fde Mon Sep 17 00:00:00 2001 +From 8f8f098f97eb8082f9bd795b6a730942ba7ad9a9 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 24 Jun 2015 11:23:06 +0100 -Subject: [PATCH 086/204] dts/overlays: document DHT11 overlay +Subject: [PATCH 086/278] dts/overlays: document DHT11 overlay --- arch/arm/boot/dts/overlays/README | 8 ++++++++ @@ -136101,10 +136102,10 @@ index 425eb19..9406cf3 100644 -From a64baab36c2fea4043c2e862efd5f2ce979d3671 Mon Sep 17 00:00:00 2001 +From 9ec9b89d68946fbf8c25830d55071547760fde8b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 087/204] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 087/278] 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 @@ -136219,10 +136220,10 @@ index e5332f1..6e3fec2 100644 "%s: pm_power_off function already registered", __func__); -From 751f8f85e9ecb31382f4b15fbf04311da32bd403 Mon Sep 17 00:00:00 2001 +From 6adbb3dc7508aa8e58e1c70a507c6466f81bf429 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 17 Jun 2015 17:10:40 +0100 -Subject: [PATCH 088/204] BCM270x_DT: Default Compute Module i2c, i2s and spi +Subject: [PATCH 088/278] BCM270x_DT: Default Compute Module i2c, i2s and spi support --- @@ -136312,10 +136313,10 @@ index e82fcb2..af252bd 100755 }; }; -From 310ac993d7e597234de083f9e28a950beea57e05 Mon Sep 17 00:00:00 2001 +From b6368c9b7bc077242f2d596eeaac9aec63df13e3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 22 Jun 2015 14:21:55 +0100 -Subject: [PATCH 089/204] BCM270X_DT: Sort nodes by bus address, and +Subject: [PATCH 089/278] BCM270X_DT: Sort nodes by bus address, and consolidate aliases --- @@ -136557,10 +136558,10 @@ index 24fa849..ccb9c31 100644 &gpio { -From e2eb20fe73389475f652fa9ad78db6b9dc5fd780 Mon Sep 17 00:00:00 2001 +From 216d21fd3963c13e5847e43fa8c5c6a2e297cea6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 22 Jun 2015 14:23:03 +0100 -Subject: [PATCH 090/204] i2c-bcm2708/BCM270X_DT: Add support for I2C2 +Subject: [PATCH 090/278] i2c-bcm2708/BCM270X_DT: Add support for I2C2 The third I2C bus (I2C2) is normally reserved for HDMI use. Careless use of this bus can break an attached display - use with caution. @@ -136733,10 +136734,10 @@ index 8773203..7a24fbe 100644 goto out_free_bi; } -From 9845042a17cd1bfc818801e7a5793b00346bb242 Mon Sep 17 00:00:00 2001 +From 2b9cbc7f2e7593e2eb125b0f34ad2d03fcf1d96d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 29 Jun 2015 12:14:02 +0100 -Subject: [PATCH 091/204] BCM270X_DT: Correct the lirc-rpi overlay +Subject: [PATCH 091/278] BCM270X_DT: Correct the lirc-rpi overlay documentation The polarity of the "sense" parameter was inverted with respect to reality. @@ -136762,10 +136763,10 @@ index 0ed7094..ec762d2 100644 (default "-1") -From e75018d8c8385653326af3519474b108f0f74945 Mon Sep 17 00:00:00 2001 +From 9b2fe8a5ea1bac2e924fa6666db64cbe8b83d8ef Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 08:47:09 +0100 -Subject: [PATCH 092/204] bcm2835-sdhost: Further improve overclock back-off +Subject: [PATCH 092/278] bcm2835-sdhost: Further improve overclock back-off --- drivers/mmc/host/bcm2835-sdhost.c | 144 +++++++++++++++++++++----------------- @@ -137057,10 +137058,10 @@ index 6277e43..a03db06 100644 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -From 13cbc57aa3f9dd10bdc8dad7915626d1697c9903 Mon Sep 17 00:00:00 2001 +From 0cf94d9b94bbdd94e4a19163cddc5abe5381acb1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 10:28:59 +0100 -Subject: [PATCH 093/204] i2c-bcm2708: Increase timeouts to allow larger +Subject: [PATCH 093/278] i2c-bcm2708: Increase timeouts to allow larger transfers Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting @@ -137098,10 +137099,10 @@ index 7a24fbe..8b8762d 100644 dev_err(&adap->dev, "transfer timed out\n"); goto error_timeout; -From f7d430536dec32c07a6ba6eb7ed6167ff4974855 Mon Sep 17 00:00:00 2001 +From 1e8798376b1b70d8df42ba906ef5878ffcb903ab Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 10:33:52 +0100 -Subject: [PATCH 094/204] spi-bcm2708: Increase timeout from 150ms to 1s +Subject: [PATCH 094/278] spi-bcm2708: Increase timeout from 150ms to 1s See: https://github.com/raspberrypi/linux/issues/260 --- @@ -137125,10 +137126,10 @@ index 041b5e2..5c0214e 100644 struct bcm2708_spi { spinlock_t lock; -From 9f8135d6ddcbf9ab9dd9678249c3b8c5d17a9229 Mon Sep 17 00:00:00 2001 +From 0eed7dbb226536a9445fe1566a41a7a778691151 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 15 Jun 2015 09:59:38 +0100 -Subject: [PATCH 095/204] bcm2708-spi: Don't use static pin configuration with +Subject: [PATCH 095/278] bcm2708-spi: Don't use static pin configuration with DT Also remove superfluous error checking - the SPI framework ensures the @@ -137167,10 +137168,10 @@ index 5c0214e..781c747 100644 master = spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!master) { -From 8c4cdb44d24dba5443a6bc18b7729ba76967acaa Mon Sep 17 00:00:00 2001 +From 5644403b7733de2453b7b7ac763e57d44d6a36fe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 15 Jun 2015 10:10:59 +0100 -Subject: [PATCH 096/204] bcm2708-i2s: Don't use static pin configuration with +Subject: [PATCH 096/278] bcm2708-i2s: Don't use static pin configuration with DT --- @@ -137193,10 +137194,10 @@ index a515992..5e93cd6 100644 /* * Adjust the data length according to the format. -From 21f6968a52663113eab7b89f7cb192e92d8ea951 Mon Sep 17 00:00:00 2001 +From 4490f5e794c9149eb639c6aec401f3a98e0ec00d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 097/204] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 097/278] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -137216,10 +137217,10 @@ index b4fd8de..f459feb 100644 for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From afddc0087e5b1db8311454fa66909bc400151982 Mon Sep 17 00:00:00 2001 +From be547c10063a14396459e4e2c2546338d5a77847 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 26 Jun 2015 08:50:11 +0100 -Subject: [PATCH 098/204] BCM270X_DT: Add overlay to enable uart1 +Subject: [PATCH 098/278] BCM270X_DT: Add overlay to enable uart1 N.B. The UART1 clock is derived from the core clock. The firmware will update clock-frequency if core_freq is set, but be aware @@ -137388,10 +137389,10 @@ index e757db6..363c894 100644 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y -From 9b7dfacf1ff658c5aa03075776f71c8d6e16564e Mon Sep 17 00:00:00 2001 +From 3cd5a3b39286adbe2b423ce3dde7791242ba64e2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 099/204] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 099/278] 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 @@ -137472,10 +137473,10 @@ index a506773..cf3190f 100644 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From c26edc1513a5086a1a4e0c16746d52423b0259c8 Mon Sep 17 00:00:00 2001 +From 2b98853697886d2501c01c383539177fb5eb75a2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 17:37:38 +0100 -Subject: [PATCH 100/204] BCM270X_DT: Change pio_limit of sdhost driver to 1 +Subject: [PATCH 100/278] BCM270X_DT: Change pio_limit of sdhost driver to 1 --- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 +- @@ -137495,10 +137496,10 @@ index 897204a..2da14a4 100644 }; }; -From 83dda549d089cd0117282ec6edebd697fa59f173 Mon Sep 17 00:00:00 2001 +From f368064ae85f81c2d163da5ee7c77a4d94e283ed Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Jul 2015 12:51:52 +0100 -Subject: [PATCH 101/204] bcm2835-sdhost: Clear HBLC for PIO mode +Subject: [PATCH 101/278] bcm2835-sdhost: Clear HBLC for PIO mode Also update pio_limit default in overlay README. --- @@ -137534,10 +137535,10 @@ index a03db06..d65870a 100644 BUG_ON(!host->data); } -From ecdc3c6d8615d2f5df08e2514cb0b6b12be840e1 Mon Sep 17 00:00:00 2001 +From 68df77076b8e0f71af92240b40d16989716807bc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 3 Jul 2015 12:21:01 +0100 -Subject: [PATCH 102/204] BCM270X_DT: I2S needs function Alt2 +Subject: [PATCH 102/278] BCM270X_DT: I2S needs function Alt2 --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 2 +- @@ -137599,10 +137600,10 @@ index f25f0a2..62d1c62 100644 }; -From 906a4b80abdc53ea1369eb0ecf310a4b906d2f1c Mon Sep 17 00:00:00 2001 +From 585f0b76376a9b64a0c8908aec010a889357211e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:16:15 +0200 -Subject: [PATCH 103/204] configs: Incorporate v4.1 dependency changes +Subject: [PATCH 103/278] configs: Incorporate v4.1 dependency changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -137765,10 +137766,10 @@ index 363c894..80f84d7 100644 CONFIG_CRC_ITU_T=y CONFIG_LIBCRC32C=y -From 03edd2dd4b9c016f440383c9fae725f5c4e73eca Mon Sep 17 00:00:00 2001 +From 76e06d1c860c0d2ce97aa0cd689657cf649b73c8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 3 Jul 2015 15:47:33 +0100 -Subject: [PATCH 104/204] bcmrpi_defconfigs: Add SND_SOC_WM8804_I2C (for +Subject: [PATCH 104/278] bcmrpi_defconfigs: Add SND_SOC_WM8804_I2C (for HifiBerry Digi) 4.1 has split out support for the I2C and SPI variants, so it now @@ -137803,10 +137804,10 @@ index 80f84d7..14b91fdf 100644 CONFIG_SOUND_PRIME=m CONFIG_HIDRAW=y -From b1c7182dc37e87b47377b529de6e54a431fc07aa Mon Sep 17 00:00:00 2001 +From 08cb2a5643825c1dbe4e6817c523e100c7e90746 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Sat, 4 Jul 2015 19:55:23 +0100 -Subject: [PATCH 105/204] squash: BCM270X_DT: I2S only needs Alt2 on 28-31 +Subject: [PATCH 105/278] squash: BCM270X_DT: I2S only needs Alt2 on 28-31 See: https://github.com/raspberrypi/linux/issues/1046 --- @@ -137855,10 +137856,10 @@ index 62d1c62..f25f0a2 100644 }; -From b52bc261c9b3c08ac73aca166afb05090ffca7eb Mon Sep 17 00:00:00 2001 +From fe05ba5439e24590b4b1bc180b597bf8cb993d11 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 8 Jul 2015 14:48:57 +0100 -Subject: [PATCH 106/204] vchiq_arm: Two cacheing fixes +Subject: [PATCH 106/278] vchiq_arm: Two cacheing fixes 1) Make fragment size vary with cache line size Without this patch, non-cache-line-aligned transfers may corrupt @@ -138129,10 +138130,10 @@ index c739083..5edba23 100644 kfree(pagelist); } -From fc0a0a8a198ad39fa58dd4e2b3efba0a89a9d627 Mon Sep 17 00:00:00 2001 +From 7603d917647e2522d8067c0c6bcd9acc37f4b392 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 09:10:36 +0100 -Subject: [PATCH 107/204] BCM270X_DT: Overlay for the Fen Logic VGA666 board +Subject: [PATCH 107/278] BCM270X_DT: Overlay for the Fen Logic VGA666 board The VGA666 board requires GPIOs 2-21 (so no I2C or UART). Using the overlay (instead of a custom dt-blob.bin) has the advantage that it will @@ -138214,10 +138215,10 @@ index 0000000..7fcab96 + }; +}; -From c9eb6844bc315ee5ab2c807f873ca04d45fc6303 Mon Sep 17 00:00:00 2001 +From 8dea50173689a51c32610aea81198c7a0022519d Mon Sep 17 00:00:00 2001 From: petit-miner Date: Fri, 10 Jul 2015 13:59:18 +0200 -Subject: [PATCH 108/204] Added support for 2 mcp2515 CAN Bus IC +Subject: [PATCH 108/278] Added support for 2 mcp2515 CAN Bus IC See: https://github.com/raspberrypi/linux/issues/1018 https://github.com/raspberrypi/linux/pull/1049 @@ -138347,10 +138348,10 @@ index 0000000..6bef9ae + }; +}; -From 632d8b6abe925d8300a9c824856ea7c286d95229 Mon Sep 17 00:00:00 2001 +From f77141196c685ee3ec5781b190a042977ec5b868 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 5 May 2015 13:27:45 -0700 -Subject: [PATCH 109/204] mailbox: Enable BCM2835 mailbox support +Subject: [PATCH 109/278] mailbox: Enable BCM2835 mailbox support This mailbox driver provides a single mailbox channel to write 32-bit values to the VPU and get a 32-bit response. The Raspberry Pi @@ -138629,10 +138630,10 @@ index 0000000..4b13268 +MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); +MODULE_LICENSE("GPL v2"); -From d9468dc86cfdb7fed108e1e888979b622d578f71 Mon Sep 17 00:00:00 2001 +From 0abc1ba7051398796ce2f655bf52c3045e6b0253 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 13 May 2015 13:10:32 -0700 -Subject: [PATCH 110/204] mailbox/bcm2835: Fix mailbox full detection. +Subject: [PATCH 110/278] mailbox/bcm2835: Fix mailbox full detection. With the VC reader blocked and the ARM writing, MAIL0_STA reads empty permanently while MAIL1_STA goes from empty (0x40000000) to non-empty @@ -138671,10 +138672,10 @@ index 4b13268..0b47dd4 100644 return ret; } -From 518512c73c439f3684fbe42f07048b79be906f4a Mon Sep 17 00:00:00 2001 +From bd47b7bc661d21a2d73fcd8048ea69cf5eed854e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:19:30 +0200 -Subject: [PATCH 111/204] mailbox: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 111/278] mailbox: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -138790,10 +138791,10 @@ index 19b491d..cc07d71 100644 dev_dbg(dev, "%s: mailbox not free\n", __func__); mutex_unlock(&con_mutex); -From 69b0fd32b30439447e33723fde68aadaed7d9b42 Mon Sep 17 00:00:00 2001 +From 6990286fa34cb0dc7b5a89cb18045ee7c48237fc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 4 Jun 2015 13:11:47 -0700 -Subject: [PATCH 112/204] ARM: bcm2835: Add the firmware driver information to +Subject: [PATCH 112/278] ARM: bcm2835: Add the firmware driver information to the RPi DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -138827,10 +138828,10 @@ index 466f02b..5cdfd5a 100644 audio: audio { compatible = "brcm,bcm2835-audio"; -From 0438cbca296cfb3bc165b1f54c4e16f57f5760f0 Mon Sep 17 00:00:00 2001 +From 5584119926486bd13ba9a249d2bb7d3fcccf6b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:21:20 +0200 -Subject: [PATCH 113/204] firmware: bcm2835: Add missing property tags +Subject: [PATCH 113/278] firmware: bcm2835: Add missing property tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -138892,10 +138893,10 @@ index 9d9efb7..d3933af 100644 RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From 2df587b5e056fb8a0eba5efc2023533efb2807be Mon Sep 17 00:00:00 2001 +From fb58672855848cde55e4f6c7f66ccc2364c2ae58 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 114/204] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 114/278] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139001,10 +139002,10 @@ index dd506cd3..b980d53 100644 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From c9295b68944211995a84d596a904f9657b4482c6 Mon Sep 17 00:00:00 2001 +From c11b1cbade80f88de34bb774efd4332d5a7229e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:26:10 +0200 -Subject: [PATCH 115/204] firmware: bcm2835: Support legacy mailbox API +Subject: [PATCH 115/278] firmware: bcm2835: Support legacy mailbox API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139094,10 +139095,10 @@ index d3933af..9a08cf1 100644 u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, -From 2f10d2c9d55ec24c07d869e591d7db9fdde5dfa6 Mon Sep 17 00:00:00 2001 +From f45011102e9f4cda3eb313ba41d418bec61f059b 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 116/204] char: broadcom: Add vcio module +Subject: [PATCH 116/278] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139321,10 +139322,10 @@ index 0000000..c19bc20 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From 8bcd6e604c131b2009b0d9e47561cead558c3d82 Mon Sep 17 00:00:00 2001 +From 1878457cbd4737017a1d9c236160bd8e51274baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:37:19 +0200 -Subject: [PATCH 117/204] BCM270x: Switch to firmware driver +Subject: [PATCH 117/278] BCM270x: Switch to firmware driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139931,10 +139932,10 @@ index 06fb2c2f..2e4031b 100644 MODULE_DESCRIPTION("ARM I/O to VideoCore processor"); MODULE_LICENSE("GPL"); -From 51a7a4a822bc6ab6927bc0522e5afb6bda8f52b4 Mon Sep 17 00:00:00 2001 +From f199fb695244ef2c56baf961669481dceb1c5de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:39:21 +0200 -Subject: [PATCH 118/204] bcm2835: Switch to firmware driver +Subject: [PATCH 118/278] bcm2835: Switch to firmware driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139990,10 +139991,10 @@ index 47f2a6a..c284414 100644 CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y -From 46dd86c7b1dd676e614daca70ec3b7a31cc905f9 Mon Sep 17 00:00:00 2001 +From c44ca0bd5ac0fa61e25683079b78046afde9b609 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Jul 2015 13:25:31 +0100 -Subject: [PATCH 119/204] Merge pull request #1059 from pelwell/rpi-4.0.y +Subject: [PATCH 119/278] Merge pull request #1059 from pelwell/rpi-4.0.y w1_therm: Back-port locking improvements from 4.2-rc1 --- @@ -140188,10 +140189,10 @@ index 55eb86c..2f029e8 100644 { int err, i; -From 86a4624ee6bc33f41fd7f53d081096ed4aa28cca Mon Sep 17 00:00:00 2001 +From 98ab473b5499e7572b83b165fb1faad941b34ff6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 11:11:51 +0100 -Subject: [PATCH 120/204] vchiq_arm: Sort out the vmalloc case +Subject: [PATCH 120/278] vchiq_arm: Sort out the vmalloc case See: https://github.com/raspberrypi/linux/issues/1055 --- @@ -140230,10 +140231,10 @@ index 5edba23..56bff05 100644 *need_release = 0; /* do not try and release vmalloc pages */ } else { -From 18952e8ccf8d64fb32bb7b2bbd04967047f02840 Mon Sep 17 00:00:00 2001 +From 504380d8268a59d54123ec5276ec0a6ae2f78073 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 121/204] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 121/278] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -140254,10 +140255,10 @@ index 8fab566..a9db602 100644 }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 58f35e5dc8355250d21db3b7ba0aa560d76a0adc Mon Sep 17 00:00:00 2001 +From 50521168f2e04219e9274032b1352fffbc623366 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 122/204] Merge pull request #1043 from XECDesign/sense-4.0 +Subject: [PATCH 122/278] Merge pull request #1043 from XECDesign/sense-4.0 mfd: Add Raspberry Pi Sense HAT core driver --- @@ -141190,10 +141191,10 @@ index 0000000..56196dc + +#endif -From 7ec906836d03f54c2f62372c25a413af323c2564 Mon Sep 17 00:00:00 2001 +From 29bb619a239e455d18e9551bd3178cd2a200b056 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jul 2015 13:46:08 +0100 -Subject: [PATCH 123/204] leds-gpio: Implement the brightness_get method +Subject: [PATCH 123/278] leds-gpio: Implement the brightness_get method The power LED uses some clever logic that means it is driven by a voltage measuring circuit when configured as input, otherwise @@ -141236,10 +141237,10 @@ index 3cfbd6a..4e4e132 100644 state = !!gpiod_get_value_cansleep(led_dat->gpiod); else -From 0cfac48f6780a5038da6e0fc0e37dfc3975f2077 Mon Sep 17 00:00:00 2001 +From 1a2d904e7a40d547a5ccff5767d9c1ad690f5a08 Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Fri, 17 Jul 2015 09:50:55 +0200 -Subject: [PATCH 124/204] dmaengine: bcm2708-dmaengine: Fix memory leak when +Subject: [PATCH 124/278] dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer --- @@ -141259,10 +141260,10 @@ index 987ed53..73c6c00 100644 bcm2835_dma_abort(c->chan_base); -From 095268253a866ff43278ff24f4a7502949c6cf92 Mon Sep 17 00:00:00 2001 +From 7778211a9bc17f57bb07a1c66ffa8d4cd687f22f Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:13 +0200 -Subject: [PATCH 125/204] BCM270X_DT: Fix I2S register map +Subject: [PATCH 125/278] BCM270X_DT: Fix I2S register map --- arch/arm/boot/dts/bcm2708_common.dtsi | 4 ++-- @@ -141284,10 +141285,10 @@ index 2dd25f7..728e14a 100644 //dmas = <&dma 2>, // <&dma 3>; -From 649b011d757054ad6d9d5702f8d3bf670a42e404 Mon Sep 17 00:00:00 2001 +From d18f5eacd5bd806b85a6d5251f42abcd7163ff0e Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 126/204] BCM2835_DT: Fix I2S register map +Subject: [PATCH 126/278] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -141341,10 +141342,10 @@ index 4a63704..1135120 100644 dmas = <&dma 2>, <&dma 3>; -From 5076ca8360f9ad0d46a060fcde7eefe7fb10eea1 Mon Sep 17 00:00:00 2001 +From 4dcfd42ad88596da2d80b03c0177534e43aa5ba8 Mon Sep 17 00:00:00 2001 From: David Frey Date: Tue, 14 Jul 2015 15:57:36 +0200 -Subject: [PATCH 127/204] config: Enable SHT drivers for raspberry pi +Subject: [PATCH 127/278] config: Enable SHT drivers for raspberry pi The SHT temperature and humidity sensors are often used in weather station projects. @@ -141386,10 +141387,10 @@ index b9b5bdf..7b24274 100644 CONFIG_THERMAL_BCM2835=y CONFIG_WATCHDOG=y -From 2e23dd0be7034e7aee9795288d9de1ed151ad5fd Mon Sep 17 00:00:00 2001 +From 5494637b49c6566e5194466943058f3c746e6fcb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 14:07:14 +0100 -Subject: [PATCH 128/204] BCM270X_DT: Correct typo in overlays/README +Subject: [PATCH 128/278] BCM270X_DT: Correct typo in overlays/README --- arch/arm/boot/dts/overlays/README | 2 +- @@ -141409,10 +141410,10 @@ index 8792f98..ed484ae 100644 i2c_arm Set to "on" to enable the ARM's i2c interface -From dc0a5bcc935ccc881fb4043dc949af755d3e8f1c Mon Sep 17 00:00:00 2001 +From 0b9e10a4f393083b470d2498cc36bf96c5874b58 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 10:53:26 +0100 -Subject: [PATCH 129/204] bcm2835-sdhost: Add the ERASE capability +Subject: [PATCH 129/278] bcm2835-sdhost: Add the ERASE capability See: https://github.com/raspberrypi/linux/issues/1076 --- @@ -141433,10 +141434,10 @@ index d65870a..57a6ad3 100644 spin_lock_init(&host->lock); -From 54ef0643fae43fff2cb1583919a34f787ad132af Mon Sep 17 00:00:00 2001 +From a7e50e9d4ea5809bea8cbff68a0ac5982d262744 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 17:32:18 +0100 -Subject: [PATCH 130/204] bcm2835-sdhost: Ignore CRC7 for MMC CMD1 +Subject: [PATCH 130/278] bcm2835-sdhost: Ignore CRC7 for MMC CMD1 It seems that the sdhost interface returns CRC7 errors for CMD1, which is the MMC-specific SEND_OP_COND. Returning these errors to @@ -141500,10 +141501,10 @@ index 57a6ad3..84f645f 100644 if (host->cmd->flags & MMC_RSP_PRESENT) { -From 24f4ffb4f7a2f5b37197a168485207216b736adb Mon Sep 17 00:00:00 2001 +From bfc887c5a51aed2b54bb7ec3350b60f241f62740 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 14:48:21 +0100 -Subject: [PATCH 131/204] BCM270X_DT: Add unit address to gpio node name +Subject: [PATCH 131/278] BCM270X_DT: Add unit address to gpio node name --- arch/arm/boot/dts/bcm2708_common.dtsi | 2 +- @@ -141523,10 +141524,10 @@ index 728e14a..cb608df 100644 reg = <0x7e200000 0xb4>; interrupts = <2 17>, <2 18>; -From 7d633f69a6cbc12d37782f6ab96e402eb1b18949 Mon Sep 17 00:00:00 2001 +From 17c28653e1dd93b3f85bc9603db780a20e433d5c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 24 Jul 2015 10:36:32 +0100 -Subject: [PATCH 132/204] BCM270X_DT: Use i2c_arm for rtc and bmp085 overlays +Subject: [PATCH 132/278] BCM270X_DT: Use i2c_arm for rtc and bmp085 overlays --- arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts | 2 +- @@ -141560,10 +141561,10 @@ index 7052c71..fed4bd8 100644 #address-cells = <1>; #size-cells = <0>; -From 70694a4073fa62862c93ab409b49d3d86071a6c0 Mon Sep 17 00:00:00 2001 +From 0caf9d051a535a8ae01f2bb4d7ebbf870eda68f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 24 Jul 2015 12:11:31 +0100 -Subject: [PATCH 133/204] BCM2708_DT: CM dtparams for audio, watchdog and RNG +Subject: [PATCH 133/278] BCM2708_DT: CM dtparams for audio, watchdog and RNG --- arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 8 ++++---- @@ -141593,10 +141594,10 @@ index 34d4bc6..713e5a2 100644 }; }; -From a36ecdc70162e181fac2f7b7afb952639df22384 Mon Sep 17 00:00:00 2001 +From 9393cd2eb6a2e5cb43b226c48e7562a20bdde6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:13:18 +0200 -Subject: [PATCH 134/204] vchiq: Use firmware API +Subject: [PATCH 134/278] vchiq: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -141712,10 +141713,10 @@ index 31e2cba..e11c0e0 100644 err = vchiq_debugfs_init(); if (err != 0) -From 97df14a49141d2831362aac3d18875d271b1a97f Mon Sep 17 00:00:00 2001 +From 11c9e83521909809bf0dd53860e31a1de18b2774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:17:10 +0200 -Subject: [PATCH 135/204] thermal: bcm2835: Use firmware API +Subject: [PATCH 135/278] thermal: bcm2835: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -141998,10 +141999,10 @@ index 3bc80f1..c1d8f1b 100644 -module_platform_driver(bcm2835_thermal_driver); +MODULE_LICENSE("GPL"); -From c2e3b884a9498adb58d4d403465e2d99ddd79e61 Mon Sep 17 00:00:00 2001 +From ea78d55755fd86c6dd39a084f941a0f0c7547944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:18:36 +0200 -Subject: [PATCH 136/204] cpufreq: bcm2835: Use firmware API +Subject: [PATCH 136/278] cpufreq: bcm2835: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142185,10 +142186,10 @@ index 6735da9..3eb9e93 100644 } -From 1ef7396bd8f7fa5452d762b9c534552604c0ec35 Mon Sep 17 00:00:00 2001 +From b33aacadbb1c946cda4904762fd659e491202a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:20:59 +0200 -Subject: [PATCH 137/204] fbdev: bcm2708: Use firmware API +Subject: [PATCH 137/278] fbdev: bcm2708: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142604,10 +142605,10 @@ index f6ac7da..06a96d16 100644 free_irq(fb->dma_irq, fb); -From e24a0ff68aeded060486f55911653aec60ea87c7 Mon Sep 17 00:00:00 2001 +From 06ef9603501eaa19b408f0dcb2256de4cd607a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:27:17 +0200 -Subject: [PATCH 138/204] bcm2835: Add firmware property to affected devices +Subject: [PATCH 138/278] bcm2835: Add firmware property to affected devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142688,10 +142689,10 @@ index 1135120..807264d 100644 clocks { -From 4fa2f3a62adf17ef122476d8fc63b132a717d71f Mon Sep 17 00:00:00 2001 +From 763f71573d07480bb1d8f2f99eeb878f7c44f8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 21 Jul 2015 19:09:39 +0200 -Subject: [PATCH 139/204] rpi-ft5406: Use firmware API +Subject: [PATCH 139/278] rpi-ft5406: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142831,10 +142832,10 @@ index d41851d..c08817e 100644 ts->regs = (struct ft5406_regs *) ts->ts_base; -From 70b5d66ef90adc3ee74708ecf15fd5fd3c6a3f9e Mon Sep 17 00:00:00 2001 +From 65b515748a861ae662ac45b5d3a989f044cfde56 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 140/204] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 140/278] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142966,10 +142967,10 @@ index 5916d6c..db66246 100644 } -From 48ff5ec47ad9778a6d2eb5d75ee2e161302673fa Mon Sep 17 00:00:00 2001 +From c8650561dc2a36e433e769a9abb6e23c68a1242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 15:50:04 +0200 -Subject: [PATCH 141/204] dwc_otg: Add ARCH_BCM2835 support +Subject: [PATCH 141/278] dwc_otg: Add ARCH_BCM2835 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143022,10 +143023,10 @@ index 0f4ebcd..5c83309 100644 } -From 28a1fd2b8afaf5524cca8890394f9fc07c8a8b71 Mon Sep 17 00:00:00 2001 +From da4400c6f9f667118be6d6b84f5277631479a526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 15:50:24 +0200 -Subject: [PATCH 142/204] bcm2835: Use DWC_OTG +Subject: [PATCH 142/278] bcm2835: Use DWC_OTG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143068,10 +143069,10 @@ index c284414..14ef294 100644 CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From cf7a056866fba1d602de661a47cd0548dfe2304b Mon Sep 17 00:00:00 2001 +From 1b7fdbfce8a0b6d481783f7b58aeb3a5d0018efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:33:16 +0200 -Subject: [PATCH 143/204] Fix RASPBERRYPI_FIRMWARE dependents +Subject: [PATCH 143/278] Fix RASPBERRYPI_FIRMWARE dependents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143152,10 +143153,10 @@ index b89998b7..08678b9 100644 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT -From 16b9943dbfbc7d7f19f44e91808dc1450ca9d4b4 Mon Sep 17 00:00:00 2001 +From 08e28b36aa1f14a39c8f61e9be0cb8776c7128f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:33:46 +0200 -Subject: [PATCH 144/204] vc_mem: Remove unnecessary include +Subject: [PATCH 144/278] vc_mem: Remove unnecessary include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143178,10 +143179,10 @@ index fcde6b1..be64f23 100644 #define DRIVER_NAME "vc-mem" -From d98428b8e2a5bb9815aaa3eed3e0777f50f55196 Mon Sep 17 00:00:00 2001 +From 90ad3d4c3ed68a9524942c6bc46e7d0ed6503f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:06 +0200 -Subject: [PATCH 145/204] configs: Remove BCM2708_MBOX +Subject: [PATCH 145/278] configs: Remove BCM2708_MBOX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143230,10 +143231,10 @@ index 7b24274..0859113 100644 # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXTCON=m -From b3b0ebfd9dd4bcd6fe8d787aa7740a47f419da9f Mon Sep 17 00:00:00 2001 +From 5390f1521dd8fcef75cd21e26543be02370af6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:31 +0200 -Subject: [PATCH 146/204] bcm2708-vcio: Remove module +Subject: [PATCH 146/278] bcm2708-vcio: Remove module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143507,10 +143508,10 @@ index d3ea839..0000000 - -#endif -From 6fadac31b6bf0690059342642ff4453d6d95a2d8 Mon Sep 17 00:00:00 2001 +From 2beb16e7abcd4faf212d69fc89291ec75909e8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:55 +0200 -Subject: [PATCH 147/204] Revert "firmware: bcm2835: Support legacy mailbox +Subject: [PATCH 147/278] Revert "firmware: bcm2835: Support legacy mailbox API" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -143601,10 +143602,10 @@ index 9a08cf1..d3933af 100644 u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, -From 9418fab5167ef4095a62ba3b11d9e420595cf559 Mon Sep 17 00:00:00 2001 +From cf926787c9db379504cb78d2cf65dc1283665591 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Tue, 30 Jun 2015 12:35:39 +0100 -Subject: [PATCH 148/204] pinctrl: bcm2835: Clear the event latch register when +Subject: [PATCH 148/278] pinctrl: bcm2835: Clear the event latch register when disabling interrupts It's possible to hit a race condition if interrupts are generated on a GPIO @@ -143641,10 +143642,10 @@ index 986779a..61ef002 100644 spin_unlock_irqrestore(&pc->irq_lock[bank], flags); } -From 1a099cd189c09d3dc5d2e0ed2061cb9b0dcd2a0b Mon Sep 17 00:00:00 2001 +From 74345136dd3f9bee648635995c25f88def12cfa9 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 4 Aug 2015 01:15:20 +0100 -Subject: [PATCH 149/204] dwc_otg: fiq_fsm: Make high-speed isochronous strided +Subject: [PATCH 149/278] dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly Certain low-bandwidth high-speed USB devices (specialist audio devices, @@ -143784,10 +143785,10 @@ index 3f71f29..8db3dfc 100644 case FIQ_PER_SPLIT_LS_ABORTED: -From 671205b0f0ec871b8fcabbab6d9a2ffb3444378c Mon Sep 17 00:00:00 2001 +From ae470066222c5f32ef5172fd12ff5027b11f5d6f Mon Sep 17 00:00:00 2001 From: Uli Middelberg Date: Wed, 17 Jun 2015 10:36:56 +0200 -Subject: [PATCH 150/204] added basic docker support +Subject: [PATCH 150/278] added basic docker support --- arch/arm/configs/bcm2709_defconfig | 3 +++ @@ -143851,10 +143852,10 @@ index 0859113..06e7529 100644 CONFIG_FSCACHE_STATS=y CONFIG_FSCACHE_HISTOGRAM=y -From 1621191b72eef418410908e1b789381f2956275e Mon Sep 17 00:00:00 2001 +From 1c1c7183d63895d394e79eaf0971801ca5ec005d Mon Sep 17 00:00:00 2001 From: Garrett Date: Thu, 2 Jul 2015 19:32:04 -0500 -Subject: [PATCH 151/204] bcm2835 camera planar/packed stride length +Subject: [PATCH 151/278] bcm2835 camera planar/packed stride length Added a field to the mmal_fmt struct used to compute the bytes per line when using a particular format. This results in the correct stride being @@ -144026,10 +144027,10 @@ index 35698c8..15788a1 100644 /* buffer for one video frame */ -From 86b0488fa249c00bd7c381fe637026a7f33a6ffa Mon Sep 17 00:00:00 2001 +From c172a7453e174a470f4642fa1ad37195d96a6611 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 17 Aug 2015 10:49:44 +0100 -Subject: [PATCH 154/204] BCM270X_DT: Add pwm and pwm-2chan overlays +Subject: [PATCH 154/278] BCM270X_DT: Add pwm and pwm-2chan overlays From the README entries: Legal pin,function combinations for each channel: @@ -144295,10 +144296,10 @@ index b1541f4..90591a9 100644 PWM framework driver for BCM2835 controller (Raspberry Pi) -From 0d1f86de027a4406151de275663b2cb68d3b39f5 Mon Sep 17 00:00:00 2001 +From 4b1505ce4c7c75ad68164fb46a5384cf1e8f4d7c Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Apr 2015 07:33:03 +0000 -Subject: [PATCH 155/204] spi: bcm2835: fallback to interrupt for polling +Subject: [PATCH 155/278] spi: bcm2835: fallback to interrupt for polling timeouts exceeding 2 jiffies The polling mode of the driver is designed for transfers that run @@ -144434,10 +144435,10 @@ index cf3190f..505a993 100644 struct spi_device *spi, struct spi_transfer *tfr) -From 9a96e7390f5bb3db6138d07ffe6145c17e53246d Mon Sep 17 00:00:00 2001 +From 2fead4f30a07f85c28e730c4d41332c8c9ba2eca Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Sun, 10 May 2015 20:47:28 +0000 -Subject: [PATCH 156/204] spi: bcm2835: enable dma modes for transfers meeting +Subject: [PATCH 156/278] spi: bcm2835: enable dma modes for transfers meeting certain conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -144860,10 +144861,10 @@ index 505a993..27fb5b0 100644 } -From 6e92fd1644001ba7827e2706c0ed4fd4c2d85bc1 Mon Sep 17 00:00:00 2001 +From 93ff62a97a33f9de56bcd1cc3c9ceddbe49836a8 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 12 May 2015 10:32:08 +0000 -Subject: [PATCH 157/204] spi: bcm2835: fix kbuild compile warnings/errors and +Subject: [PATCH 157/278] spi: bcm2835: fix kbuild compile warnings/errors and a typo fixes several warnings/error emmitted by the kbuild system: @@ -144919,10 +144920,10 @@ index 27fb5b0..52aaf2d 100644 "Unaligned spi tx-transfer bridging page\n"); return false; -From 63ad0b9f2b638c3968473d46f732de9f28ad184b Mon Sep 17 00:00:00 2001 +From b2a51b3e348bab5c16db54e6071256519cf642b7 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 12 May 2015 19:43:59 +0800 -Subject: [PATCH 158/204] spi: bcm2835: bcm2835_dma_release() can be static +Subject: [PATCH 158/278] spi: bcm2835: bcm2835_dma_release() can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown @@ -144954,10 +144955,42 @@ index 52aaf2d..bad36c5 100644 struct dma_slave_config slave_config; const __be32 *addr; -From f3260b7d15164b1ddd0f080592defb79949db0aa Mon Sep 17 00:00:00 2001 +From b001cd6a6bebdbfbca679e60c090d7f9a964f231 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Wed, 22 Jul 2015 07:43:28 +0000 +Subject: [PATCH 159/278] spi: bcm2835: fixed compile issues due to embedded + comments... replaced with #if to avoid issues in the future. + +Signed-off-by: Martin Sperl +--- + drivers/spi/spi-bcm2835.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index bad36c5..b5c1123 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -609,6 +609,7 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, + return 0; + } + ++#if 0 + static void bcm2835_spi_handle_err(struct spi_master *master, + struct spi_message *msg) + { +@@ -623,6 +624,7 @@ static void bcm2835_spi_handle_err(struct spi_master *master, + /* and reset */ + bcm2835_spi_reset_hw(master); + } ++#endif + + static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { + +From 04e67d061baea0c514289df9157e7a8e7be9adf5 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Jul 2015 08:34:41 +0000 -Subject: [PATCH 159/204] dt-overlay to enable dma for spi driver +Subject: [PATCH 160/278] dt-overlay to enable dma for spi driver Signed-off-by: Martin Sperl --- @@ -145005,10 +145038,10 @@ index 0000000..266cf9d + }; + }; -From 67c4106248a6d4eaee1de239e8f18da5e08ed8fd Mon Sep 17 00:00:00 2001 +From 16f8343e27b8392174402c99535b6e9ef845b1c4 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Jul 2015 12:41:54 +0000 -Subject: [PATCH 160/204] dt: overlay: added documentation of spi-dma overlay +Subject: [PATCH 161/278] dt: overlay: added documentation of spi-dma overlay Signed-off-by: Martin Sperl --- @@ -145033,10 +145066,10 @@ index 1cd2140..bda8c14 100644 Info: 3.5" Color TFT Display by www.tinylcd.com Options: Touch, RTC, keypad -From 1981274d8b58c613e5f3f0f40068f25ffcdbe481 Mon Sep 17 00:00:00 2001 +From 444bb34e3561106d475c4b5a001e2b6df5994697 Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Mon, 17 Aug 2015 18:06:16 +0100 -Subject: [PATCH 161/204] rpisense-fb: add low-light mode and gamma control +Subject: [PATCH 162/278] rpisense-fb: add low-light mode and gamma control --- drivers/video/fbdev/rpisense-fb.c | 68 +++++++++++++++++++++++++++++--- @@ -145179,10 +145212,40 @@ index c4c1118..2ba95d7 100644 struct rpisense; -From 82bd9aca8c50e84e17b9c62a6d5c528aa8f0e490 Mon Sep 17 00:00:00 2001 +From f1feb5092241c6dacd666e9adb344c2308ba8a52 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 18 Aug 2015 11:50:03 +0100 +Subject: [PATCH 163/278] spi: bcm2835: Fix buld error from previous commit + +--- + drivers/spi/spi-bcm2835.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index b5c1123..bad36c5 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -609,7 +609,6 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, + return 0; + } + +-#if 0 + static void bcm2835_spi_handle_err(struct spi_master *master, + struct spi_message *msg) + { +@@ -624,7 +623,6 @@ static void bcm2835_spi_handle_err(struct spi_master *master, + /* and reset */ + bcm2835_spi_reset_hw(master); + } +-#endif + + static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { + +From d68e70e1282e2621a355638c4a67d3a7f6254b43 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 19 Aug 2015 11:38:10 +0100 -Subject: [PATCH 162/204] BCM270X_DT: README - add note on indentation +Subject: [PATCH 164/278] BCM270X_DT: README - add note on indentation --- arch/arm/boot/dts/overlays/README | 4 ++++ @@ -145204,10 +145267,10 @@ index bda8c14..ac9c427 100644 Info: Configures the base Raspberry Pi hardware Load: -From b6277bf87e266469ee14448d41209f79f3caa8d1 Mon Sep 17 00:00:00 2001 +From 5c922b5c3dfd8ae456c532a41f403f3ebe443551 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 20 Aug 2015 13:50:18 +0100 -Subject: [PATCH 163/204] bcm2708-dmaengine: Use more DMA channels (but not 12) +Subject: [PATCH 165/278] bcm2708-dmaengine: Use more DMA channels (but not 12) 1) Only the bcm2708_fb drivers uses the legacy DMA API, and it requires a BULK-capable channel, so all other types @@ -145381,10 +145444,521 @@ index 73c6c00..85ce18b 100644 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) -From 72de9ce92b348a0f4f9230affa0e27d3f775342e Mon Sep 17 00:00:00 2001 +From b05ddc77a21e746431e6b81adfe0a0bf86d6c48b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 11 Jul 2015 18:48:10 +0200 +Subject: [PATCH 166/278] staging: fbtft: Add reset to fbtft_init_display_dt() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When an init sequence is present in the Device Tree, +fbtft_init_display_dt() is used to initialize the display. +Add missing reset function call and activation of +chip select for parallel bus. + +Signed-off-by: Noralf Trønnes +--- + drivers/staging/fbtft/fbtft-core.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c +index 53b748b..4f165d3 100644 +--- a/drivers/staging/fbtft/fbtft-core.c ++++ b/drivers/staging/fbtft/fbtft-core.c +@@ -1074,6 +1074,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) + p = of_prop_next_u32(prop, NULL, &val); + if (!p) + return -EINVAL; ++ ++ par->fbtftops.reset(par); ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ + while (p) { + if (val & FBTFT_OF_INIT_CMD) { + val &= 0xFFFF; + +From cd43f83e67e7e0917052444966f737ab896f41f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 19 Jul 2015 18:57:06 +0200 +Subject: [PATCH 167/278] BCM270X_DT: mz61581: Revert to spi-bcm2708 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The MZ61581 display does not work with spi-bcm2835 and software +chip select. It works before the commit: +spi: bcm2835: transform native-cs to gpio-cs on first spi_setup + +Revert to spi-bcm2708 until the cause has been detected and the +issue resolved. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index c06fe12..f674a66 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -12,6 +12,8 @@ + fragment@0 { + target = <&spi0>; + __overlay__ { ++ /* does not work with spi-bcm2835 using software chip selects */ ++ compatible = "brcm,bcm2708-spi"; + status = "okay"; + + spidev@0{ + +From d1dc22f2e8fefa9069ada02c2e66c6bfc4a7809a Mon Sep 17 00:00:00 2001 +From: Luke Wren +Date: Fri, 21 Aug 2015 23:14:48 +0100 +Subject: [PATCH 168/278] Add /dev/gpiomem device for rootless user GPIO access + +Signed-off-by: Luke Wren +--- + arch/arm/boot/dts/bcm2708.dtsi | 6 + + arch/arm/boot/dts/bcm2709.dtsi | 6 + + drivers/char/broadcom/Kconfig | 9 ++ + drivers/char/broadcom/Makefile | 3 + + drivers/char/broadcom/bcm2835-gpiomem.c | 265 ++++++++++++++++++++++++++++++++ + 5 files changed, 289 insertions(+) + create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c + +diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +index 0d47427..3bed0a6 100644 +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -15,5 +15,11 @@ + arm-pmu { + compatible = "arm,arm1176-pmu"; + }; ++ ++ gpiomem { ++ compatible = "brcm,bcm2835-gpiomem"; ++ reg = <0x7e200000 0x1000>; ++ status = "okay"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi +index 5e0b935..811d825 100644 +--- a/arch/arm/boot/dts/bcm2709.dtsi ++++ b/arch/arm/boot/dts/bcm2709.dtsi +@@ -16,6 +16,12 @@ + compatible = "arm,cortex-a7-pmu"; + interrupts = <3 9>; + }; ++ ++ gpiomem { ++ compatible = "brcm,bcm2835-gpiomem"; ++ reg = <0x7e200000 0x1000>; ++ status = "okay"; ++ }; + }; + + timer { +diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig +index fc40846..bc2eb1e 100644 +--- a/drivers/char/broadcom/Kconfig ++++ b/drivers/char/broadcom/Kconfig +@@ -38,3 +38,12 @@ config BCM_VC_SM + help + Support for the VC shared memory on the Broadcom reference + design. Uses the VCHIQ stack. ++ ++config BCM2835_DEVGPIOMEM ++ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835" ++ default m ++ help ++ Provides users with root-free access to the GPIO registers ++ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. ++ +diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile +index 18171e2..664e2c4 100644 +--- a/drivers/char/broadcom/Makefile ++++ b/drivers/char/broadcom/Makefile +@@ -2,3 +2,6 @@ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o + obj-$(CONFIG_BCM_VCIO) += vcio.o + obj-$(CONFIG_BCM_VC_SM) += vc_sm/ ++ ++obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o ++ +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +new file mode 100644 +index 0000000..0085e13 +--- /dev/null ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -0,0 +1,265 @@ ++/** ++ * GPIO memory device driver ++ * ++ * Creates a chardev /dev/gpiomem which will provide user access to ++ * the BCM2835's GPIO registers when it is mmap()'d. ++ * No longer need root for user GPIO access, but without relaxing permissions ++ * on /dev/mem. ++ * ++ * Written by Luke Wren ++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "bcm2835-gpiomem" ++#define DRIVER_NAME "gpiomem-bcm2835" ++#define DEVICE_MINOR 0 ++ ++struct bcm2835_gpiomem_instance { ++ unsigned long gpio_regs_phys; ++ struct device *dev; ++}; ++ ++static struct cdev bcm2835_gpiomem_cdev; ++static dev_t bcm2835_gpiomem_devid; ++static struct class *bcm2835_gpiomem_class; ++static struct device *bcm2835_gpiomem_dev; ++static struct bcm2835_gpiomem_instance *inst; ++ ++ ++/**************************************************************************** ++* ++* GPIO mem chardev file ops ++* ++***************************************************************************/ ++ ++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; ++ } ++ return ret; ++} ++ ++static int bcm2835_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ /* Ignore what the user says - they're getting the GPIO regs ++ whether they like it or not! */ ++ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT; ++ ++ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page, ++ PAGE_SIZE, ++ vma->vm_page_prot); ++ vma->vm_ops = &bcm2835_gpiomem_vm_ops; ++ if (remap_pfn_range(vma, vma->vm_start, ++ gpio_page, ++ PAGE_SIZE, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++static const struct file_operations ++bcm2835_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = bcm2835_gpiomem_open, ++ .release = bcm2835_gpiomem_release, ++ .mmap = bcm2835_gpiomem_mmap, ++}; ++ ++ ++ /**************************************************************************** ++* ++* Probe and remove functions ++* ++***************************************************************************/ ++ ++ ++static int bcm2835_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err; ++ void *ptr_err; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct resource *ioresource; ++ ++ /* Allocate buffers and instance data */ ++ ++ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL); ++ ++ if (!inst) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ ++ inst->dev = dev; ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&bcm2835_gpiomem_devid, ++ DEVICE_MINOR, 1, DEVICE_NAME); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops); ++ bcm2835_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); ++ ptr_err = bcm2835_gpiomem_class; ++ if (IS_ERR(ptr_err)) ++ goto failed_class_create; ++ ++ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL, ++ bcm2835_gpiomem_devid, NULL, ++ "gpiomem"); ++ ptr_err = bcm2835_gpiomem_dev; ++ if (IS_ERR(ptr_err)) ++ goto failed_device_create; ++ ++ /* Get address from device tree if available (*_resource() correctly ++ converts the bus address in device tree to a physical address), ++ or use hardcoded offset + BCM2708_PERI_BASE if not. ++ (In spite of its name 2708 actually seems to have the correct ++ mach-dependent value on 2709 etc, as it is defined in ++ mach-bcm270x/platform.h) */ ++ ++ if (node) { ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ inst->gpio_regs_phys = GPIO_BASE; ++ } ++ ++ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", ++ inst->gpio_regs_phys); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(bcm2835_gpiomem_class); ++failed_class_create: ++ cdev_del(&bcm2835_gpiomem_cdev); ++ err = PTR_ERR(ptr_err); ++failed_cdev_add: ++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); ++failed_alloc_chrdev: ++ kfree(inst); ++failed_inst_alloc: ++ dev_err(inst->dev, "could not load bcm2835_gpiomem"); ++ return err; ++} ++ ++static int bcm2835_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = inst->dev; ++ ++ kfree(inst); ++ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid); ++ class_destroy(bcm2835_gpiomem_class); ++ cdev_del(&bcm2835_gpiomem_cdev); ++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); ++ ++ dev_info(dev, "GPIO mem driver removed - OK"); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Register the driver with device tree ++* ++***************************************************************************/ ++ ++static const struct of_device_id bcm2835_gpiomem_of_match[] = { ++ {.compatible = "brcm,bcm2835-gpiomem",}, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match); ++ ++static struct platform_driver bcm2835_gpiomem_driver = { ++ .probe = bcm2835_gpiomem_probe, ++ .remove = bcm2835_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = bcm2835_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(bcm2835_gpiomem_driver); ++ ++MODULE_ALIAS("platform:gpiomem-bcm2835"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); ++MODULE_AUTHOR("Luke Wren "); + +From 30390d79fb7c138010adb59ee24420b0db1bd025 Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Mon, 24 Aug 2015 16:02:34 +0100 +Subject: [PATCH 169/278] tpa6130a2: Add headphone switch control + +Signed-off-by: Jan Grulich +--- + sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c +index 6fac9e0..f60ebe1c 100644 +--- a/sound/soc/codecs/tpa6130a2.c ++++ b/sound/soc/codecs/tpa6130a2.c +@@ -4,6 +4,7 @@ + * Copyright (C) Nokia Corporation + * + * Author: Peter Ujfalusi ++ * Modified: Jan Grulich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -52,6 +53,8 @@ struct tpa6130a2_data { + enum tpa_model id; + }; + ++static void tpa6130a2_channel_enable(u8 channel, int enable); ++ + static int tpa6130a2_i2c_read(int reg) + { + struct tpa6130a2_data *data; +@@ -189,7 +192,7 @@ static int tpa6130a2_power(u8 power) + } + + static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) ++ struct snd_ctl_elem_value *ucontrol) + { + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; +@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, + } + + static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) ++ struct snd_ctl_elem_value *ucontrol) + { + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; +@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, + return 1; + } + ++static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ int enable = ucontrol->value.integer.value[0]; ++ unsigned int state; ++ ++ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0; ++ if (state == enable) ++ return 0; /* No change */ ++ ++ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable); ++ return 1; /* Changed */ ++} ++ + /* +- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going ++ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going + * down in gain. + */ + static const unsigned int tpa6130_tlv[] = { +@@ -278,6 +295,9 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { + TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, + tpa6130a2_get_volsw, tpa6130a2_put_volsw, + tpa6130_tlv), ++ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch", ++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, ++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), + }; + + static const unsigned int tpa6140_tlv[] = { +@@ -292,6 +312,9 @@ static const struct snd_kcontrol_new tpa6140a2_controls[] = { + TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, + tpa6130a2_get_volsw, tpa6130a2_put_volsw, + tpa6140_tlv), ++ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch", ++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, ++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), + }; + + /* + +From 520c391058dfa211d8886ffc7445d39970c8f8b3 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 164/204] RaspiDAC3 support +Subject: [PATCH 170/278] RaspiDAC3 support Signed-off-by: Jan Grulich --- @@ -145735,10 +146309,10 @@ index 0000000..fddaeec +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From 5639b22eb081048b07152c5bd90d25d7768cb1cf Mon Sep 17 00:00:00 2001 +From 754681b13bca3e13c25d634b712206ed1e025827 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 14 Jul 2015 16:55:02 +0100 -Subject: [PATCH 165/204] config: Add SND_SOC_ADAU1701 module +Subject: [PATCH 171/278] config: Add SND_SOC_ADAU1701 module --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -145770,10 +146344,10 @@ index 8979f23..7dd4fd4 100644 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 6a0f88404b8cc24c073b1d157be02fbc9007788a Mon Sep 17 00:00:00 2001 +From 7ee6b5002a6d79f7e417b3df39a58cfcff6e35ca Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 29 Jul 2015 07:34:10 +0000 -Subject: [PATCH 166/204] spi: bcm2835: fix overflow in calculation of transfer +Subject: [PATCH 172/278] spi: bcm2835: fix overflow in calculation of transfer time This resulted in the use of polling mode when other approaches @@ -145826,10 +146400,10 @@ index bad36c5..b68991c 100644 /* for short requests run polling*/ if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) -From 74f48a53e476a7d34ab0a58c883149b19e5bbdec Mon Sep 17 00:00:00 2001 +From 7a0645687fefdfaa92960e349f54c477e6918061 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Sep 2015 15:14:50 +0100 -Subject: [PATCH 167/204] BCM270X_DT: Add SDIO overlay +Subject: [PATCH 173/278] BCM270X_DT: Add SDIO overlay Enable SDIO from MMC interface via GPIOs 22-27. Includes the sdhost overlay to free up the MMC interface. @@ -145914,521 +146488,10 @@ index 0000000..164f269 + }; +}; -From a216fc64bde9a95901c92deb7bcd7f3fe4567f75 Mon Sep 17 00:00:00 2001 -From: Luke Wren -Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 168/204] Add /dev/gpiomem device for rootless user GPIO access - -Signed-off-by: Luke Wren ---- - arch/arm/boot/dts/bcm2708.dtsi | 6 + - arch/arm/boot/dts/bcm2709.dtsi | 6 + - drivers/char/broadcom/Kconfig | 9 ++ - drivers/char/broadcom/Makefile | 3 + - drivers/char/broadcom/bcm2835-gpiomem.c | 265 ++++++++++++++++++++++++++++++++ - 5 files changed, 289 insertions(+) - create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c - -diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi -index 0d47427..3bed0a6 100644 ---- a/arch/arm/boot/dts/bcm2708.dtsi -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -15,5 +15,11 @@ - arm-pmu { - compatible = "arm,arm1176-pmu"; - }; -+ -+ gpiomem { -+ compatible = "brcm,bcm2835-gpiomem"; -+ reg = <0x7e200000 0x1000>; -+ status = "okay"; -+ }; - }; - }; -diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi -index 5e0b935..811d825 100644 ---- a/arch/arm/boot/dts/bcm2709.dtsi -+++ b/arch/arm/boot/dts/bcm2709.dtsi -@@ -16,6 +16,12 @@ - compatible = "arm,cortex-a7-pmu"; - interrupts = <3 9>; - }; -+ -+ gpiomem { -+ compatible = "brcm,bcm2835-gpiomem"; -+ reg = <0x7e200000 0x1000>; -+ status = "okay"; -+ }; - }; - - timer { -diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig -index fc40846..bc2eb1e 100644 ---- a/drivers/char/broadcom/Kconfig -+++ b/drivers/char/broadcom/Kconfig -@@ -38,3 +38,12 @@ config BCM_VC_SM - help - Support for the VC shared memory on the Broadcom reference - design. Uses the VCHIQ stack. -+ -+config BCM2835_DEVGPIOMEM -+ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835" -+ default m -+ help -+ Provides users with root-free access to the GPIO registers -+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO -+ register page to the user's pointer. -+ -diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile -index 18171e2..664e2c4 100644 ---- a/drivers/char/broadcom/Makefile -+++ b/drivers/char/broadcom/Makefile -@@ -2,3 +2,6 @@ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ - obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o - obj-$(CONFIG_BCM_VCIO) += vcio.o - obj-$(CONFIG_BCM_VC_SM) += vc_sm/ -+ -+obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o -+ -diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c -new file mode 100644 -index 0000000..0085e13 ---- /dev/null -+++ b/drivers/char/broadcom/bcm2835-gpiomem.c -@@ -0,0 +1,265 @@ -+/** -+ * GPIO memory device driver -+ * -+ * Creates a chardev /dev/gpiomem which will provide user access to -+ * the BCM2835's GPIO registers when it is mmap()'d. -+ * No longer need root for user GPIO access, but without relaxing permissions -+ * on /dev/mem. -+ * -+ * Written by Luke Wren -+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2, as published by the Free -+ * Software Foundation. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVICE_NAME "bcm2835-gpiomem" -+#define DRIVER_NAME "gpiomem-bcm2835" -+#define DEVICE_MINOR 0 -+ -+struct bcm2835_gpiomem_instance { -+ unsigned long gpio_regs_phys; -+ struct device *dev; -+}; -+ -+static struct cdev bcm2835_gpiomem_cdev; -+static dev_t bcm2835_gpiomem_devid; -+static struct class *bcm2835_gpiomem_class; -+static struct device *bcm2835_gpiomem_dev; -+static struct bcm2835_gpiomem_instance *inst; -+ -+ -+/**************************************************************************** -+* -+* GPIO mem chardev file ops -+* -+***************************************************************************/ -+ -+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; -+ } -+ return ret; -+} -+ -+static int bcm2835_gpiomem_release(struct inode *inode, struct file *file) -+{ -+ int dev = iminor(inode); -+ int ret = 0; -+ -+ if (dev != DEVICE_MINOR) { -+ dev_err(inst->dev, "Unknown minor device %d", dev); -+ ret = -ENXIO; -+ } -+ return ret; -+} -+ -+static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = { -+#ifdef CONFIG_HAVE_IOREMAP_PROT -+ .access = generic_access_phys -+#endif -+}; -+ -+static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ /* Ignore what the user says - they're getting the GPIO regs -+ whether they like it or not! */ -+ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT; -+ -+ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page, -+ PAGE_SIZE, -+ vma->vm_page_prot); -+ vma->vm_ops = &bcm2835_gpiomem_vm_ops; -+ if (remap_pfn_range(vma, vma->vm_start, -+ gpio_page, -+ PAGE_SIZE, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+static const struct file_operations -+bcm2835_gpiomem_fops = { -+ .owner = THIS_MODULE, -+ .open = bcm2835_gpiomem_open, -+ .release = bcm2835_gpiomem_release, -+ .mmap = bcm2835_gpiomem_mmap, -+}; -+ -+ -+ /**************************************************************************** -+* -+* Probe and remove functions -+* -+***************************************************************************/ -+ -+ -+static int bcm2835_gpiomem_probe(struct platform_device *pdev) -+{ -+ int err; -+ void *ptr_err; -+ struct device *dev = &pdev->dev; -+ struct device_node *node = dev->of_node; -+ struct resource *ioresource; -+ -+ /* Allocate buffers and instance data */ -+ -+ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL); -+ -+ if (!inst) { -+ err = -ENOMEM; -+ goto failed_inst_alloc; -+ } -+ -+ inst->dev = dev; -+ -+ /* Create character device entries */ -+ -+ err = alloc_chrdev_region(&bcm2835_gpiomem_devid, -+ DEVICE_MINOR, 1, DEVICE_NAME); -+ if (err != 0) { -+ dev_err(inst->dev, "unable to allocate device number"); -+ goto failed_alloc_chrdev; -+ } -+ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops); -+ bcm2835_gpiomem_cdev.owner = THIS_MODULE; -+ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1); -+ if (err != 0) { -+ dev_err(inst->dev, "unable to register device"); -+ goto failed_cdev_add; -+ } -+ -+ /* Create sysfs entries */ -+ -+ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); -+ ptr_err = bcm2835_gpiomem_class; -+ if (IS_ERR(ptr_err)) -+ goto failed_class_create; -+ -+ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL, -+ bcm2835_gpiomem_devid, NULL, -+ "gpiomem"); -+ ptr_err = bcm2835_gpiomem_dev; -+ if (IS_ERR(ptr_err)) -+ goto failed_device_create; -+ -+ /* Get address from device tree if available (*_resource() correctly -+ converts the bus address in device tree to a physical address), -+ or use hardcoded offset + BCM2708_PERI_BASE if not. -+ (In spite of its name 2708 actually seems to have the correct -+ mach-dependent value on 2709 etc, as it is defined in -+ mach-bcm270x/platform.h) */ -+ -+ if (node) { -+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ inst->gpio_regs_phys = ioresource->start; -+ } else { -+ inst->gpio_regs_phys = GPIO_BASE; -+ } -+ -+ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", -+ inst->gpio_regs_phys); -+ -+ return 0; -+ -+failed_device_create: -+ class_destroy(bcm2835_gpiomem_class); -+failed_class_create: -+ cdev_del(&bcm2835_gpiomem_cdev); -+ err = PTR_ERR(ptr_err); -+failed_cdev_add: -+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); -+failed_alloc_chrdev: -+ kfree(inst); -+failed_inst_alloc: -+ dev_err(inst->dev, "could not load bcm2835_gpiomem"); -+ return err; -+} -+ -+static int bcm2835_gpiomem_remove(struct platform_device *pdev) -+{ -+ struct device *dev = inst->dev; -+ -+ kfree(inst); -+ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid); -+ class_destroy(bcm2835_gpiomem_class); -+ cdev_del(&bcm2835_gpiomem_cdev); -+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); -+ -+ dev_info(dev, "GPIO mem driver removed - OK"); -+ return 0; -+} -+ -+ /**************************************************************************** -+* -+* Register the driver with device tree -+* -+***************************************************************************/ -+ -+static const struct of_device_id bcm2835_gpiomem_of_match[] = { -+ {.compatible = "brcm,bcm2835-gpiomem",}, -+ { /* sentinel */ }, -+}; -+ -+MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match); -+ -+static struct platform_driver bcm2835_gpiomem_driver = { -+ .probe = bcm2835_gpiomem_probe, -+ .remove = bcm2835_gpiomem_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = bcm2835_gpiomem_of_match, -+ }, -+}; -+ -+module_platform_driver(bcm2835_gpiomem_driver); -+ -+MODULE_ALIAS("platform:gpiomem-bcm2835"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); -+MODULE_AUTHOR("Luke Wren "); - -From 4e9cf1447a7ef0f8f46c6a8170f44c78c1690a96 Mon Sep 17 00:00:00 2001 -From: Jan Grulich -Date: Mon, 24 Aug 2015 16:02:34 +0100 -Subject: [PATCH 169/204] tpa6130a2: Add headphone switch control - -Signed-off-by: Jan Grulich ---- - sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++--- - 1 file changed, 26 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c -index 6fac9e0..f60ebe1c 100644 ---- a/sound/soc/codecs/tpa6130a2.c -+++ b/sound/soc/codecs/tpa6130a2.c -@@ -4,6 +4,7 @@ - * Copyright (C) Nokia Corporation - * - * Author: Peter Ujfalusi -+ * Modified: Jan Grulich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License -@@ -52,6 +53,8 @@ struct tpa6130a2_data { - enum tpa_model id; - }; - -+static void tpa6130a2_channel_enable(u8 channel, int enable); -+ - static int tpa6130a2_i2c_read(int reg) - { - struct tpa6130a2_data *data; -@@ -189,7 +192,7 @@ static int tpa6130a2_power(u8 power) - } - - static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; -@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, - } - - static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; -@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, - return 1; - } - -+static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ int enable = ucontrol->value.integer.value[0]; -+ unsigned int state; -+ -+ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0; -+ if (state == enable) -+ return 0; /* No change */ -+ -+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable); -+ return 1; /* Changed */ -+} -+ - /* -- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going -+ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going - * down in gain. - */ - static const unsigned int tpa6130_tlv[] = { -@@ -278,6 +295,9 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { - TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, - tpa6130a2_get_volsw, tpa6130a2_put_volsw, - tpa6130_tlv), -+ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch", -+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, -+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), - }; - - static const unsigned int tpa6140_tlv[] = { -@@ -292,6 +312,9 @@ static const struct snd_kcontrol_new tpa6140a2_controls[] = { - TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, - tpa6130a2_get_volsw, tpa6130a2_put_volsw, - tpa6140_tlv), -+ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch", -+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, -+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), - }; - - /* - -From bdad59048f5910ea3c4439ba40a4a14ca8f1be90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sat, 11 Jul 2015 18:48:10 +0200 -Subject: [PATCH 170/204] staging: fbtft: Add reset to fbtft_init_display_dt() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When an init sequence is present in the Device Tree, -fbtft_init_display_dt() is used to initialize the display. -Add missing reset function call and activation of -chip select for parallel bus. - -Signed-off-by: Noralf Trønnes ---- - drivers/staging/fbtft/fbtft-core.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c -index 53b748b..4f165d3 100644 ---- a/drivers/staging/fbtft/fbtft-core.c -+++ b/drivers/staging/fbtft/fbtft-core.c -@@ -1074,6 +1074,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) - p = of_prop_next_u32(prop, NULL, &val); - if (!p) - return -EINVAL; -+ -+ par->fbtftops.reset(par); -+ if (par->gpio.cs != -1) -+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ -+ - while (p) { - if (val & FBTFT_OF_INIT_CMD) { - val &= 0xFFFF; - -From 928b8dbc73acdb75d3f03ef7d5cf9fc639e0280c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 19 Jul 2015 18:57:06 +0200 -Subject: [PATCH 171/204] BCM270X_DT: mz61581: Revert to spi-bcm2708 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The MZ61581 display does not work with spi-bcm2835 and software -chip select. It works before the commit: -spi: bcm2835: transform native-cs to gpio-cs on first spi_setup - -Revert to spi-bcm2708 until the cause has been detected and the -issue resolved. - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index c06fe12..f674a66 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -12,6 +12,8 @@ - fragment@0 { - target = <&spi0>; - __overlay__ { -+ /* does not work with spi-bcm2835 using software chip selects */ -+ compatible = "brcm,bcm2708-spi"; - status = "okay"; - - spidev@0{ - -From 707866acc48470ec677f1fb6befdfd928d9994f1 Mon Sep 17 00:00:00 2001 +From 7fd1e80b9a338c1f5edf22f0503f8da4a7f8a73a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Sep 2015 16:52:34 +0000 -Subject: [PATCH 172/204] vchiq: fix NULL pointer dereference when closing +Subject: [PATCH 174/278] vchiq: fix NULL pointer dereference when closing driver The following code run as root will cause a null pointer dereference oops: @@ -146528,10 +146591,10 @@ index f4d0b66..4055d4b 100644 struct semaphore pop; struct semaphore push; -From 2c90639076be957e3e5eb9f44e0c09719db83f7e Mon Sep 17 00:00:00 2001 +From 073fe0debc4a1183a086f9c2b4823621fba8e859 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:13:17 -0400 -Subject: [PATCH 173/204] bcm2708_fb: remove redundant code as detected by +Subject: [PATCH 175/278] bcm2708_fb: remove redundant code as detected by static analysis static analysis with cppcheck detected some redundant code which @@ -146563,10 +146626,10 @@ index 06a96d16..fed0672 100644 } -From 473b4d43abe530f11f07dbdd9be666a90d75313c Mon Sep 17 00:00:00 2001 +From 875cf2e54234b4391d8a77fcb6fe7a44249291aa Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:15:38 -0400 -Subject: [PATCH 174/204] bcm2708_fb: remove unnecessary initialization of +Subject: [PATCH 176/278] bcm2708_fb: remove unnecessary initialization of result static analysis by cppcheck detected an unnecessary initialization @@ -146595,10 +146658,10 @@ index fed0672..0f62d76 100644 info->var.yoffset = var->yoffset; result = bcm2708_fb_set_par(info); -From 94946643df81ee3acaeed9a5e0eb8944ab8492fe Mon Sep 17 00:00:00 2001 +From 09ecd711af91b371e688a828c603662dddcdca35 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:27:36 -0400 -Subject: [PATCH 175/204] vcsm: increment res_stats MAP_FAIL stats before we +Subject: [PATCH 177/278] vcsm: increment res_stats MAP_FAIL stats before we potentially release the resource resource can be kfree'd when the reference count is zero, so we should @@ -146632,10 +146695,10 @@ index 0bfb42e..b62a3b2 100644 } -From 874c6177f126c4fdb31ed9234fe053581ff632fb Mon Sep 17 00:00:00 2001 +From dfdab3848edea54a4e1a3fbb7aece9305954b347 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:33:39 -0400 -Subject: [PATCH 176/204] bcm2835: camera: check for scene not being found +Subject: [PATCH 178/278] bcm2835: camera: check for scene not being found static analysis by cppcheck detected some potential NULL pointer dereference issues: @@ -146666,10 +146729,10 @@ index 3017b94..f9f903f 100644 return -EINVAL; -From a255eb898f2ff3d63de6dbc201797ff732499dca Mon Sep 17 00:00:00 2001 +From f912909c363f4670fb0a861096668fac03e80bd9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:47:51 -0400 -Subject: [PATCH 177/204] bcm2835: memcpy port data to m rather than rmsg +Subject: [PATCH 179/278] bcm2835: memcpy port data to m rather than rmsg static analysis by cppcheck detected a memcpy to rmsg which is not actually initialized at that point. The memcpy should be copying @@ -146681,7 +146744,7 @@ Signed-off-by: Colin Ian King 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/bcm2835/mmal-vchiq.c b/drivers/media/platform/bcm2835/mmal-vchiq.c -index 76f249e..7813225 100644 +index 76f249e..78132254 100644 --- a/drivers/media/platform/bcm2835/mmal-vchiq.c +++ b/drivers/media/platform/bcm2835/mmal-vchiq.c @@ -851,7 +851,7 @@ static int port_info_set(struct vchiq_mmal_instance *instance, @@ -146694,119 +146757,10 @@ index 76f249e..7813225 100644 ret = send_synchronous_mmal_msg(instance, &m, -From bd4d78dcb66955bc2ea1c81232db499e1f662ac6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 13 Sep 2015 15:54:28 +0200 -Subject: [PATCH 178/204] Revert "BCM270X_DT: mz61581: Revert to spi-bcm2708" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit 1820cd05d93b2d465d1616202772efe5bf0d11fe. - -The spi-bcm2835 driver has been fixed, so now we can use it again. - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index f674a66..c06fe12 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -12,8 +12,6 @@ - fragment@0 { - target = <&spi0>; - __overlay__ { -- /* does not work with spi-bcm2835 using software chip selects */ -- compatible = "brcm,bcm2708-spi"; - status = "okay"; - - spidev@0{ - -From 63103cf8b12f79c02f1a6d7a851fbb6727528d33 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 13 Sep 2015 17:17:14 +0200 -Subject: [PATCH 179/204] BCM270X_DT: mz61581: Set txbuflen to 32k -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Because of the spi dma mapping/engine overhead with spi-bcm2835, -txbuflen has to be increased from 4096 to 32768 to maximize -throughput (11MB/s at 128MHz). - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/README | 2 ++ - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index a749ff7..0aa5aa1 100644 ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -368,6 +368,8 @@ Params: speed Display SPI bus speed - - fps Delay between frame updates - -+ txbuflen Transmit buffer length (default 32768) -+ - debug Debug output level {0-7} - - xohms Touchpanel sensitivity (X-plate resistance) -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index c06fe12..9242a6e 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -57,6 +57,7 @@ - bgr; - fps = <30>; - buswidth = <8>; -+ txbuflen = <32768>; - - reset-gpios = <&gpio 15 0>; - dc-gpios = <&gpio 25 0>; -@@ -103,6 +104,7 @@ - speed = <&mz61581>, "spi-max-frequency:0"; - rotate = <&mz61581>, "rotate:0"; - fps = <&mz61581>, "fps:0"; -+ txbuflen = <&mz61581>, "txbuflen:0"; - debug = <&mz61581>, "debug:0"; - xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; - }; - -From 6881996989b77354049455c95e8af67f278cfa48 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 11 Sep 2015 12:10:15 +0100 -Subject: [PATCH 180/204] bcm2835-mmc: Don't overwrite MMC capabilities from DT - ---- - drivers/mmc/host/bcm2835-mmc.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c -index b7c4883..164bfad 100644 ---- a/drivers/mmc/host/bcm2835-mmc.c -+++ b/drivers/mmc/host/bcm2835-mmc.c -@@ -1327,8 +1327,9 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) - mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; - #endif - /* host controller capabilities */ -- mmc->caps = MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | -- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; -+ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | -+ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | -+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; - - host->flags = SDHCI_AUTO_CMD23; - - -From 7bbc4815e21230a8a011d3f3cf794d765cdacb35 Mon Sep 17 00:00:00 2001 +From 9d4b7e347d5242312445767678dd179d77e14880 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 11 Sep 2015 09:14:01 +0100 -Subject: [PATCH 181/204] BCM270X_DT: Use fixed-factor-clock for uart1 +Subject: [PATCH 180/278] BCM270X_DT: Use fixed-factor-clock for uart1 The BCM2835 mini-UART is almost 8250-compatible, but there is a factor-of-two difference in the clock divider for the baud rate. @@ -146906,10 +146860,681 @@ index f25f0a2..76d44a2 100644 spi = <&spi0>,"status"; i2c0 = <&i2c0>,"status"; -From d851a069d33dba42c5c7fa023ee13f994643fa90 Mon Sep 17 00:00:00 2001 +From 877e636ac93e659f949d389bfad63db1fdfb29dd Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 11 Sep 2015 12:10:15 +0100 +Subject: [PATCH 181/278] bcm2835-mmc: Don't overwrite MMC capabilities from DT + +--- + drivers/mmc/host/bcm2835-mmc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index b7c4883..164bfad 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1327,8 +1327,9 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; + #endif + /* host controller capabilities */ +- mmc->caps = MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | +- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; ++ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | ++ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | ++ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; + + host->flags = SDHCI_AUTO_CMD23; + + +From a2c55d70c3c1b45ed04c5e1f6672794774380486 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 13 Sep 2015 15:54:28 +0200 +Subject: [PATCH 182/278] Revert "BCM270X_DT: mz61581: Revert to spi-bcm2708" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 1820cd05d93b2d465d1616202772efe5bf0d11fe. + +The spi-bcm2835 driver has been fixed, so now we can use it again. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index f674a66..c06fe12 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -12,8 +12,6 @@ + fragment@0 { + target = <&spi0>; + __overlay__ { +- /* does not work with spi-bcm2835 using software chip selects */ +- compatible = "brcm,bcm2708-spi"; + status = "okay"; + + spidev@0{ + +From ab97368a3d04c1871395370c1f78fc1e26451302 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 13 Sep 2015 17:17:14 +0200 +Subject: [PATCH 183/278] BCM270X_DT: mz61581: Set txbuflen to 32k +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because of the spi dma mapping/engine overhead with spi-bcm2835, +txbuflen has to be increased from 4096 to 32768 to maximize +throughput (11MB/s at 128MHz). + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index a749ff7..0aa5aa1 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -368,6 +368,8 @@ Params: speed Display SPI bus speed + + fps Delay between frame updates + ++ txbuflen Transmit buffer length (default 32768) ++ + debug Debug output level {0-7} + + xohms Touchpanel sensitivity (X-plate resistance) +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index c06fe12..9242a6e 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -57,6 +57,7 @@ + bgr; + fps = <30>; + buswidth = <8>; ++ txbuflen = <32768>; + + reset-gpios = <&gpio 15 0>; + dc-gpios = <&gpio 25 0>; +@@ -103,6 +104,7 @@ + speed = <&mz61581>, "spi-max-frequency:0"; + rotate = <&mz61581>, "rotate:0"; + fps = <&mz61581>, "fps:0"; ++ txbuflen = <&mz61581>, "txbuflen:0"; + debug = <&mz61581>, "debug:0"; + xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; + }; + +From 6843570d2962f631cd6fad34634f7a3988e6fd78 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 10 Sep 2015 09:32:14 +0000 +Subject: [PATCH 184/278] backport: spi: bcm2835: BUG: fix wrong use of + PAGE_MASK + +There is a bug in the alignment checking of transfers, +that results in DMA not being used for un-aligned +transfers that do not cross page-boundries, which is valid. + +This is due to a missconception of the meaning PAGE_MASK +when implementing that check originally - (PAGE_SIZE - 1) +should have been used instead. + +Also fixes a copy/paste error. + +Reported-by: +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +Cc: stable@vger.kernel.org +--- + drivers/spi/spi-bcm2835.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index b68991c..3835332 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -386,14 +386,14 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, + /* otherwise we only allow transfers within the same page + * to avoid wasting time on dma_mapping when it is not practical + */ +- if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { ++ if (((size_t)tfr->tx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, + "Unaligned spi tx-transfer bridging page\n"); + return false; + } +- if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { ++ if (((size_t)tfr->rx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, +- "Unaligned spi tx-transfer bridging page\n"); ++ "Unaligned spi rx-transfer bridging page\n"); + return false; + } + + +From b27fa0514e45ed920a49817f453a990b1a913c5e Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:46 +0200 +Subject: [PATCH 185/278] mt7601u: fix dma from stack address + +DMA to variables located on the stack is a bad idea. +For simplicity and to avoid frequent allocations create +a buffer inside the device structure. Protect this +buffer with vendor_req_mutex. Don't protect vendor +requests which don't use this buffer. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +- + drivers/net/wireless/mediatek/mt7601u/usb.c | 63 ++++++++++++------------- + drivers/net/wireless/mediatek/mt7601u/usb.h | 2 + + 3 files changed, 34 insertions(+), 35 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index 9102be6b..6bdfc11 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -146,7 +146,7 @@ enum { + * @rx_lock: protects @rx_q. + * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. + * @mutex: ensures exclusive access from mac80211 callbacks. +- * @vendor_req_mutex: ensures atomicity of vendor requests. ++ * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. + * @reg_atomic_mutex: ensures atomicity of indirect register accesses + * (accesses to RF and BBP). + * @hw_atomic_mutex: ensures exclusive access to HW during critical +@@ -184,6 +184,8 @@ struct mt7601u_dev { + struct mt7601u_eeprom_params *ee; + + struct mutex vendor_req_mutex; ++ void *vend_buf; ++ + struct mutex reg_atomic_mutex; + struct mutex hw_atomic_mutex; + +diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c +index 54dba40..416c604 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/usb.c ++++ b/drivers/net/wireless/mediatek/mt7601u/usb.c +@@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb) + complete(cmpl); + } + +-static int +-__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, +- const u8 direction, const u16 val, const u16 offset, +- void *buf, const size_t buflen) ++int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, ++ const u8 direction, const u16 val, const u16 offset, ++ void *buf, const size_t buflen) + { + int i, ret; + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); +@@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + trace_mt_vend_req(dev, pipe, req, req_type, val, offset, + buf, buflen, ret); + ++ if (ret == -ENODEV) ++ set_bit(MT7601U_STATE_REMOVED, &dev->state); + if (ret >= 0 || ret == -ENODEV) + return ret; + +@@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + return ret; + } + +-int +-mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, +- const u8 direction, const u16 val, const u16 offset, +- void *buf, const size_t buflen) +-{ +- int ret; +- +- mutex_lock(&dev->vendor_req_mutex); +- +- ret = __mt7601u_vendor_request(dev, req, direction, val, offset, +- buf, buflen); +- if (ret == -ENODEV) +- set_bit(MT7601U_STATE_REMOVED, &dev->state); +- +- mutex_unlock(&dev->vendor_req_mutex); +- +- return ret; +-} +- + void mt7601u_vendor_reset(struct mt7601u_dev *dev) + { + mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, +@@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) + u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) + { + int ret; +- __le32 reg; +- u32 val; ++ u32 val = ~0; + + WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); + ++ mutex_lock(&dev->vendor_req_mutex); ++ + ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, +- 0, offset, ®, sizeof(reg)); +- val = le32_to_cpu(reg); +- if (ret > 0 && ret != sizeof(reg)) { ++ 0, offset, dev->vend_buf, MT_VEND_BUF); ++ if (ret == MT_VEND_BUF) ++ val = get_unaligned_le32(dev->vend_buf); ++ else if (ret > 0) + dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", + ret, offset); +- val = ~0; +- } ++ ++ mutex_unlock(&dev->vendor_req_mutex); + + trace_reg_read(dev, offset, val); + return val; +@@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + { + int ret; + ++ mutex_lock(&dev->vendor_req_mutex); ++ + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val & 0xffff, offset, NULL, 0); +- if (ret) +- return ret; +- return mt7601u_vendor_request(dev, req, USB_DIR_OUT, +- val >> 16, offset + 2, NULL, 0); ++ if (!ret) ++ ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, ++ val >> 16, offset + 2, NULL, 0); ++ ++ mutex_unlock(&dev->vendor_req_mutex); ++ ++ return ret; + } + + void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) +@@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf, + + usb_set_intfdata(usb_intf, dev); + ++ dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); ++ if (!dev->vend_buf) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ + ret = mt7601u_assign_pipes(usb_intf, dev); + if (ret) + goto err; +diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h +index 49e188f..bc18202 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/usb.h ++++ b/drivers/net/wireless/mediatek/mt7601u/usb.h +@@ -23,6 +23,8 @@ + + #define MT_VEND_DEV_MODE_RESET 1 + ++#define MT_VEND_BUF sizeof(__le32) ++ + enum mt_vendor_req { + MT_VEND_DEV_MODE = 1, + MT_VEND_WRITE = 2, + +From 7365b42453cef6277126ea65cbd7bbff2e221a8c Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:47 +0200 +Subject: [PATCH 186/278] mt7601u: use correct ieee80211_rx variant + +Rx is run inside a tasklet so ieee80211_rx() should be used +instead of ieee80211_rx_ni(). + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index 7217da4..fb183e3 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -112,7 +112,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, + if (!skb) + return; + +- ieee80211_rx_ni(dev->hw, skb); ++ ieee80211_rx(dev->hw, skb); + } + + static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) + +From 940d45dc308372ea75c867542a1ed1195d185612 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:48 +0200 +Subject: [PATCH 187/278] mt7601u: fix tx status reporting contexts + +mac80211 requires that rx path does not run concurrently with +tx status reporting. Since rx path is run in driver tasklet, +tx status cannot be reported directly from interrupt context +(there would be no way to lock it out). + +Add tasklet for tx and move all possible code from irq handler +there. + +Note: tx tasklet is needed because workqueue is queued very + rarely and that kills TCP performance. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 30 +++++++++++++++++++++---- + drivers/net/wireless/mediatek/mt7601u/init.c | 1 + + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++++ + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 2 ++ + 4 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index fb183e3..63c4854 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -236,23 +236,42 @@ static void mt7601u_complete_tx(struct urb *urb) + skb = q->e[q->start].skb; + trace_mt_tx_dma_done(dev, skb); + +- mt7601u_tx_status(dev, skb); ++ __skb_queue_tail(&dev->tx_skb_done, skb); ++ tasklet_schedule(&dev->tx_tasklet); + + if (q->used == q->entries - q->entries / 8) + ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); + + q->start = (q->start + 1) % q->entries; + q->used--; ++out: ++ spin_unlock_irqrestore(&dev->tx_lock, flags); ++} + +- if (urb->status) +- goto out; ++static void mt7601u_tx_tasklet(unsigned long data) ++{ ++ struct mt7601u_dev *dev = (struct mt7601u_dev *) data; ++ struct sk_buff_head skbs; ++ unsigned long flags; ++ ++ __skb_queue_head_init(&skbs); ++ ++ spin_lock_irqsave(&dev->tx_lock, flags); + + set_bit(MT7601U_STATE_MORE_STATS, &dev->state); + if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) + queue_delayed_work(dev->stat_wq, &dev->stat_work, + msecs_to_jiffies(10)); +-out: ++ ++ skb_queue_splice_init(&dev->tx_skb_done, &skbs); ++ + spin_unlock_irqrestore(&dev->tx_lock, flags); ++ ++ while (!skb_queue_empty(&skbs)) { ++ struct sk_buff *skb = __skb_dequeue(&skbs); ++ ++ mt7601u_tx_status(dev, skb); ++ } + } + + static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, +@@ -475,6 +494,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev) + { + int ret = -ENOMEM; + ++ tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); + tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); + + ret = mt7601u_alloc_tx(dev); +@@ -502,4 +522,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev) + + mt7601u_free_rx(dev); + mt7601u_free_tx(dev); ++ ++ tasklet_kill(&dev->tx_tasklet); + } +diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c +index 45eb079..8f5417e 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/init.c ++++ b/drivers/net/wireless/mediatek/mt7601u/init.c +@@ -456,6 +456,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) + spin_lock_init(&dev->lock); + spin_lock_init(&dev->con_mon_lock); + atomic_set(&dev->avg_ampdu_len, 1); ++ skb_queue_head_init(&dev->tx_skb_done); + + dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); + if (!dev->stat_wq) { +diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c +index 7514bce..e3928cf 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mac.c ++++ b/drivers/net/wireless/mediatek/mt7601u/mac.c +@@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) + } + + mt76_mac_fill_tx_status(dev, &info, stat); ++ ++ local_bh_disable(); + ieee80211_tx_status_noskb(dev->hw, sta, &info); ++ local_bh_enable(); ++ + rcu_read_unlock(); + } + +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index 6bdfc11..bc5e294 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -199,7 +199,9 @@ struct mt7601u_dev { + + /* TX */ + spinlock_t tx_lock; ++ struct tasklet_struct tx_tasklet; + struct mt7601u_tx_queue *tx_q; ++ struct sk_buff_head tx_skb_done; + + atomic_t avg_ampdu_len; + + +From 39ca7c97e0f31402be28d1ea543714f5e1901613 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:49 +0200 +Subject: [PATCH 188/278] mt7601u: lock out rx path and tx status reporting + +mac80211 requires that rx path does not run concurrently with +tx status reporting. Add a spinlock which will ensure that. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 2 ++ + drivers/net/wireless/mediatek/mt7601u/init.c | 1 + + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++-- + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +++- + drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +++ + 5 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index 63c4854..57a80cf 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, + if (!skb) + return; + ++ spin_lock(&dev->mac_lock); + ieee80211_rx(dev->hw, skb); ++ spin_unlock(&dev->mac_lock); + } + + static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) +diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c +index 8f5417e..c60eb7d 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/init.c ++++ b/drivers/net/wireless/mediatek/mt7601u/init.c +@@ -454,6 +454,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) + spin_lock_init(&dev->tx_lock); + spin_lock_init(&dev->rx_lock); + spin_lock_init(&dev->lock); ++ spin_lock_init(&dev->mac_lock); + spin_lock_init(&dev->con_mon_lock); + atomic_set(&dev->avg_ampdu_len, 1); + skb_queue_head_init(&dev->tx_skb_done); +diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c +index e3928cf..e21c53e 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mac.c ++++ b/drivers/net/wireless/mediatek/mt7601u/mac.c +@@ -182,9 +182,9 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) + + mt76_mac_fill_tx_status(dev, &info, stat); + +- local_bh_disable(); ++ spin_lock_bh(&dev->mac_lock); + ieee80211_tx_status_noskb(dev->hw, sta, &info); +- local_bh_enable(); ++ spin_unlock_bh(&dev->mac_lock); + + rcu_read_unlock(); + } +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index bc5e294..428bd2f 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -141,8 +141,9 @@ enum { + /** + * struct mt7601u_dev - adapter structure + * @lock: protects @wcid->tx_rate. ++ * @mac_lock: locks out mac80211's tx status and rx paths. + * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS +- flags in @state. ++ * flags in @state. + * @rx_lock: protects @rx_q. + * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. + * @mutex: ensures exclusive access from mac80211 callbacks. +@@ -177,6 +178,7 @@ struct mt7601u_dev { + struct mt76_wcid __rcu *wcid[N_WCIDS]; + + spinlock_t lock; ++ spinlock_t mac_lock; + + const u16 *beacon_offsets; + +diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c +index 0be2080..a0a33dc 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/tx.c ++++ b/drivers/net/wireless/mediatek/mt7601u/tx.c +@@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; ++ ++ spin_lock(&dev->mac_lock); + ieee80211_tx_status(dev->hw, skb); ++ spin_unlock(&dev->mac_lock); + } + + static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) + +From 2a4c4dc8aaf0bfdfbbaceedaae7aa6a227f73b21 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 15 Sep 2015 15:16:24 +0100 +Subject: [PATCH 189/278] config: Add CIFS_DFS_UPCALL, CIFS_ACL, CIFS_SMB2, + CIFS_FSCACHE + +--- + arch/arm/configs/bcm2709_defconfig | 4 ++++ + arch/arm/configs/bcmrpi_defconfig | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 16a8354..db55b51 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1160,6 +1160,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y + CONFIG_CIFS_UPCALL=y + CONFIG_CIFS_XATTR=y + CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_ACL=y ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_SMB2=y ++CONFIG_CIFS_FSCACHE=y + CONFIG_9P_FS=m + CONFIG_9P_FS_POSIX_ACL=y + CONFIG_NLS_DEFAULT="utf8" +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 7dd4fd4..d474418 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1153,6 +1153,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y + CONFIG_CIFS_UPCALL=y + CONFIG_CIFS_XATTR=y + CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_ACL=y ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_SMB2=y ++CONFIG_CIFS_FSCACHE=y + CONFIG_9P_FS=m + CONFIG_9P_FS_POSIX_ACL=y + CONFIG_NLS_DEFAULT="utf8" + +From 3582f4a5b986d55fb9782b030c7daa0ae8fd4df6 Mon Sep 17 00:00:00 2001 +From: David Lechner +Date: Mon, 14 Sep 2015 19:08:36 -0500 +Subject: [PATCH 190/278] Use dts-dirs feature for overlays. + +The kernel makefiles have a dts-dirs target that is for vendor subdirectories. + +Using this fixes the install_dtbs target, which previously did not install the overlays. +--- + arch/arm/boot/dts/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 12de305..faf293f 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -15,6 +15,9 @@ endif + ifeq ($(CONFIG_ARCH_BCM2835),y) + RPI_DT_OVERLAYS=y + endif ++ifeq ($(RPI_DT_OVERLAYS),y) ++ dts-dirs += overlays ++endif + + dtb-$(CONFIG_ARCH_ALPINE) += \ + alpine-db.dtb +@@ -683,11 +686,10 @@ targets += $(dtb-y) + endif + + always := $(dtb-y) ++subdir-y := $(dts-dirs) + clean-files := *.dtb + + # Enable fixups to support overlays on BCM2708 platforms + ifeq ($(RPI_DT_OVERLAYS),y) + DTC_FLAGS ?= -@ + endif +- +-subdir-y += overlays + +From 47e7b64a15a3bacae29eb7a4c600387c0d9c0995 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 182/204] Add SMI driver +Subject: [PATCH 191/278] Add SMI driver Signed-off-by: Luke Wren --- @@ -148968,10 +149593,10 @@ index 0000000..ee3a75e + +#endif /* BCM2835_SMI_H */ -From f657d984e244c7348152e2edc09cd5decb2f5b55 Mon Sep 17 00:00:00 2001 +From da1b5e6b5a2e0e997e997f628a40393079a1b16f Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 183/204] Add SMI NAND driver +Subject: [PATCH 192/278] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -149125,7 +149750,7 @@ index 0000000..13ce0b7 + }; +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 16a8354..c7671bf 100644 +index db55b51..60f8357 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -392,6 +392,10 @@ CONFIG_DEVTMPFS=y @@ -149150,7 +149775,7 @@ index 16a8354..c7671bf 100644 CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 7dd4fd4..75fa1d0 100644 +index d474418..8ebc8d5 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -385,6 +385,10 @@ CONFIG_DEVTMPFS=y @@ -149479,10 +150104,10 @@ index 0000000..b747326 + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From a3bf36473505511198d71fdf19e6b28b4ee55195 Mon Sep 17 00:00:00 2001 +From dfc75f99bdfb59fb968abc53f70ac3b74c2f6b43 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 16 Sep 2015 17:28:41 +0100 -Subject: [PATCH 184/204] BCM270X_DT: Document SMI overlay +Subject: [PATCH 193/278] BCM270X_DT: Document SMI overlay --- arch/arm/boot/dts/overlays/Makefile | 6 +++--- @@ -149543,10 +150168,10 @@ index 0aa5aa1..4ab4c695 100644 Info: Selects the bcm2708-spi SPI driver Load: dtoverlay=spi-bcm2708 -From 24a9683edd38171e27a170b95a42133c2bd3890f Mon Sep 17 00:00:00 2001 +From a79e0fbb9e48eec364aa3e1803c9f56513ee546e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 17 Sep 2015 17:13:42 +0100 -Subject: [PATCH 185/204] dwc_otg: Force host mode to fix incorrect compute +Subject: [PATCH 194/278] dwc_otg: Force host mode to fix incorrect compute module boards --- @@ -149567,139 +150192,45 @@ index e40060f..beaa8b3 100644 dwc_mdelay(100); } -From 4f8563760264a9aedad6fec09e8adb8c3929c1a3 Mon Sep 17 00:00:00 2001 +From a31d2a648467bc5c8c7ef3e5cba9d7357ccffc2e Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Tue, 15 Sep 2015 15:16:24 +0100 -Subject: [PATCH 186/204] config: Add CIFS_DFS_UPCALL, CIFS_ACL, CIFS_SMB2, - CIFS_FSCACHE +Date: Thu, 1 Oct 2015 11:49:11 +0100 +Subject: [PATCH 195/278] config: Add CONFIG_UHID --- - arch/arm/configs/bcm2709_defconfig | 4 ++++ - arch/arm/configs/bcmrpi_defconfig | 4 ++++ - 2 files changed, 8 insertions(+) + 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 c7671bf..60f8357 100644 +index 60f8357..41727bf 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -1167,6 +1167,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y - CONFIG_CIFS_UPCALL=y - CONFIG_CIFS_XATTR=y - CONFIG_CIFS_POSIX=y -+CONFIG_CIFS_ACL=y -+CONFIG_CIFS_DFS_UPCALL=y -+CONFIG_CIFS_SMB2=y -+CONFIG_CIFS_FSCACHE=y - CONFIG_9P_FS=m - CONFIG_9P_FS_POSIX_ACL=y - CONFIG_NLS_DEFAULT="utf8" +@@ -842,6 +842,7 @@ CONFIG_SND_SOC_WM8804_I2C=m + CONFIG_SND_SIMPLE_CARD=m + CONFIG_SOUND_PRIME=m + CONFIG_HIDRAW=y ++CONFIG_UHID=m + CONFIG_HID_A4TECH=m + CONFIG_HID_ACRUX=m + CONFIG_HID_APPLE=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 75fa1d0..8ebc8d5 100644 +index 8ebc8d5..bc0f523 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -1160,6 +1160,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y - CONFIG_CIFS_UPCALL=y - CONFIG_CIFS_XATTR=y - CONFIG_CIFS_POSIX=y -+CONFIG_CIFS_ACL=y -+CONFIG_CIFS_DFS_UPCALL=y -+CONFIG_CIFS_SMB2=y -+CONFIG_CIFS_FSCACHE=y - CONFIG_9P_FS=m - CONFIG_9P_FS_POSIX_ACL=y - CONFIG_NLS_DEFAULT="utf8" +@@ -835,6 +835,7 @@ CONFIG_SND_SOC_WM8804_I2C=m + CONFIG_SND_SIMPLE_CARD=m + CONFIG_SOUND_PRIME=m + CONFIG_HIDRAW=y ++CONFIG_UHID=m + CONFIG_HID_A4TECH=m + CONFIG_HID_ACRUX=m + CONFIG_HID_APPLE=m -From dee40d2ad759e6f0d9737f15c9c00a9149d55b73 Mon Sep 17 00:00:00 2001 -From: David Lechner -Date: Mon, 14 Sep 2015 19:08:36 -0500 -Subject: [PATCH 187/204] Use dts-dirs feature for overlays. - -The kernel makefiles have a dts-dirs target that is for vendor subdirectories. - -Using this fixes the install_dtbs target, which previously did not install the overlays. ---- - arch/arm/boot/dts/Makefile | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 12de305..faf293f 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -15,6 +15,9 @@ endif - ifeq ($(CONFIG_ARCH_BCM2835),y) - RPI_DT_OVERLAYS=y - endif -+ifeq ($(RPI_DT_OVERLAYS),y) -+ dts-dirs += overlays -+endif - - dtb-$(CONFIG_ARCH_ALPINE) += \ - alpine-db.dtb -@@ -683,11 +686,10 @@ targets += $(dtb-y) - endif - - always := $(dtb-y) -+subdir-y := $(dts-dirs) - clean-files := *.dtb - - # Enable fixups to support overlays on BCM2708 platforms - ifeq ($(RPI_DT_OVERLAYS),y) - DTC_FLAGS ?= -@ - endif -- --subdir-y += overlays - -From 51ccad4fd102f2eb4d2a8115ff2a06ec01676acd Mon Sep 17 00:00:00 2001 -From: Martin Sperl -Date: Thu, 10 Sep 2015 09:32:14 +0000 -Subject: [PATCH 192/204] backport: spi: bcm2835: BUG: fix wrong use of - PAGE_MASK - -There is a bug in the alignment checking of transfers, -that results in DMA not being used for un-aligned -transfers that do not cross page-boundries, which is valid. - -This is due to a missconception of the meaning PAGE_MASK -when implementing that check originally - (PAGE_SIZE - 1) -should have been used instead. - -Also fixes a copy/paste error. - -Reported-by: -Signed-off-by: Martin Sperl -Signed-off-by: Mark Brown -Cc: stable@vger.kernel.org ---- - drivers/spi/spi-bcm2835.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c -index b68991c..3835332 100644 ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -386,14 +386,14 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, - /* otherwise we only allow transfers within the same page - * to avoid wasting time on dma_mapping when it is not practical - */ -- if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { -+ if (((size_t)tfr->tx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { - dev_warn_once(&spi->dev, - "Unaligned spi tx-transfer bridging page\n"); - return false; - } -- if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { -+ if (((size_t)tfr->rx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { - dev_warn_once(&spi->dev, -- "Unaligned spi tx-transfer bridging page\n"); -+ "Unaligned spi rx-transfer bridging page\n"); - return false; - } - - -From 16e92c1ffaf2b25fc3b410ba8e1dc6a457b645f7 Mon Sep 17 00:00:00 2001 +From e2bed14c7bea9eb805bea8ac0d10952dc0070032 Mon Sep 17 00:00:00 2001 From: Stuart MacLean Date: Fri, 2 Oct 2015 15:12:59 +0100 -Subject: [PATCH 193/204] Add support for the HiFiBerry DAC+ Pro. +Subject: [PATCH 196/278] Add support for the HiFiBerry DAC+ Pro. The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators. @@ -150247,10 +150778,645 @@ index e12764d..8d16b2f 100644 dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From f1c2c5ab06e1597d0aa0593c5dec52cf580332e3 Mon Sep 17 00:00:00 2001 +From 1cddc8af1c04d0958bd2bb968cfe1f06936a0398 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sun, 4 Oct 2015 12:30:01 +0100 +Subject: [PATCH 197/278] config: Add CONFIG_CRYPTO_USER_API_SKCIPHER + +--- + 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 41727bf..a13cd93 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1238,6 +1238,7 @@ CONFIG_CRYPTO_WP512=m + CONFIG_CRYPTO_CAST5=m + CONFIG_CRYPTO_DES=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_SKCIPHER=m + # CONFIG_CRYPTO_HW is not set + CONFIG_ARM_CRYPTO=y + CONFIG_CRYPTO_SHA1_ARM_NEON=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index bc0f523..5cf54ea 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1234,6 +1234,7 @@ CONFIG_CRYPTO_WP512=m + CONFIG_CRYPTO_CAST5=m + CONFIG_CRYPTO_DES=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_SKCIPHER=m + # CONFIG_CRYPTO_HW is not set + CONFIG_ARM_CRYPTO=y + CONFIG_CRYPTO_SHA1_ARM=m + +From 371b2e422fd6f8d724d8b51613b9cc07f0ea7887 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sun, 4 Oct 2015 12:36:44 +0100 +Subject: [PATCH 198/278] config: Add options for supporting openlabs 802.15.4 + radio + +--- + arch/arm/configs/bcm2709_defconfig | 6 ++++++ + arch/arm/configs/bcmrpi_defconfig | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index a13cd93..630da1b 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -283,6 +283,9 @@ CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m + CONFIG_6LOWPAN=m ++CONFIG_IEEE802154=m ++CONFIG_IEEE802154_6LOWPAN=m ++CONFIG_MAC802154=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -529,6 +532,9 @@ CONFIG_ZD1211RW=m + CONFIG_MWIFIEX=m + CONFIG_MWIFIEX_SDIO=m + CONFIG_WIMAX_I2400M_USB=m ++CONFIG_IEEE802154_AT86RF230=m ++CONFIG_IEEE802154_MRF24J40=m ++CONFIG_IEEE802154_CC2520=m + CONFIG_INPUT_POLLDEV=m + # CONFIG_INPUT_MOUSEDEV_PSAUX is not set + CONFIG_INPUT_JOYDEV=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 5cf54ea..df4cebc 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -276,6 +276,9 @@ CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m + CONFIG_6LOWPAN=m ++CONFIG_IEEE802154=m ++CONFIG_IEEE802154_6LOWPAN=m ++CONFIG_MAC802154=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -522,6 +525,9 @@ CONFIG_ZD1211RW=m + CONFIG_MWIFIEX=m + CONFIG_MWIFIEX_SDIO=m + CONFIG_WIMAX_I2400M_USB=m ++CONFIG_IEEE802154_AT86RF230=m ++CONFIG_IEEE802154_MRF24J40=m ++CONFIG_IEEE802154_CC2520=m + CONFIG_INPUT_POLLDEV=m + # CONFIG_INPUT_MOUSEDEV_PSAUX is not set + CONFIG_INPUT_JOYDEV=m + +From 097a8688c9aaa1b6f5c4c7eeb7a02dc86c27c6d1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 5 Oct 2015 10:47:45 +0100 +Subject: [PATCH 199/278] BCM270X_DT: Add at86rf233 overlay + +Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0. + +See: https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 21 +++++++-- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++ + 3 files changed, 72 insertions(+), 4 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 192bda7..6de04be 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y) + endif + + dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 4ab4c695..68b608b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -69,13 +69,14 @@ DT parameters: + + Parameters always have default values, although in some cases (e.g. "w1-gpio") + it is necessary to provided multiple overlays in order to get the desired +-behaviour. See the list of overlays below for a description of the parameters and their defaults. ++behaviour. See the list of overlays below for a description of the parameters ++and their defaults. + + The Overlay and Parameter Reference + =================================== + +-N.B. When editing this file, please preserve the indentation levels to make it simple to parse +-programmatically. NO HARD TABS. ++N.B. When editing this file, please preserve the indentation levels to make it ++simple to parse programmatically. NO HARD TABS. + + + Name: +@@ -149,7 +150,7 @@ Name: ads7846 + Info: ADS7846 Touch controller + Load: dtoverlay=ads7846,= + Params: cs SPI bus Chip Select (default 1) +- speed SPI bus speed (default 2Mhz, max 3.25MHz) ++ speed SPI bus speed (default 2MHz, max 3.25MHz) + penirq GPIO used for PENIRQ. REQUIRED + penirq_pull Set GPIO pull (default 0=none, 2=pullup) + swapxy Swap x and y axis +@@ -170,6 +171,18 @@ Params: cs SPI bus Chip Select (default 1) + www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt + + ++Name: at86rf233 ++Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, ++ connected to spi0.0 ++Load: dtoverlay=at86rf233,= ++Params: interrupt GPIO used for INT (default 23) ++ reset GPIO used for Reset (default 24) ++ sleep GPIO used for Sleep (default 25) ++ speed SPI bus speed in Hz (default 750000) ++ trim Fine tuning of the internal capacitance ++ arrays (0=+0pF, 15=+4.5pF, default 15) ++ ++ + Name: bmp085_i2c-sensor + Info: Configures the BMP085/BMP180 digital barometric pressure and temperature + sensors from Bosch Sensortec +diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +new file mode 100644 +index 0000000..70f50ea +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +@@ -0,0 +1,54 @@ ++/dts-v1/; ++/plugin/; ++ ++/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */ ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ lowpan0: at86rf233@0 { ++ compatible = "atmel,at86rf233"; ++ reg = <0>; ++ interrupt-parent = <&gpio>; ++ interrupts = <23 4>; /* active high */ ++ reset-gpio = <&gpio 24 1>; ++ sleep-gpio = <&gpio 25 1>; ++ spi-max-frequency = <7500000>; ++ xtal-trim = /bits/ 8 <0xf>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ lowpan0_pins: lowpan0_pins { ++ brcm,pins = <23 24 25>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ interrupt = <&lowpan0>, "interrupts:0", ++ <&lowpan0_pins>, "brcm,pins:0"; ++ reset = <&lowpan0>, "reset-gpio:4", ++ <&lowpan0_pins>, "brcm,pins:4"; ++ sleep = <&lowpan0>, "sleep-gpio:4", ++ <&lowpan0_pins>, "brcm,pins:8"; ++ speed = <&lowpan0>, "spi-max-frequency:0"; ++ trim = <&lowpan0>, "xtal-trim.0"; ++ }; ++}; + +From 429666c96ef139bd1b9f4668b60a824448a20d52 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 6 Oct 2015 10:16:58 +0100 +Subject: [PATCH 200/278] bcm2835-gpiomem: Fix for ARCH_BCM2835 builds + +Build on ARCH_BCM2835, and fail to probe if no IO resource. + +See: https://github.com/raspberrypi/linux/issues/1154 +--- + drivers/char/broadcom/bcm2835-gpiomem.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +index 0085e13..911f5b7 100644 +--- a/drivers/char/broadcom/bcm2835-gpiomem.c ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -143,7 +143,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + int err; + void *ptr_err; + struct device *dev = &pdev->dev; +- struct device_node *node = dev->of_node; + struct resource *ioresource; + + /* Allocate buffers and instance data */ +@@ -157,6 +156,15 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + + inst->dev = dev; + ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (ioresource) { ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ dev_err(inst->dev, "failed to get IO resource"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ + /* Create character device entries */ + + err = alloc_chrdev_region(&bcm2835_gpiomem_devid, +@@ -187,20 +195,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + if (IS_ERR(ptr_err)) + goto failed_device_create; + +- /* Get address from device tree if available (*_resource() correctly +- converts the bus address in device tree to a physical address), +- or use hardcoded offset + BCM2708_PERI_BASE if not. +- (In spite of its name 2708 actually seems to have the correct +- mach-dependent value on 2709 etc, as it is defined in +- mach-bcm270x/platform.h) */ +- +- if (node) { +- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- inst->gpio_regs_phys = ioresource->start; +- } else { +- inst->gpio_regs_phys = GPIO_BASE; +- } +- + dev_info(inst->dev, "Initialised: Registers at 0x%08lx", + inst->gpio_regs_phys); + +@@ -214,6 +208,7 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + failed_cdev_add: + unregister_chrdev_region(bcm2835_gpiomem_devid, 1); + failed_alloc_chrdev: ++failed_get_resource: + kfree(inst); + failed_inst_alloc: + dev_err(inst->dev, "could not load bcm2835_gpiomem"); + +From b21b82f99f3bd05b70800c2722ac254eaf707224 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 8 Oct 2015 13:33:28 +0100 +Subject: [PATCH 201/278] scripts/mkknlimg: Improve ARCH_BCM2835 detection + +The board support code contains sufficient strings to be able to +distinguish 2708 vs. 2835 builds, so remove the check for +bcm2835-pm-wdt which could exist in either. + +Also, since the canned configuration is no longer built in (it's +a module), remove the config string checking. + +See: https://github.com/raspberrypi/linux/issues/1157 +--- + scripts/mkknlimg | 41 +++++------------------------------------ + 1 file changed, 5 insertions(+), 36 deletions(-) + +diff --git a/scripts/mkknlimg b/scripts/mkknlimg +index 3dff948..3998d43 100755 +--- a/scripts/mkknlimg ++++ b/scripts/mkknlimg +@@ -50,12 +50,6 @@ if (! -r $kernel_file) + usage(); + } + +-my @wanted_config_lines = +-( +- 'CONFIG_BCM2708_DT', +- 'CONFIG_ARCH_BCM2835' +-); +- + my @wanted_strings = + ( + 'bcm2708_fb', +@@ -63,7 +57,8 @@ my @wanted_strings = + 'brcm,bcm2835-sdhost', + 'brcm,bcm2708-pinctrl', + 'brcm,bcm2835-gpio', +- 'brcm,bcm2835-pm-wdt' ++ 'brcm,bcm2835', ++ 'brcm,bcm2836' + ); + + my $res = try_extract($kernel_file, $tmpfile1); +@@ -98,12 +93,11 @@ if ($res) + config_bool($res, 'brcm,bcm2835-mmc') || + config_bool($res, 'brcm,bcm2835-sdhost')) + { +- $dtok ||= config_bool($res, 'CONFIG_BCM2708_DT'); +- $dtok ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); + $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl'); + $dtok ||= config_bool($res, 'brcm,bcm2835-gpio'); +- $is_283x ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); +- $is_283x ||= config_bool($res, 'brcm,bcm2835-pm-wdt'); ++ $is_283x ||= config_bool($res, 'brcm,bcm2835'); ++ $is_283x ||= config_bool($res, 'brcm,bcm2836'); ++ $dtok ||= $is_283x; + $append_trailer = 1; + } + else +@@ -205,31 +199,6 @@ sub try_extract + $res->{$match} = 1; + } + +- my $config_pattern = '^('.join('|', @wanted_config_lines).')=(.*)$'; +- my $cf1 = 'IKCFG_ST\037\213\010'; +- my $cf2 = '0123456789'; +- +- my $pos = `tr "$cf1\n$cf2" "\n$cf2=" < "$knl" | grep -abo "^$cf2"`; +- if ($pos) +- { +- $pos =~ s/:.*[\r\n]*$//s; +- $pos += 8; +- my $err = (system("tail -c+$pos \"$knl\" | zcat > $tmp 2> /dev/null") >> 8); +- if (($err == 0) || ($err == 2)) +- { +- if (open(my $fh, '<', $tmp)) +- { +- while (my $line = <$fh>) +- { +- chomp($line); +- $res->{$1} = $2 if ($line =~ /$config_pattern/); +- } +- +- close($fh); +- } +- } +- } +- + return $res; + } + + +From 8f7cf07cccdc8a867d3b413156038d15142fa8fa Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 9 Oct 2015 10:49:00 +0100 +Subject: [PATCH 202/278] BCM270X_DT: Make mmc overlay compatible with current + firmware + +The original DT overlay logic followed a merge-then-patch procedure, +i.e. parameters are applied to the loaded overlay before the overlay +is merged into the base DTB. This sequence has been changed to +patch-then-merge, in order to support parameterised node names, and +to protect against bad overlays. As a result, overrides (parameters) +must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB. + +mmc-overlay.dts (that switches back to the original mmc sdcard +driver) is the only overlay violating that rule, and this patch +fixes it. +--- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 0a37cf4..4579ff2 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -7,13 +7,13 @@ + fragment@0 { + target = <&mmc>; + +- __overlay__ { ++ frag0: __overlay__ { + brcm,overclock-50 = <0>; + }; + }; + + __overrides__ { +- overclock_50 = <&mmc>,"brcm,overclock-50:0"; +- force_pio = <&mmc>,"brcm,force-pio?"; ++ overclock_50 = <&frag0>,"brcm,overclock-50:0"; ++ force_pio = <&frag0>,"brcm,force-pio?"; + }; + }; + +From 2ff4df2d402e49fd86a179ec9a6145d35c6a9b1a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 12 Oct 2015 08:52:00 +0100 +Subject: [PATCH 203/278] BCM270X_DT: Reduce default at86rf233 SPI frequency + +The AT86RF233 has been found to be unreliable on a 7.5MHz SPI bus, +so reduce the default frequency to 6MHz. + +See: https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/README | 2 +- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 68b608b..970d37e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -178,7 +178,7 @@ Load: dtoverlay=at86rf233,= + Params: interrupt GPIO used for INT (default 23) + reset GPIO used for Reset (default 24) + sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 750000) ++ speed SPI bus speed in Hz (default 6000000) + trim Fine tuning of the internal capacitance + arrays (0=+0pF, 15=+4.5pF, default 15) + +diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +index 70f50ea..0460269 100644 +--- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts ++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +@@ -25,7 +25,7 @@ + interrupts = <23 4>; /* active high */ + reset-gpio = <&gpio 24 1>; + sleep-gpio = <&gpio 25 1>; +- spi-max-frequency = <7500000>; ++ spi-max-frequency = <6000000>; + xtal-trim = /bits/ 8 <0xf>; + }; + }; + +From 4842bf44119f87f6cff2bb0158b3d62b8fd3b4cc Mon Sep 17 00:00:00 2001 +From: mwilliams03 +Date: Sun, 18 Oct 2015 17:07:24 -0700 +Subject: [PATCH 204/278] New overlay for PiScreen2r + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 14 +++ + arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++ + 3 files changed, 115 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 6de04be..b36b8e3 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 970d37e..b605dc4e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -411,6 +411,20 @@ Params: speed Display SPI bus speed + xohms Touchpanel sensitivity (X-plate resistance) + + ++Name: piscreen2r ++Info: PiScreen 2 with resistive TP display by OzzMaker.com ++Load: dtoverlay=piscreen,= ++Params: speed Display SPI bus speed ++ ++ rotate Display rotation {0,90,180,270} ++ ++ fps Delay between frame updates ++ ++ debug Debug output level {0-7} ++ ++ xohms Touchpanel sensitivity (X-plate resistance) ++ ++ + Name: pitft28-resistive + Info: Adafruit PiTFT 2.8" resistive touch screen + Load: dtoverlay=pitft28-resistive,= +diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +new file mode 100644 +index 0000000..7c018e0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +@@ -0,0 +1,100 @@ ++ /* ++ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ piscreen2_pins: piscreen2_pins { ++ brcm,pins = <17 25 24 22>; ++ brcm,function = <0 1 1 1>; /* in out out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ piscreen2: piscreen2@0{ ++ compatible = "ilitek,ili9486"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&piscreen2_pins>; ++ bgr; ++ spi-max-frequency = <64000000>; ++ rotate = <90>; ++ fps = <30>; ++ buswidth = <8>; ++ regwidth = <16>; ++ txbuflen = <32768>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 22 1>; ++ debug = <0>; ++ ++ init = <0x10000b0 0x00 ++ 0x1000011 ++ 0x20000ff ++ 0x100003a 0x55 ++ 0x1000036 0x28 ++ 0x10000c0 0x11 0x09 ++ 0x10000c1 0x41 ++ 0x10000c5 0x00 0x00 0x00 0x00 ++ 0x10000b6 0x00 0x02 ++ 0x10000f7 0xa9 0x51 0x2c 0x2 ++ 0x10000be 0x00 0x04 ++ 0x10000e9 0x00 ++ 0x1000011 ++ 0x1000029>; ++ ++ }; ++ ++ piscreen2_ts: piscreen2-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,swap-xy; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&piscreen2>,"spi-max-frequency:0"; ++ rotate = <&piscreen2>,"rotate:0"; ++ fps = <&piscreen2>,"fps:0"; ++ debug = <&piscreen2>,"debug:0"; ++ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; ++ + +From 7316bdce9228750ba92627dfbb9836dba652c639 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 194/204] rpi_display: add backlight driver and overlay +Subject: [PATCH 205/278] 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 @@ -150272,10 +151438,10 @@ Signed-off-by: Gordon Hollingworth create mode 100644 drivers/video/backlight/rpi_backlight.c diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index 192bda7..2e82be5 100644 +index b36b8e3..f4b2817 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -38,6 +38,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb +@@ -40,6 +40,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb @@ -150284,10 +151450,10 @@ index 192bda7..2e82be5 100644 dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 4ab4c695..b57bd11 100644 +index b605dc4e..42a5876 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -463,6 +463,12 @@ Load: dtoverlay=raspidac3 +@@ -490,6 +490,12 @@ Load: dtoverlay=raspidac3 Params: @@ -150328,10 +151494,10 @@ index 0000000..c021d02 + }; +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 60f8357..6f4021b 100644 +index 630da1b..fb402e8 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -802,6 +802,7 @@ CONFIG_FB_BCM2708=y +@@ -808,6 +808,7 @@ CONFIG_FB_BCM2708=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m # CONFIG_BACKLIGHT_GENERIC is not set @@ -150340,10 +151506,10 @@ index 60f8357..6f4021b 100644 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 8ebc8d5..015540b 100644 +index df4cebc..eb81555e 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -795,6 +795,7 @@ CONFIG_FB_BCM2708=y +@@ -801,6 +801,7 @@ CONFIG_FB_BCM2708=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m # CONFIG_BACKLIGHT_GENERIC is not set @@ -150517,251 +151683,720 @@ index d3933af..ffb0f82 100644 RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, +From 8b9ee2dffa3104f41e9b9a6a956ca7e2151bd266 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Fri, 2 Oct 2015 11:30:11 -0700 +Subject: [PATCH 207/278] Input: add support for FocalTech FT6236 touchscreen + controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +This adds support for the FT6x06 and the FT6x36 family of capacitive touch +panel controllers, in particular the FT6236. -From ed66fe22cf07f1240e693bf6e7628ac9c42d36d4 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 6 Oct 2015 10:16:58 +0100 -Subject: [PATCH 196/204] bcm2835-gpiomem: Fix for ARCH_BCM2835 builds - -Build on ARCH_BCM2835, and fail to probe if no IO resource. - -See: https://github.com/raspberrypi/linux/issues/1154 +Signed-off-by: Noralf Trønnes +Signed-off-by: Dmitry Torokhov --- - drivers/char/broadcom/bcm2835-gpiomem.c | 25 ++++++++++--------------- - 1 file changed, 10 insertions(+), 15 deletions(-) + .../input/touchscreen/focaltech-ft6236.txt | 35 +++ + .../devicetree/bindings/vendor-prefixes.txt | 1 + + drivers/input/touchscreen/Kconfig | 13 + + drivers/input/touchscreen/Makefile | 1 + + drivers/input/touchscreen/ft6236.c | 327 +++++++++++++++++++++ + 5 files changed, 377 insertions(+) + create mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt + create mode 100644 drivers/input/touchscreen/ft6236.c -diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c -index 0085e13..911f5b7 100644 ---- a/drivers/char/broadcom/bcm2835-gpiomem.c -+++ b/drivers/char/broadcom/bcm2835-gpiomem.c -@@ -143,7 +143,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - int err; - void *ptr_err; - struct device *dev = &pdev->dev; -- struct device_node *node = dev->of_node; - struct resource *ioresource; +diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt +new file mode 100644 +index 0000000..777521d +--- /dev/null ++++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt +@@ -0,0 +1,35 @@ ++* FocalTech FT6236 I2C touchscreen controller ++ ++Required properties: ++ - compatible : "focaltech,ft6236" ++ - reg : I2C slave address of the chip (0x38) ++ - interrupt-parent : a phandle pointing to the interrupt controller ++ serving the interrupt for this chip ++ - interrupts : interrupt specification for the touch controller ++ interrupt ++ - reset-gpios : GPIO specification for the RSTN input ++ - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) ++ - touchscreen-size-y : vertical resolution of touchscreen (in pixels) ++ ++Optional properties: ++ - touchscreen-fuzz-x : horizontal noise value of the absolute input ++ device (in pixels) ++ - touchscreen-fuzz-y : vertical noise value of the absolute input ++ device (in pixels) ++ - touchscreen-inverted-x : X axis is inverted (boolean) ++ - touchscreen-inverted-y : Y axis is inverted (boolean) ++ - touchscreen-swapped-x-y: X and Y axis are swapped (boolean) ++ Swapping is done after inverting the axis ++ ++Example: ++ ++ ft6x06@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ interrupt-parent = <&gpio>; ++ interrupts = <23 2>; ++ touchscreen-size-x = <320>; ++ touchscreen-size-y = <480>; ++ touchscreen-inverted-x; ++ touchscreen-swapped-x-y; ++ }; +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 80339192..08490ef 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -76,6 +76,7 @@ everspin Everspin Technologies, Inc. + excito Excito + fcs Fairchild Semiconductor + firefly Firefly ++focaltech FocalTech Systems Co.,Ltd + fsl Freescale Semiconductor + GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. + gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index d7e74a1..6536cd2 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -295,6 +295,19 @@ config TOUCHSCREEN_EGALAX + To compile this driver as a module, choose M here: the + module will be called egalax_ts. - /* Allocate buffers and instance data */ -@@ -157,6 +156,15 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - - inst->dev = dev; - -+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (ioresource) { -+ inst->gpio_regs_phys = ioresource->start; -+ } else { -+ dev_err(inst->dev, "failed to get IO resource"); -+ err = -ENOENT; -+ goto failed_get_resource; ++config TOUCHSCREEN_FT6236 ++ tristate "FT6236 I2C touchscreen" ++ depends on I2C ++ depends on GPIOLIB || COMPILE_TEST ++ help ++ Say Y here to enable support for the I2C connected FT6x06 and ++ FT6x36 family of capacitive touchscreen drivers. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ft6236. ++ + config TOUCHSCREEN_FUJITSU + tristate "Fujitsu serial touchscreen" + select SERIO +diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile +index a1be09f..c867f82 100644 +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -36,6 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o + obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o + obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o ++obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o + obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +new file mode 100644 +index 0000000..cccae19 +--- /dev/null ++++ b/drivers/input/touchscreen/ft6236.c +@@ -0,0 +1,327 @@ ++/* ++ * FocalTech FT6236 TouchScreen driver. ++ * ++ * Copyright (c) 2010 Focal tech Ltd. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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 ++ ++#define FT6236_MAX_TOUCH_POINTS 2 ++ ++#define FT6236_REG_TH_GROUP 0x80 ++#define FT6236_REG_PERIODACTIVE 0x88 ++#define FT6236_REG_LIB_VER_H 0xa1 ++#define FT6236_REG_LIB_VER_L 0xa2 ++#define FT6236_REG_CIPHER 0xa3 ++#define FT6236_REG_FIRMID 0xa6 ++#define FT6236_REG_FOCALTECH_ID 0xa8 ++#define FT6236_REG_RELEASE_CODE_ID 0xaf ++ ++#define FT6236_EVENT_PRESS_DOWN 0 ++#define FT6236_EVENT_LIFT_UP 1 ++#define FT6236_EVENT_CONTACT 2 ++#define FT6236_EVENT_NO_EVENT 3 ++ ++struct ft6236_data { ++ struct i2c_client *client; ++ struct input_dev *input; ++ struct gpio_desc *reset_gpio; ++ u32 max_x; ++ u32 max_y; ++ bool invert_x; ++ bool invert_y; ++ bool swap_xy; ++}; ++ ++/* ++ * This struct is a touchpoint as stored in hardware. Note that the id, ++ * as well as the event, are stored in the upper nybble of the hi byte. ++ */ ++struct ft6236_touchpoint { ++ union { ++ u8 xhi; ++ u8 event; ++ }; ++ u8 xlo; ++ union { ++ u8 yhi; ++ u8 id; ++ }; ++ u8 ylo; ++ u8 weight; ++ u8 misc; ++} __packed; ++ ++/* This packet represents the register map as read from offset 0 */ ++struct ft6236_packet { ++ u8 dev_mode; ++ u8 gest_id; ++ u8 touches; ++ struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; ++} __packed; ++ ++static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) ++{ ++ int error; ++ ++ error = i2c_smbus_read_i2c_block_data(client, reg, len, data); ++ if (error < 0) ++ return error; ++ ++ if (error != len) ++ return -EIO; ++ ++ return 0; ++} ++ ++static irqreturn_t ft6236_interrupt(int irq, void *dev_id) ++{ ++ struct ft6236_data *ft6236 = dev_id; ++ struct device *dev = &ft6236->client->dev; ++ struct input_dev *input = ft6236->input; ++ struct ft6236_packet buf; ++ u8 touches; ++ int i, error; ++ ++ error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); ++ if (error) { ++ dev_err(dev, "read touchdata failed %d\n", error); ++ return IRQ_HANDLED; + } + - /* Create character device entries */ - - err = alloc_chrdev_region(&bcm2835_gpiomem_devid, -@@ -187,20 +195,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - if (IS_ERR(ptr_err)) - goto failed_device_create; - -- /* Get address from device tree if available (*_resource() correctly -- converts the bus address in device tree to a physical address), -- or use hardcoded offset + BCM2708_PERI_BASE if not. -- (In spite of its name 2708 actually seems to have the correct -- mach-dependent value on 2709 etc, as it is defined in -- mach-bcm270x/platform.h) */ -- -- if (node) { -- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- inst->gpio_regs_phys = ioresource->start; -- } else { -- inst->gpio_regs_phys = GPIO_BASE; -- } -- - dev_info(inst->dev, "Initialised: Registers at 0x%08lx", - inst->gpio_regs_phys); - -@@ -214,6 +208,7 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - failed_cdev_add: - unregister_chrdev_region(bcm2835_gpiomem_devid, 1); - failed_alloc_chrdev: -+failed_get_resource: - kfree(inst); - failed_inst_alloc: - dev_err(inst->dev, "could not load bcm2835_gpiomem"); ++ touches = buf.touches & 0xf; ++ if (touches > FT6236_MAX_TOUCH_POINTS) { ++ dev_dbg(dev, ++ "%d touch points reported, only %d are supported\n", ++ touches, FT6236_MAX_TOUCH_POINTS); ++ touches = FT6236_MAX_TOUCH_POINTS; ++ } ++ ++ for (i = 0; i < touches; i++) { ++ struct ft6236_touchpoint *point = &buf.points[i]; ++ u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; ++ u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; ++ u8 event = point->event >> 6; ++ u8 id = point->id >> 4; ++ bool act = (event == FT6236_EVENT_PRESS_DOWN || ++ event == FT6236_EVENT_CONTACT); ++ ++ input_mt_slot(input, id); ++ input_mt_report_slot_state(input, MT_TOOL_FINGER, act); ++ if (!act) ++ continue; ++ ++ if (ft6236->invert_x) ++ x = ft6236->max_x - x; ++ ++ if (ft6236->invert_y) ++ y = ft6236->max_y - y; ++ ++ if (ft6236->swap_xy) { ++ input_report_abs(input, ABS_MT_POSITION_X, y); ++ input_report_abs(input, ABS_MT_POSITION_Y, x); ++ } else { ++ input_report_abs(input, ABS_MT_POSITION_X, x); ++ input_report_abs(input, ABS_MT_POSITION_Y, y); ++ } ++ } ++ ++ input_mt_sync_frame(input); ++ input_sync(input); ++ ++ return IRQ_HANDLED; ++} ++ ++static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) ++{ ++ struct i2c_client *client = ft6236->client; ++ u8 val = 0; ++ int error; ++ ++ error = ft6236_read(client, reg, 1, &val); ++ if (error) ++ dev_dbg(&client->dev, ++ "error reading register 0x%02x: %d\n", reg, error); ++ ++ return val; ++} ++ ++static void ft6236_debug_info(struct ft6236_data *ft6236) ++{ ++ struct device *dev = &ft6236->client->dev; ++ ++ dev_dbg(dev, "Touch threshold is %d\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); ++ dev_dbg(dev, "Report rate is %dHz\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); ++ dev_dbg(dev, "Firmware library version 0x%02x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), ++ ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); ++ dev_dbg(dev, "Firmware version 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); ++ dev_dbg(dev, "Chip vendor ID 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); ++ dev_dbg(dev, "CTPM vendor ID 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); ++ dev_dbg(dev, "Release code version 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); ++} ++ ++static void ft6236_reset(struct ft6236_data *ft6236) ++{ ++ if (!ft6236->reset_gpio) ++ return; ++ ++ gpiod_set_value_cansleep(ft6236->reset_gpio, 1); ++ usleep_range(5000, 20000); ++ gpiod_set_value_cansleep(ft6236->reset_gpio, 0); ++ msleep(300); ++} ++ ++static int ft6236_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct ft6236_data *ft6236; ++ struct input_dev *input; ++ u32 fuzz_x = 0, fuzz_y = 0; ++ u8 val; ++ int error; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -ENXIO; ++ ++ if (!client->irq) { ++ dev_err(dev, "irq is missing\n"); ++ return -EINVAL; ++ } ++ ++ ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); ++ if (!ft6236) ++ return -ENOMEM; ++ ++ ft6236->client = client; ++ ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ft6236->reset_gpio)) { ++ error = PTR_ERR(ft6236->reset_gpio); ++ if (error != -EPROBE_DEFER) ++ dev_err(dev, "error getting reset gpio: %d\n", error); ++ return error; ++ } ++ ++ ft6236_reset(ft6236); ++ ++ /* verify that the controller is present */ ++ error = ft6236_read(client, 0x00, 1, &val); ++ if (error) { ++ dev_err(dev, "failed to read from controller: %d\n", error); ++ return error; ++ } ++ ++ ft6236_debug_info(ft6236); ++ ++ input = devm_input_allocate_device(dev); ++ if (!input) ++ return -ENOMEM; ++ ++ ft6236->input = input; ++ input->name = client->name; ++ input->id.bustype = BUS_I2C; ++ ++ if (device_property_read_u32(dev, "touchscreen-size-x", ++ &ft6236->max_x) || ++ device_property_read_u32(dev, "touchscreen-size-y", ++ &ft6236->max_y)) { ++ dev_err(dev, "touchscreen-size-x and/or -y missing\n"); ++ return -EINVAL; ++ } ++ ++ device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); ++ device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); ++ ft6236->invert_x = device_property_read_bool(dev, ++ "touchscreen-inverted-x"); ++ ft6236->invert_y = device_property_read_bool(dev, ++ "touchscreen-inverted-y"); ++ ft6236->swap_xy = device_property_read_bool(dev, ++ "touchscreen-swapped-x-y"); ++ ++ if (ft6236->swap_xy) { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, ++ ft6236->max_y, fuzz_y, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ++ ft6236->max_x, fuzz_x, 0); ++ } else { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, ++ ft6236->max_x, fuzz_x, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ++ ft6236->max_y, fuzz_y, 0); ++ } ++ ++ error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, ++ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); ++ if (error) ++ return error; ++ ++ error = devm_request_threaded_irq(dev, client->irq, NULL, ++ ft6236_interrupt, IRQF_ONESHOT, ++ client->name, ft6236); ++ if (error) { ++ dev_err(dev, "request irq %d failed: %d\n", client->irq, error); ++ return error; ++ } ++ ++ error = input_register_device(input); ++ if (error) { ++ dev_err(dev, "failed to register input device: %d\n", error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id ft6236_of_match[] = { ++ { .compatible = "focaltech,ft6236", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ft6236_of_match); ++#endif ++ ++static const struct i2c_device_id ft6236_id[] = { ++ { "ft6236", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ft6236_id); ++ ++static struct i2c_driver ft6236_driver = { ++ .driver = { ++ .name = "ft6236", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ft6236_of_match), ++ }, ++ .probe = ft6236_probe, ++ .id_table = ft6236_id, ++}; ++module_i2c_driver(ft6236_driver); ++ ++MODULE_AUTHOR("Sean Cross "); ++MODULE_AUTHOR("Noralf Trønnes "); ++MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); ++MODULE_LICENSE("GPL"); -From 9223ca1be3362490e689e00156fa792e04910284 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 5 Oct 2015 10:47:45 +0100 -Subject: [PATCH 197/204] BCM270X_DT: Add at86rf233 overlay +From dae7385cf2bf7503293d4af49bb713fbe8f2d62e Mon Sep 17 00:00:00 2001 +From: Fengguang Wu +Date: Tue, 6 Oct 2015 15:37:02 -0700 +Subject: [PATCH 208/278] Input: ft6236 - do not explicitly set driver's owner -Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0. +There is no need to explicitly set .owner for the driver, the core will do +it for us. -See: https://github.com/raspberrypi/linux/issues/1151 +Signed-off-by: Fengguang Wu +Signed-off-by: Dmitry Torokhov --- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 21 +++++++-- - arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++ - 3 files changed, 72 insertions(+), 4 deletions(-) - create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts + drivers/input/touchscreen/ft6236.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +index cccae19..a394cd4 100644 +--- a/drivers/input/touchscreen/ft6236.c ++++ b/drivers/input/touchscreen/ft6236.c +@@ -313,7 +313,6 @@ MODULE_DEVICE_TABLE(i2c, ft6236_id); + static struct i2c_driver ft6236_driver = { + .driver = { + .name = "ft6236", +- .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ft6236_of_match), + }, + .probe = ft6236_probe, + +From 12714b8017bece4a80e431ab321b8b346656e243 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Tue, 6 Oct 2015 17:00:36 -0700 +Subject: [PATCH 209/278] Input: ft6236 - change module license string to match + copyright notice + +The copyright/license notice says that the code is licensed under GPL v2 +only (not GPL v2+), so let's use proper string in MODULE_LICENSE(). + +Signed-off-by: Dmitry Torokhov +--- + drivers/input/touchscreen/ft6236.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +index a394cd4..d240d2e 100644 +--- a/drivers/input/touchscreen/ft6236.c ++++ b/drivers/input/touchscreen/ft6236.c +@@ -323,4 +323,4 @@ module_i2c_driver(ft6236_driver); + MODULE_AUTHOR("Sean Cross "); + MODULE_AUTHOR("Noralf Trønnes "); + MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL v2"); + +From a48e386718a983c1b1bd6f7d1fa6002fad4d56c3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Mon, 26 Oct 2015 14:42:10 +0100 +Subject: [PATCH 210/278] config: Add TOUCHSCREEN_FT6236 + +--- + 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 fb402e8..130a30c0 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -551,6 +551,7 @@ CONFIG_JOYSTICK_RPISENSE=m + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m + CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_FT6236=m + CONFIG_TOUCHSCREEN_RPI_FT5406=m + CONFIG_TOUCHSCREEN_USB_COMPOSITE=m + CONFIG_TOUCHSCREEN_STMPE=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index eb81555e..fbdfa91 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -544,6 +544,7 @@ CONFIG_JOYSTICK_RPISENSE=m + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m + CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_FT6236=m + CONFIG_TOUCHSCREEN_RPI_FT5406=m + CONFIG_TOUCHSCREEN_USB_COMPOSITE=m + CONFIG_TOUCHSCREEN_STMPE=m + +From d321f1163cf92999b2b8a8fbcf88a8ee246312fa Mon Sep 17 00:00:00 2001 +From: Alistair Buxton +Date: Sun, 1 Nov 2015 22:27:56 +0000 +Subject: [PATCH 211/278] Build i2c_gpio module and add a device tree overlay + to configure it. + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 11 ++++++++++ + arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 28 +++++++++++++++++++++++++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + 5 files changed, 42 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index 2e82be5..b370eb0 100644 +index f4b2817..84c1566 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y) - endif - - dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb -+dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb +@@ -25,6 +25,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index b57bd11..014675a 100644 +index 42a5876..46149ea 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -69,13 +69,14 @@ DT parameters: - - Parameters always have default values, although in some cases (e.g. "w1-gpio") - it is necessary to provided multiple overlays in order to get the desired --behaviour. See the list of overlays below for a description of the parameters and their defaults. -+behaviour. See the list of overlays below for a description of the parameters -+and their defaults. - - The Overlay and Parameter Reference - =================================== - --N.B. When editing this file, please preserve the indentation levels to make it simple to parse --programmatically. NO HARD TABS. -+N.B. When editing this file, please preserve the indentation levels to make it -+simple to parse programmatically. NO HARD TABS. +@@ -284,6 +284,17 @@ Params: speed Display SPI bus speed + ledgpio GPIO used to control backlight - Name: -@@ -149,7 +150,7 @@ Name: ads7846 - Info: ADS7846 Touch controller - Load: dtoverlay=ads7846,= - Params: cs SPI bus Chip Select (default 1) -- speed SPI bus speed (default 2Mhz, max 3.25MHz) -+ speed SPI bus speed (default 2MHz, max 3.25MHz) - penirq GPIO used for PENIRQ. REQUIRED - penirq_pull Set GPIO pull (default 0=none, 2=pullup) - swapxy Swap x and y axis -@@ -170,6 +171,18 @@ Params: cs SPI bus Chip Select (default 1) - www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt - - -+Name: at86rf233 -+Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, -+ connected to spi0.0 -+Load: dtoverlay=at86rf233,= -+Params: interrupt GPIO used for INT (default 23) -+ reset GPIO used for Reset (default 24) -+ sleep GPIO used for Sleep (default 25) -+ speed SPI bus speed in Hz (default 750000) -+ trim Fine tuning of the internal capacitance -+ arrays (0=+0pF, 15=+4.5pF, default 15) ++Name: i2c-gpio ++Info: Adds support for software i2c controller on gpio pins ++Load: dtoverlay=i2c-gpio, ++Params: i2c_gpio_sda GPIO used for I2C data (default "23") ++ ++ i2c_gpio_scl GPIO used for I2C clock (default "24") ++ ++ i2c_gpio_delay_us Clock delay in microseconds ++ (default "2" = ~100kHz) + + - Name: bmp085_i2c-sensor - Info: Configures the BMP085/BMP180 digital barometric pressure and temperature - sensors from Bosch Sensortec -diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices + Load: dtoverlay=i2c-rtc, +diff --git a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts new file mode 100644 -index 0000000..70f50ea +index 0000000..2a2dc98 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts -@@ -0,0 +1,54 @@ ++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts +@@ -0,0 +1,28 @@ ++// Overlay for i2c_gpio bitbanging host bus. +/dts-v1/; +/plugin/; + -+/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */ -+ +/ { -+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ compatible = "brcm,bcm2708"; + + fragment@0 { -+ target = <&spi0>; ++ target-path = "/"; + __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ lowpan0: at86rf233@0 { -+ compatible = "atmel,at86rf233"; -+ reg = <0>; -+ interrupt-parent = <&gpio>; -+ interrupts = <23 4>; /* active high */ -+ reset-gpio = <&gpio 24 1>; -+ sleep-gpio = <&gpio 25 1>; -+ spi-max-frequency = <7500000>; -+ xtal-trim = /bits/ 8 <0xf>; ++ i2c_gpio: i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&gpio 23 0 /* sda */ ++ &gpio 24 0 /* scl */ ++ >; ++ i2c-gpio,delay-us = <2>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; + }; + }; + }; -+ -+ fragment@1 { -+ target = <&gpio>; -+ __overlay__ { -+ lowpan0_pins: lowpan0_pins { -+ brcm,pins = <23 24 25>; -+ brcm,function = <0 1 1>; /* in out out */ -+ }; -+ }; -+ }; -+ + __overrides__ { -+ interrupt = <&lowpan0>, "interrupts:0", -+ <&lowpan0_pins>, "brcm,pins:0"; -+ reset = <&lowpan0>, "reset-gpio:4", -+ <&lowpan0_pins>, "brcm,pins:4"; -+ sleep = <&lowpan0>, "sleep-gpio:4", -+ <&lowpan0_pins>, "brcm,pins:8"; -+ speed = <&lowpan0>, "spi-max-frequency:0"; -+ trim = <&lowpan0>, "xtal-trim.0"; ++ i2c_gpio_sda = <&i2c_gpio>,"gpios:4"; ++ i2c_gpio_scl = <&i2c_gpio>,"gpios:16"; ++ i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0"; + }; +}; ++ +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 130a30c0..f87e8b6 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -595,6 +595,7 @@ CONFIG_BCM_VC_SM=y + CONFIG_I2C=y + CONFIG_I2C_CHARDEV=m + CONFIG_I2C_BCM2708=m ++CONFIG_I2C_GPIO=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index fbdfa91..214b9b6 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -588,6 +588,7 @@ CONFIG_BCM_VC_SM=y + CONFIG_I2C=y + CONFIG_I2C_CHARDEV=m + CONFIG_I2C_BCM2708=m ++CONFIG_I2C_GPIO=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m -From c089bd70a6d37cb4a05626d48eaebcdfcef0bf41 Mon Sep 17 00:00:00 2001 -From: mwilliams03 -Date: Sun, 18 Oct 2015 17:07:24 -0700 -Subject: [PATCH 198/204] New overlay for PiScreen2r +From 2ae0a4766fe7c891c3ce5be714a80787a227a274 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 5 Nov 2015 12:01:53 +0000 +Subject: [PATCH 212/278] config: Add MCP320X + +See: https://github.com/raspberrypi/linux/issues/1189 +--- + 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 f87e8b6..d789c51 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1106,6 +1106,7 @@ CONFIG_IIO=m + CONFIG_IIO_BUFFER=y + CONFIG_IIO_BUFFER_CB=y + CONFIG_IIO_KFIFO_BUF=m ++CONFIG_MCP320X=m + CONFIG_DHT11=m + CONFIG_PWM_BCM2835=m + CONFIG_RASPBERRYPI_FIRMWARE=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 214b9b6..d658aa7 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1099,6 +1099,7 @@ CONFIG_IIO=m + CONFIG_IIO_BUFFER=y + CONFIG_IIO_BUFFER_CB=y + CONFIG_IIO_KFIFO_BUF=m ++CONFIG_MCP320X=m + CONFIG_DHT11=m + CONFIG_PWM_BCM2835=m + CONFIG_RASPBERRYPI_FIRMWARE=y + +From 7fefb6e593bf0478edbcd0266cac3af9a6856610 Mon Sep 17 00:00:00 2001 +From: Ondrej Wisniewski +Date: Fri, 6 Nov 2015 15:01:28 +0100 +Subject: [PATCH 213/278] dts: Added overlay for Adafruit PiTFT 2.8" capacitive + touch screen --- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 14 +++ - arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++ - 3 files changed, 115 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 22 ++++++ + .../dts/overlays/pitft28-capacitive-overlay.dts | 88 ++++++++++++++++++++++ + 3 files changed, 111 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index b370eb0..f4b2817 100644 +index 84c1566..3df97bb 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb +@@ -36,6 +36,7 @@ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb -+dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 014675a..3276312 100644 +index 46149ea..db4a77b 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -411,6 +411,20 @@ Params: speed Display SPI bus speed +@@ -436,6 +436,28 @@ Params: speed Display SPI bus speed xohms Touchpanel sensitivity (X-plate resistance) -+Name: piscreen2r -+Info: PiScreen 2 with resistive TP display by OzzMaker.com -+Load: dtoverlay=piscreen,= ++Name: pitft28-capacitive ++Info: Adafruit PiTFT 2.8" capacitive touch screen ++Load: dtoverlay=pitft28-capacitive,= +Params: speed Display SPI bus speed + + rotate Display rotation {0,90,180,270} @@ -150770,20 +152405,28 @@ index 014675a..3276312 100644 + + debug Debug output level {0-7} + -+ xohms Touchpanel sensitivity (X-plate resistance) ++ touch-sizex Touchscreen size x (default 240) ++ ++ touch-sizey Touchscreen size y (default 320) ++ ++ touch-invx Touchscreen inverted x axis ++ ++ touch-invy Touchscreen inverted y axis ++ ++ touch-swapxy Touchscreen swapped x y axis + + Name: pitft28-resistive Info: Adafruit PiTFT 2.8" resistive touch screen Load: dtoverlay=pitft28-resistive,= -diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts new file mode 100644 -index 0000000..7c018e0 +index 0000000..48920e9 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts -@@ -0,0 +1,100 @@ -+ /* -+ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com ++++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts +@@ -0,0 +1,88 @@ ++/* ++ * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen + * + */ + @@ -150791,400 +152434,17955 @@ index 0000000..7c018e0 +/plugin/; + +/ { -+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ pitft_pins: pitft_pins { ++ brcm,pins = <24 25>; ++ brcm,function = <0 1>; /* in out */ ++ brcm,pull = <2 0>; /* pullup none */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pitft: pitft@0{ ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pitft_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <90>; ++ fps = <25>; ++ bgr; ++ buswidth = <8>; ++ dc-gpios = <&gpio 25 0>; ++ debug = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c1>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ft6236: ft6236@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ ++ interrupt-parent = <&gpio>; ++ interrupts = <24 2>; ++ touchscreen-size-x = <240>; ++ touchscreen-size-y = <320>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0"; ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ touch-sizex = <&ft6236>,"touchscreen-size-x?"; ++ touch-sizey = <&ft6236>,"touchscreen-size-y?"; ++ touch-invx = <&ft6236>,"touchscreen-inverted-x?"; ++ touch-invy = <&ft6236>,"touchscreen-inverted-y?"; ++ touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?"; ++ }; ++}; + +From be1f4be48573c6cda72ed1324a5fe97f8eda5dd9 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 6 Nov 2015 16:24:59 +0000 +Subject: [PATCH 214/278] rpi-ft5406: Use interruptible sleep to avoid high + load reported + +--- + drivers/input/touchscreen/rpi-ft5406.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/rpi-ft5406.c b/drivers/input/touchscreen/rpi-ft5406.c +index c08817e..b27dbee 100644 +--- a/drivers/input/touchscreen/rpi-ft5406.c ++++ b/drivers/input/touchscreen/rpi-ft5406.c +@@ -65,7 +65,7 @@ static int ft5406_thread(void *arg) + while(!kthread_should_stop()) + { + // 60fps polling +- msleep(17); ++ msleep_interruptible(17); + memcpy_fromio(®s, ts->regs, sizeof(*ts->regs)); + writel(99, &ts->regs->num_points); + // Do not output if theres no new information (num_points is 99) + +From fe07a10d55ea6f22ef183cb8469761d21fc02909 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 11 Nov 2015 12:55:53 +0000 +Subject: [PATCH 215/278] config: ADD CONFIG_FB_UDL module (USB displaylink) + +--- + 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 d789c51..2c32293 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -807,6 +807,7 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y ++CONFIG_FB_UDL=m + CONFIG_FB_SSD1307=m + CONFIG_FB_RPISENSE=m + # CONFIG_BACKLIGHT_GENERIC is not set +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index d658aa7..c2ff887 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -800,6 +800,7 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y ++CONFIG_FB_UDL=m + CONFIG_FB_SSD1307=m + CONFIG_FB_RPISENSE=m + # CONFIG_BACKLIGHT_GENERIC is not set + +From e6d2c7de9b7041eface31625868429f1386d44e6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson <6by9@users.noreply.github.com> +Date: Tue, 14 Jul 2015 22:57:57 +0100 +Subject: [PATCH 216/278] BCM2835-V4L2: Return buffers to videobuf2 on shutdown + +https://github.com/raspberrypi/linux/issues/817 +Fixes the kernel warning from videobuf2 as buffers +are now returned as they are being flushed on +stop_streaming. +--- + drivers/media/platform/bcm2835/bcm2835-camera.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c +index 04a1711..b49b6dc3 100644 +--- a/drivers/media/platform/bcm2835/bcm2835-camera.c ++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c +@@ -404,6 +404,7 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, + } + } else { + /* signal frame completion */ ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + complete(&dev->capture.frame_cmplt); + } + } + +From 9bd52d710b4b7bfa1bcf5a805f316e10b02a8112 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 14 Nov 2015 12:24:59 +0000 +Subject: [PATCH 217/278] config: Add FB_TFT_ILI9163 module + +--- + 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 2c32293..d06b9c8 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1076,6 +1076,7 @@ CONFIG_FB_TFT_BD663474=m + CONFIG_FB_TFT_HX8340BN=m + CONFIG_FB_TFT_HX8347D=m + CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9163=m + CONFIG_FB_TFT_ILI9320=m + CONFIG_FB_TFT_ILI9325=m + CONFIG_FB_TFT_ILI9340=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index c2ff887..e04f122 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1069,6 +1069,7 @@ CONFIG_FB_TFT_BD663474=m + CONFIG_FB_TFT_HX8340BN=m + CONFIG_FB_TFT_HX8347D=m + CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9163=m + CONFIG_FB_TFT_ILI9320=m + CONFIG_FB_TFT_ILI9325=m + CONFIG_FB_TFT_ILI9340=m + +From 6137f86ef451567cf414b0330eadd60812bd5b6b Mon Sep 17 00:00:00 2001 +From: Holger Steinhaus +Date: Sat, 14 Nov 2015 18:37:43 +0100 +Subject: [PATCH 218/278] dts: Added overlay for gpio_ir_recv driver + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 16 +++++++++ + arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 45 ++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 3df97bb..1a60e9c 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -17,6 +17,7 @@ dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index db4a77b..a2db163 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -209,6 +209,22 @@ Params: int_pin GPIO used for INT (default 25) + speed SPI bus speed (default 12000000) + + ++Name: gpio-ir ++Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core- ++ based gpio_ir_recv driver maps received keys directly to a ++ /dev/input/event* device, all decoding is done by the kernel - LIRC is ++ not required! The key mapping and other decoding parameters can be ++ configured by "ir-keytable" tool. ++Load: dtoverlay=gpio-ir,= ++Params: gpio_pin Input pin number. Default is 18. ++ ++ gpio_pull Desired pull-up/down state (off, down, up) ++ Default is "down". ++ ++ rc-map-name Default rc keymap (can also be changed by ++ ir-keytable), defaults to "rc-rc6-mce" ++ ++ + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot + Load: gpio-poweroff,= +diff --git a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts +new file mode 100644 +index 0000000..a2d6bc7 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts +@@ -0,0 +1,45 @@ ++// Definitions for ir-gpio module ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ gpio_ir: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ ++ // pin number, high or low ++ gpios = <&gpio 18 1>; ++ ++ // parameter for keymap name ++ linux,rc-map-name = "rc-rc6-mce"; ++ ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ gpio_ir_pins: gpio_ir_pins { ++ brcm,pins = <18>; // pin 18 ++ brcm,function = <0>; // in ++ brcm,pull = <1>; // down ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ // parameters ++ gpio_pin = <&gpio_ir>,"gpios:4", ++ <&gpio_ir_pins>,"brcm,pins:0", ++ <&gpio_ir_pins>,"brcm,pull:0"; // pin number ++ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state ++ ++ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map ++ }; ++}; + +From fc7249d583613c11bd5d75f2a71db14d79fae137 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 17 Nov 2015 10:07:08 +0000 +Subject: [PATCH 219/278] BCM270X_DT: Fix overlay README anomalies + +--- + arch/arm/boot/dts/overlays/README | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index a2db163..df5b3e6 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -227,7 +227,7 @@ Params: gpio_pin Input pin number. Default is 18. + + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot +-Load: gpio-poweroff,= ++Load: dtoverlay=gpio-poweroff,= + Params: gpiopin GPIO for signalling (default 26) + + active_low Set if the power control device requires a +@@ -302,7 +302,7 @@ Params: speed Display SPI bus speed + + Name: i2c-gpio + Info: Adds support for software i2c controller on gpio pins +-Load: dtoverlay=i2c-gpio, ++Load: dtoverlay=i2c-gpio,= + Params: i2c_gpio_sda GPIO used for I2C data (default "23") + + i2c_gpio_scl GPIO used for I2C clock (default "24") +@@ -313,7 +313,7 @@ Params: i2c_gpio_sda GPIO used for I2C data (default "23") + + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices +-Load: dtoverlay=i2c-rtc, ++Load: dtoverlay=i2c-rtc,= + Params: ds1307 Select the DS1307 device + + ds3231 Select the DS3231 device +@@ -348,7 +348,7 @@ Params: + Name: lirc-rpi + Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi) + Consult the module documentation for more details. +-Load: dtoverlay=lirc-rpi,=,... ++Load: dtoverlay=lirc-rpi,= + Params: gpio_out_pin GPIO for output (default "17") + + gpio_in_pin GPIO for input (default "18") +@@ -440,7 +440,7 @@ Params: speed Display SPI bus speed + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com +-Load: dtoverlay=piscreen,= ++Load: dtoverlay=piscreen2r,= + Params: speed Display SPI bus speed + + rotate Display rotation {0,90,180,270} +@@ -505,7 +505,6 @@ Info: Configures a single PWM channel + 3) So be careful mixing audio and PWM. + 4) Currently the clock must have been enabled and configured + by other means. +-Load: dtoverlay=pwm-2chan,= + Load: dtoverlay=pwm,= + Params: pin Output pin (default 18) - see table + func Pin function (default 2 = Alt5) - see above +@@ -708,7 +707,7 @@ Params: gpiopin GPIO for I/O (default "4") + Name: w1-gpio-pullup + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *do* need a GPIO to drive an external pullup. +-Load: dtoverlay=w1-gpio-pullup,=,... ++Load: dtoverlay=w1-gpio-pullup,= + Params: gpiopin GPIO for I/O (default "4") + + pullup Non-zero, "on", or "y" to enable the parasitic + +From e3c114e909ea3a42bcc84781d5cc63afcf7a9c8e Mon Sep 17 00:00:00 2001 +From: wuyuehang +Date: Tue, 17 Nov 2015 09:24:41 +0800 +Subject: [PATCH 220/278] bcm2709_fb: refine appropriate behaviors to + unsupported fb ioctls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +since fbturbo introduces and use FBUNSUPPORTED ioctl on copyarea +operations for unsupported dummy ioctl which is expected to return +failure. in such scenario, bcm2709 always prompts error log. + +in order not to bother users in kernel log, we change the dev_err to +dev_dbg and return a ENOTTY other than EINVAL to let userspace handles +the return value. + +Signed-off-by: wuyuehang +Reviewed-by: popcornmix +Reviewed-by: Phil Elwell +Reviewed-by: Noralf Trønnes +--- + drivers/video/fbdev/bcm2708_fb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c +index 0f62d76..a20539a 100644 +--- a/drivers/video/fbdev/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c +@@ -442,8 +442,8 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long a + &dummy, sizeof(dummy)); + break; + default: +- dev_err(info->device, "Unknown ioctl 0x%x\n", cmd); +- return -EINVAL; ++ dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd); ++ return -ENOTTY; + } + + if (ret) + +From e2fd14f8ca274c7da18b34db3298961d68c1d95b Mon Sep 17 00:00:00 2001 +From: Patrick Boettcher +Date: Fri, 20 Nov 2015 15:09:36 +0100 +Subject: [PATCH 221/278] SDIO-overlay: add poll_once-boolean parameter + +Add paramter to toggle sdio-device-polling +done every second or once at boot-time. + +Signed-off-by: Patrick Boettcher +--- + arch/arm/boot/dts/overlays/README | 3 +++ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 6 +++++- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index df5b3e6..019928d 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -610,6 +610,9 @@ Params: overclock_50 Clock (in MHz) to use when the MMC framework + + debug Enable debug output (default off) + ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) ++ + + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 164f269..6626a1d 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -7,7 +7,7 @@ + + fragment@3 { + target = <&mmc>; +- __overlay__ { ++ sdio_mmc: __overlay__ { + compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; +@@ -26,4 +26,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ poll_once = <&sdio_mmc>,"non-removable?"; ++ }; + }; + +From 744ebedb1283cd11649381155dca86821c76bfe6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 1 Dec 2015 16:52:13 +0000 +Subject: [PATCH 222/278] BCM270X_DT: Use clk_core for I2C interfaces + +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 43 +++++++++++++++-------------------- + 1 file changed, 18 insertions(+), 25 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 933711e..66f7165 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -147,7 +147,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -186,7 +186,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e804000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -199,7 +199,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e805000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -258,56 +258,49 @@ + #address-cells = <1>; + #size-cells = <0>; + +- clk_mmc: clock@0 { ++ clk_core: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; +- clock-output-names = "mmc"; ++ clock-output-names = "core"; + clock-frequency = <250000000>; + }; + +- clk_i2c: clock@1 { ++ clk_mmc: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; +- clock-output-names = "i2c"; ++ clock-output-names = "mmc"; + clock-frequency = <250000000>; + }; + +- clk_core: clock@2 { ++ clk_uart0: clock@2 { + compatible = "fixed-clock"; + reg = <2>; + #clock-cells = <0>; +- clock-output-names = "core"; +- clock-frequency = <250000000>; +- }; +- +- clk_uart0: clock@3 { +- compatible = "fixed-clock"; +- reg = <3>; +- #clock-cells = <0>; + clock-output-names = "uart0_pclk"; + clock-frequency = <3000000>; + }; + +- clk_apb_p: clock@4 { ++ clk_apb_p: clock@3 { + compatible = "fixed-clock"; +- reg = <4>; ++ reg = <3>; + #clock-cells = <0>; + clock-output-names = "apb_pclk"; + clock-frequency = <126000000>; + }; + +- clk_pwm: clock@5 { +- compatible = "fixed-clock"; +- reg = <3>; +- #clock-cells = <0>; +- clock-output-names = "pwm"; +- clock-frequency = <100000000>; ++ clk_pwm: clock@4 { ++ compatible = "fixed-clock"; ++ reg = <4>; ++ #clock-cells = <0>; ++ clock-output-names = "pwm"; ++ clock-frequency = <100000000>; + }; + +- clk_uart1: clock@6 { ++ clk_uart1: clock@5 { + compatible = "fixed-factor-clock"; ++ reg = <5>; + clocks = <&clk_core>; + #clock-cells = <0>; + clock-div = <1>; + +From 8a9b2d2b1c247942d0f57c23d780641e5eefed37 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 8 Dec 2015 16:23:33 +0000 +Subject: [PATCH 223/278] bcm270x_dt: Use the sdhost MMC controller by default + +The "mmc" overlay reverts to using the other controller. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 11 ++++-- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 11 ++++-- + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 14 ++++++-- + arch/arm/boot/dts/bcm2708_common.dtsi | 13 +++++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 11 ++++-- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 22 +++++++++++- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 49 ++++++--------------------- + arch/arm/boot/dts/overlays/sdio-overlay.dts | 1 - + 8 files changed, 84 insertions(+), 48 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index e3ae8e6..566f52e1 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 2adc248..5218ee9 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 713e5a2..91ec483c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,5 +1,12 @@ + /include/ "bcm2708.dtsi" + ++&gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++}; ++ + &leds { + act_led: act { + label = "led0"; +@@ -8,9 +15,12 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ non-removable; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 66f7165..463777e 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,6 +14,7 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; ++ sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -114,6 +115,18 @@ + status = "disabled"; + }; + ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,pio-limit = <1>; ++ status = "disabled"; ++ }; ++ + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 76d44a2..c703448 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 4579ff2..00a22be 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,9 +6,29 @@ + + fragment@0 { + target = <&mmc>; +- + frag0: __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc_pins>; ++ bus-width = <4>; + brcm,overclock-50 = <0>; + status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ spidev@1{ -+ status = "disabled"; -+ }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { -+ piscreen2_pins: piscreen2_pins { -+ brcm,pins = <17 25 24 22>; -+ brcm,function = <0 1 1 1>; /* in out out out */ ++ mmc_pins: mmc_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <7>; /* alt3 */ + }; + }; + }; + + fragment@2 { -+ target = <&spi0>; ++ target = <&sdhost>; + __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ piscreen2: piscreen2@0{ -+ compatible = "ilitek,ili9486"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&piscreen2_pins>; -+ bgr; -+ spi-max-frequency = <64000000>; -+ rotate = <90>; -+ fps = <30>; -+ buswidth = <8>; -+ regwidth = <16>; -+ txbuflen = <32768>; -+ reset-gpios = <&gpio 25 0>; -+ dc-gpios = <&gpio 24 0>; -+ led-gpios = <&gpio 22 1>; -+ debug = <0>; -+ -+ init = <0x10000b0 0x00 -+ 0x1000011 -+ 0x20000ff -+ 0x100003a 0x55 -+ 0x1000036 0x28 -+ 0x10000c0 0x11 0x09 -+ 0x10000c1 0x41 -+ 0x10000c5 0x00 0x00 0x00 0x00 -+ 0x10000b6 0x00 0x02 -+ 0x10000f7 0xa9 0x51 0x2c 0x2 -+ 0x10000be 0x00 0x04 -+ 0x10000e9 0x00 -+ 0x1000011 -+ 0x1000029>; -+ -+ }; -+ -+ piscreen2_ts: piscreen2-ts@1 { -+ compatible = "ti,ads7846"; -+ reg = <1>; -+ -+ spi-max-frequency = <2000000>; -+ interrupts = <17 2>; /* high-to-low edge triggered */ -+ interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; -+ ti,swap-xy; -+ ti,x-plate-ohms = /bits/ 16 <100>; -+ ti,pressure-max = /bits/ 16 <255>; -+ }; -+ }; -+ }; -+ __overrides__ { -+ speed = <&piscreen2>,"spi-max-frequency:0"; -+ rotate = <&piscreen2>,"rotate:0"; -+ fps = <&piscreen2>,"fps:0"; -+ debug = <&piscreen2>,"debug:0"; -+ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0"; -+ }; -+}; -+ - -From 30a73891df28c2922fcad40317f474914ccf4434 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 9 Oct 2015 10:49:00 +0100 -Subject: [PATCH 199/204] BCM270X_DT: Make mmc overlay compatible with current - firmware - -The original DT overlay logic followed a merge-then-patch procedure, -i.e. parameters are applied to the loaded overlay before the overlay -is merged into the base DTB. This sequence has been changed to -patch-then-merge, in order to support parameterised node names, and -to protect against bad overlays. As a result, overrides (parameters) -must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB. - -mmc-overlay.dts (that switches back to the original mmc sdcard -driver) is the only overlay violating that rule, and this patch -fixes it. ---- - arch/arm/boot/dts/overlays/mmc-overlay.dts | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts -index 0a37cf4..4579ff2 100644 ---- a/arch/arm/boot/dts/overlays/mmc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts -@@ -7,13 +7,13 @@ - fragment@0 { - target = <&mmc>; ++ status = "disabled"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 2da14a4..85f0725 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -5,52 +5,25 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; ++ target = <&mmc>; + __overlay__ { +- #address-cells = <1>; +- #size-cells = <1>; +- +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,delay-after-stop = <0>; +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; +- }; ++ status = "disabled"; + }; + }; + + fragment@1 { +- target = <&gpio>; - __overlay__ { -+ frag0: __overlay__ { - brcm,overclock-50 = <0>; +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- }; +- }; +- +- fragment@2 { +- target = <&mmc>; +- __overlay__ { +- /* Find a way to disable the other driver */ +- compatible = ""; +- status = "disabled"; ++ target = <&sdhost>; ++ frag1: __overlay__ { ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; }; }; __overrides__ { -- overclock_50 = <&mmc>,"brcm,overclock-50:0"; -- force_pio = <&mmc>,"brcm,force-pio?"; -+ overclock_50 = <&frag0>,"brcm,overclock-50:0"; -+ force_pio = <&frag0>,"brcm,force-pio?"; +- overclock_50 = <&sdhost>,"brcm,overclock-50:0"; +- force_pio = <&sdhost>,"brcm,force-pio?"; +- pio_limit = <&sdhost>,"brcm,pio-limit:0"; +- debug = <&sdhost>,"brcm,debug?"; ++ overclock_50 = <&frag1>,"brcm,overclock-50:0"; ++ force_pio = <&frag1>,"brcm,force-pio?"; ++ pio_limit = <&frag1>,"brcm,pio-limit:0"; ++ debug = <&frag1>,"brcm,debug?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 6626a1d..afc8742 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -8,7 +8,6 @@ + fragment@3 { + target = <&mmc>; + sdio_mmc: __overlay__ { +- compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; + +From c0690a03d3127c7a33fd4c818792d386f0cd7dad Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 9 Dec 2015 11:38:15 +0000 +Subject: [PATCH 224/278] bcm2835-sdhost: Don't log timeout errors unless + debug=1 + +The MMC card-discovery process generates timeouts. This is +expected behaviour, so reporting it to the user serves no purpose. +Suppress the reporting of timeout errors unless the debug flag +is on. +--- + drivers/mmc/host/bcm2835-sdhost.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 84f645f..44d61c3 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -966,19 +966,15 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + mmc_hostname(host->mmc)); + } else { + if (sdhsts & SDHSTS_CMD_TIME_OUT) { +- switch (host->cmd->opcode) { +- case 5: case 52: case 53: +- /* Don't warn about SDIO commands */ +- break; +- default: +- pr_err("%s: command timeout\n", +- mmc_hostname(host->mmc)); +- break; +- } ++ if (host->debug) ++ pr_err("%s: command %d timeout\n", ++ mmc_hostname(host->mmc), ++ host->cmd->opcode); + host->cmd->error = -ETIMEDOUT; + } else { +- pr_err("%s: unexpected command error\n", +- mmc_hostname(host->mmc)); ++ pr_err("%s: unexpected command %d error\n", ++ mmc_hostname(host->mmc), ++ host->cmd->opcode); + bcm2835_sdhost_dumpregs(host); + host->cmd->error = -EIO; + } + +From aefc9a3a911fa6f514b648edfcfa6125b43f7d69 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 15 Dec 2015 16:42:29 +0000 +Subject: [PATCH 225/278] config: Switch CONFIG_PREEMPT to + CONFIG_PREEMPT_VOLUNTARY + +See discussion here: https://github.com/raspberrypi/linux/issues/1216 +--- + arch/arm/configs/bcm2709_defconfig | 3 +-- + arch/arm/configs/bcmrpi_defconfig | 3 +-- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index d06b9c8..5a61222 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -44,7 +44,7 @@ CONFIG_BCM2709_DT=y + CONFIG_SMP=y + CONFIG_HAVE_ARM_ARCH_TIMER=y + CONFIG_VMSPLIT_2G=y +-CONFIG_PREEMPT=y ++CONFIG_PREEMPT_VOLUNTARY=y + CONFIG_AEABI=y + CONFIG_OABI_COMPAT=y + CONFIG_CLEANCACHE=y +@@ -1230,7 +1230,6 @@ CONFIG_BOOT_PRINTK_DELAY=y + CONFIG_DEBUG_MEMORY_INIT=y + CONFIG_DETECT_HUNG_TASK=y + CONFIG_TIMER_STATS=y +-# CONFIG_DEBUG_PREEMPT is not set + CONFIG_IRQSOFF_TRACER=y + CONFIG_SCHED_TRACER=y + CONFIG_STACK_TRACER=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index e04f122..20a26f0 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -39,7 +39,7 @@ CONFIG_MAC_PARTITION=y + CONFIG_CFQ_GROUP_IOSCHED=y + CONFIG_ARCH_BCM2708=y + CONFIG_BCM2708_DT=y +-CONFIG_PREEMPT=y ++CONFIG_PREEMPT_VOLUNTARY=y + CONFIG_AEABI=y + CONFIG_OABI_COMPAT=y + CONFIG_CLEANCACHE=y +@@ -1223,7 +1223,6 @@ CONFIG_BOOT_PRINTK_DELAY=y + CONFIG_DEBUG_MEMORY_INIT=y + CONFIG_DETECT_HUNG_TASK=y + CONFIG_TIMER_STATS=y +-# CONFIG_DEBUG_PREEMPT is not set + CONFIG_LATENCYTOP=y + CONFIG_IRQSOFF_TRACER=y + CONFIG_SCHED_TRACER=y + +From b776573142576cb8c38690113d2446de16a4a4cd Mon Sep 17 00:00:00 2001 +From: Devon Fyson +Date: Wed, 30 Dec 2015 16:40:47 -0500 +Subject: [PATCH 226/278] Extend clock timeout, fix modprobe baudrate + parameter. + +Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.\n- Increase priority of baudrate parameter passed to modprobe (in /etc/modprobe.d/*.conf or command line). Currently custom baudrates don't work because they are overridden by clock-frequency in the platform_device passed to the function. +--- + drivers/i2c/busses/i2c-bcm2708.c | 45 ++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 16 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c +index 8b8762d..426bd4e 100644 +--- a/drivers/i2c/busses/i2c-bcm2708.c ++++ b/drivers/i2c/busses/i2c-bcm2708.c +@@ -71,7 +71,8 @@ + + #define DRV_NAME "bcm2708_i2c" + +-static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE; ++static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE; ++static unsigned int baudrate; + module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + MODULE_PARM_DESC(baudrate, "The I2C baudrate"); + +@@ -87,6 +88,7 @@ struct bcm2708_i2c { + int irq; + struct clk *clk; + u32 cdiv; ++ u32 clk_tout; + + struct completion done; + +@@ -154,7 +156,7 @@ static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi) + + static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi) + { +- u32 cdiv, s; ++ u32 cdiv, s, clk_tout; + u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1; + int wait_loops = I2C_WAIT_LOOP_COUNT; + +@@ -162,12 +164,14 @@ static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi) + * Use the value that we cached in the probe. + */ + cdiv = bi->cdiv; ++ clk_tout = bi->clk_tout; + + if (bi->msg->flags & I2C_M_RD) + c |= BSC_C_INTR | BSC_C_READ; + else + c |= BSC_C_INTT; + ++ bcm2708_wr(bi, BSC_CLKT, clk_tout); + bcm2708_wr(bi, BSC_DIV, cdiv); + bcm2708_wr(bi, BSC_A, bi->msg->addr); + bcm2708_wr(bi, BSC_DLEN, bi->msg->len); +@@ -340,21 +344,24 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + struct bcm2708_i2c *bi; + struct i2c_adapter *adap; + unsigned long bus_hz; +- u32 cdiv; +- +- if (pdev->dev.of_node) { +- u32 bus_clk_rate; +- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); +- if (pdev->id < 0) { +- dev_err(&pdev->dev, "alias is missing\n"); +- return -EINVAL; ++ u32 cdiv, clk_tout; ++ ++ if (!baudrate) { ++ baudrate = baudrate_default; ++ if (pdev->dev.of_node) { ++ u32 bus_clk_rate; ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); ++ if (pdev->id < 0) { ++ dev_err(&pdev->dev, "alias is missing\n"); ++ return -EINVAL; ++ } ++ if (!of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &bus_clk_rate)) ++ baudrate = bus_clk_rate; ++ else ++ dev_warn(&pdev->dev, ++ "Could not read clock-frequency property\n"); + } +- if (!of_property_read_u32(pdev->dev.of_node, +- "clock-frequency", &bus_clk_rate)) +- baudrate = bus_clk_rate; +- else +- dev_warn(&pdev->dev, +- "Could not read clock-frequency property\n"); + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -448,7 +455,13 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + cdiv = 0xffff; + baudrate = bus_hz / cdiv; + } ++ ++ clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs. ++ if (clk_tout > 0xffff) ++ clk_tout = 0xffff; ++ + bi->cdiv = cdiv; ++ bi->clk_tout = clk_tout; + + dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", + pdev->id, (unsigned long)regs->start, irq, baudrate); + +From f90e9b5dc99b32dd6eac0745f7c5101b4a646ff2 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 4 Jan 2016 14:42:58 +0000 +Subject: [PATCH 227/278] rpisense: Make globals static to allow non-module + build + +--- + drivers/input/joystick/rpisense-js.c | 4 ++-- + drivers/mfd/rpisense-core.c | 2 +- + drivers/video/fbdev/rpisense-fb.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/input/joystick/rpisense-js.c b/drivers/input/joystick/rpisense-js.c +index 9eca897..6a41676 100644 +--- a/drivers/input/joystick/rpisense-js.c ++++ b/drivers/input/joystick/rpisense-js.c +@@ -18,8 +18,8 @@ + #include + #include + +-struct rpisense *rpisense; +-unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; ++static struct rpisense *rpisense; ++static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; + + static void keys_work_fn(struct work_struct *work) + { +diff --git a/drivers/mfd/rpisense-core.c b/drivers/mfd/rpisense-core.c +index 7539547..eea9312 100644 +--- a/drivers/mfd/rpisense-core.c ++++ b/drivers/mfd/rpisense-core.c +@@ -23,7 +23,7 @@ + #include + #include + +-struct rpisense *rpisense; ++static struct rpisense *rpisense; + + static void rpisense_client_dev_register(struct rpisense *rpisense, + const char *name, +diff --git a/drivers/video/fbdev/rpisense-fb.c b/drivers/video/fbdev/rpisense-fb.c +index 90553fa..26432a5 100644 +--- a/drivers/video/fbdev/rpisense-fb.c ++++ b/drivers/video/fbdev/rpisense-fb.c +@@ -31,7 +31,7 @@ static bool lowlight; + module_param(lowlight, bool, 0); + MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third"); + +-struct rpisense *rpisense; ++static struct rpisense *rpisense; + + struct rpisense_fb_param { + char __iomem *vmem; + +From fd7fd0089a640d83e9a1afbf95b3a4d1a55656a7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 8 Jan 2016 13:42:06 +0000 +Subject: [PATCH 228/278] BCM270X_DT: Enable the HW RNG by default + +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++++ + arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++++ + arch/arm/boot/dts/bcm2708-rpi-cm.dts | 4 ++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++++ + arch/arm/boot/dts/overlays/README | 2 +- + 5 files changed, 17 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 566f52e1..bb8c075 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 5218ee9..8030401 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +index bddc369..ec4bfef 100755 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +@@ -75,6 +75,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + / { + __overrides__ { + uart0 = <&uart0>,"status"; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index c703448..747f859 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 019928d..9c50cffe 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -110,7 +110,7 @@ Params: + (default "off") + + random Set to "on" to enable the hardware random +- number generator (default "off") ++ number generator (default "on") + + uart0 Set to "off" to disable uart0 (default "on") + + +From 55e957414c492e8e0d5fb7b06e951c3003ac4ef5 Mon Sep 17 00:00:00 2001 +From: Andrew Litt +Date: Mon, 11 Jan 2016 07:54:21 +0000 +Subject: [PATCH 229/278] bcm2835-mmc: Don't override bus width capabilities + from devicetree + +Take out the force setting of the MMC_CAP_4_BIT_DATA host capability +so that the result read from devicetree via mmc_of_parse() is +preserved. +--- + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 164bfad..db6617d 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1329,7 +1329,7 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + /* host controller capabilities */ + mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | + MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | +- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; ++ MMC_CAP_MMC_HIGHSPEED; + + host->flags = SDHCI_AUTO_CMD23; + + +From e3871bd4dc21145963017eddbaed4f06bb2e3b89 Mon Sep 17 00:00:00 2001 +From: Andrew Litt +Date: Mon, 11 Jan 2016 07:55:54 +0000 +Subject: [PATCH 230/278] SDIO-overlay: add bus_width parameter + +Allow setting of the SDIO bus width capability of the bcm2835-mmc +host. This is helpful when only a 1 bit wide bus is connected +between host and device but both host and device advertise 4 bit +mode. +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 9c50cffe..cb7c359 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -613,6 +613,8 @@ Params: overclock_50 Clock (in MHz) to use when the MMC framework + poll_once Disable SDIO-device polling every second + (default on: polling once at boot-time) + ++ bus_width Set the SDIO host bus width (default 4 bits) ++ + + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index afc8742..7935e7a 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -11,6 +11,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; ++ bus-width = <4>; + status = "okay"; + }; + }; +@@ -28,5 +29,6 @@ + + __overrides__ { + poll_once = <&sdio_mmc>,"non-removable?"; ++ bus_width = <&sdio_mmc>,"bus-width:0"; }; }; -From 25dc64a6491a98e8df7b387e54dfe1d2be1ea5e8 Mon Sep 17 00:00:00 2001 +From 08c1794148a2a38fd46856ee991948988b7cd0dc Mon Sep 17 00:00:00 2001 From: Phil Elwell -Date: Mon, 12 Oct 2015 08:52:00 +0100 -Subject: [PATCH 200/204] BCM270X_DT: Reduce default at86rf233 SPI frequency +Date: Tue, 19 Jan 2016 16:28:05 +0000 +Subject: [PATCH 231/278] FIXUP i2c_bcm2708: Don't change module baudrate + parameter -The AT86RF233 has been found to be unreliable on a 7.5MHz SPI bus, -so reduce the default frequency to 6MHz. +Overwriting the baudrate module parameter creates an apparent +forced baudrate for i2c busses after the first. Not only does this +override the baudrate from DT it also prevents the bus ID from +being initialised. -See: https://github.com/raspberrypi/linux/issues/1151 +Also fix whitespace errors. --- - arch/arm/boot/dts/overlays/README | 2 +- - arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + drivers/i2c/busses/i2c-bcm2708.c | 50 +++++++++++++++++++++------------------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c +index 426bd4e..4c0c729 100644 +--- a/drivers/i2c/busses/i2c-bcm2708.c ++++ b/drivers/i2c/busses/i2c-bcm2708.c +@@ -71,7 +71,6 @@ + + #define DRV_NAME "bcm2708_i2c" + +-static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE; + static unsigned int baudrate; + module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + MODULE_PARM_DESC(baudrate, "The I2C baudrate"); +@@ -345,25 +344,28 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + struct i2c_adapter *adap; + unsigned long bus_hz; + u32 cdiv, clk_tout; +- +- if (!baudrate) { +- baudrate = baudrate_default; +- if (pdev->dev.of_node) { +- u32 bus_clk_rate; +- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); +- if (pdev->id < 0) { +- dev_err(&pdev->dev, "alias is missing\n"); +- return -EINVAL; +- } +- if (!of_property_read_u32(pdev->dev.of_node, +- "clock-frequency", &bus_clk_rate)) +- baudrate = bus_clk_rate; +- else +- dev_warn(&pdev->dev, +- "Could not read clock-frequency property\n"); ++ u32 baud; ++ ++ baud = CONFIG_I2C_BCM2708_BAUDRATE; ++ ++ if (pdev->dev.of_node) { ++ u32 bus_clk_rate; ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); ++ if (pdev->id < 0) { ++ dev_err(&pdev->dev, "alias is missing\n"); ++ return -EINVAL; + } ++ if (!of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &bus_clk_rate)) ++ baud = bus_clk_rate; ++ else ++ dev_warn(&pdev->dev, ++ "Could not read clock-frequency property\n"); + } + ++ if (baudrate) ++ baud = baudrate; ++ + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "could not get IO memory\n"); +@@ -450,21 +452,21 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + } + + bus_hz = clk_get_rate(bi->clk); +- cdiv = bus_hz / baudrate; ++ cdiv = bus_hz / baud; + if (cdiv > 0xffff) { + cdiv = 0xffff; +- baudrate = bus_hz / cdiv; ++ baud = bus_hz / cdiv; + } +- +- clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs. +- if (clk_tout > 0xffff) ++ ++ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs. ++ if (clk_tout > 0xffff) + clk_tout = 0xffff; +- ++ + bi->cdiv = cdiv; + bi->clk_tout = clk_tout; + + dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", +- pdev->id, (unsigned long)regs->start, irq, baudrate); ++ pdev->id, (unsigned long)regs->start, irq, baud); + + return 0; + + +From bd24a11eeac81a9d0383de572c685c917375dbe5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 20 Jul 2015 12:33:04 -0700 +Subject: [PATCH 232/278] clk: bcm2835: Drop the fixed sys_pclk. + +Nothing uses it, and I can't find any evidence that anything ever has. +Its role is now filled by the core clock in the firmware driver. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Signed-off-by: Michael Turquette +(cherry picked from commit d24d2ec60f7b52c0eca1c52f821777329e5ffac1) +--- + drivers/clk/clk-bcm2835.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c +index 6b950ca..dd295e4 100644 +--- a/drivers/clk/clk-bcm2835.c ++++ b/drivers/clk/clk-bcm2835.c +@@ -32,11 +32,6 @@ void __init bcm2835_init_clocks(void) + struct clk *clk; + int ret; + +- clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT, +- 250000000); +- if (IS_ERR(clk)) +- pr_err("sys_pclk not registered\n"); +- + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, + 126000000); + if (IS_ERR(clk)) + +From c05754e73dc4b70deccaf7edde67fa92bf430bbe Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 28 Sep 2015 14:22:02 -0700 +Subject: [PATCH 233/278] clk: bcm2835: Move under bcm/ with other Broadcom SoC + clk drivers. + +clk-bcm2835.c predates the drivers under bcm/, but all the new BCM +drivers are going in there so let's follow them. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Signed-off-by: Stephen Boyd +(cherry picked from commit 4f61d8e220c110de90a02736ceb55e1e398d6be7) +--- + drivers/clk/Makefile | 1 - + drivers/clk/bcm/Makefile | 1 + + drivers/clk/bcm/clk-bcm2835.c | 55 +++++++++++++++++++++++++++++++++++++++++++ + drivers/clk/clk-bcm2835.c | 55 ------------------------------------------- + 4 files changed, 56 insertions(+), 56 deletions(-) + create mode 100644 drivers/clk/bcm/clk-bcm2835.c + delete mode 100644 drivers/clk/clk-bcm2835.c + +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index f949266..4178cd7 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -19,7 +19,6 @@ endif + obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o + obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o + obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o +-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o + obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o + obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o + obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile +index 6297d05..72e245e 100644 +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o ++obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +new file mode 100644 +index 0000000..dd295e4 +--- /dev/null ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2010 Broadcom ++ * Copyright (C) 2012 Stephen Warren ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * These are fixed clocks. They're probably not all root clocks and it may ++ * be possible to turn them on and off but until this is mapped out better ++ * it's the only way they can be used. ++ */ ++void __init bcm2835_init_clocks(void) ++{ ++ struct clk *clk; ++ int ret; ++ ++ clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, ++ 126000000); ++ if (IS_ERR(clk)) ++ pr_err("apb_pclk not registered\n"); ++ ++ clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, ++ 3000000); ++ if (IS_ERR(clk)) ++ pr_err("uart0_pclk not registered\n"); ++ ret = clk_register_clkdev(clk, NULL, "20201000.uart"); ++ if (ret) ++ pr_err("uart0_pclk alias not registered\n"); ++ ++ clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, ++ 125000000); ++ if (IS_ERR(clk)) ++ pr_err("uart1_pclk not registered\n"); ++ ret = clk_register_clkdev(clk, NULL, "20215000.uart"); ++ if (ret) ++ pr_err("uart1_pclk alias not registered\n"); ++} +diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c +deleted file mode 100644 +index dd295e4..0000000 +--- a/drivers/clk/clk-bcm2835.c ++++ /dev/null +@@ -1,55 +0,0 @@ +-/* +- * Copyright (C) 2010 Broadcom +- * Copyright (C) 2012 Stephen Warren +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * 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, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include +-#include +-#include +-#include +- +-/* +- * These are fixed clocks. They're probably not all root clocks and it may +- * be possible to turn them on and off but until this is mapped out better +- * it's the only way they can be used. +- */ +-void __init bcm2835_init_clocks(void) +-{ +- struct clk *clk; +- int ret; +- +- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, +- 126000000); +- if (IS_ERR(clk)) +- pr_err("apb_pclk not registered\n"); +- +- clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, +- 3000000); +- if (IS_ERR(clk)) +- pr_err("uart0_pclk not registered\n"); +- ret = clk_register_clkdev(clk, NULL, "20201000.uart"); +- if (ret) +- pr_err("uart0_pclk alias not registered\n"); +- +- clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, +- 125000000); +- if (IS_ERR(clk)) +- pr_err("uart1_pclk not registered\n"); +- ret = clk_register_clkdev(clk, NULL, "20215000.uart"); +- if (ret) +- pr_err("uart1_pclk alias not registered\n"); +-} + +From 5fc3660811e8ca66fea484858bb9555db0f87dce Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 28 Sep 2015 14:22:03 -0700 +Subject: [PATCH 234/278] clk: bcm2835: Add binding docs for the new platform + clock driver. + +Previously we've only supported a few fixed clocks based on +assumptions about how the firmware sets up the clocks, but this +binding will let us control the actual (audio power domain) clock +manager. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Acked-by: Lee Jones +Signed-off-by: Stephen Boyd +(cherry picked from commit 2c74b5399de730e3155dc3d5a8ad041fba5e93f4) +--- + .../bindings/clock/brcm,bcm2835-cprman.txt | 45 +++++++++++++++++++++ + include/dt-bindings/clock/bcm2835.h | 47 ++++++++++++++++++++++ + 2 files changed, 92 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt + create mode 100644 include/dt-bindings/clock/bcm2835.h + +diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +new file mode 100644 +index 0000000..e56a1df +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +@@ -0,0 +1,45 @@ ++Broadcom BCM2835 CPRMAN clocks ++ ++This binding uses the common clock binding: ++ Documentation/devicetree/bindings/clock/clock-bindings.txt ++ ++The CPRMAN clock controller generates clocks in the audio power domain ++of the BCM2835. There is a level of PLLs deriving from an external ++oscillator, a level of PLL dividers that produce channels off of the ++few PLLs, and a level of mostly-generic clock generators sourcing from ++the PLL channels. Most other hardware components source from the ++clock generators, but a few (like the ARM or HDMI) will source from ++the PLL dividers directly. ++ ++Required properties: ++- compatible: Should be "brcm,bcm2835-cprman" ++- #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 ++ ++Example: ++ ++ clk_osc: clock@3 { ++ compatible = "fixed-clock"; ++ reg = <3>; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <19200000>; ++ }; ++ ++ clocks: cprman@7e101000 { ++ compatible = "brcm,bcm2835-cprman"; ++ #clock-cells = <1>; ++ reg = <0x7e101000 0x2000>; ++ clocks = <&clk_osc>; ++ }; ++ ++ i2c0: i2c@7e205000 { ++ compatible = "brcm,bcm2835-i2c"; ++ reg = <0x7e205000 0x1000>; ++ interrupts = <2 21>; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; +diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h +new file mode 100644 +index 0000000..d323efa +--- /dev/null ++++ b/include/dt-bindings/clock/bcm2835.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2015 Broadcom Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#define BCM2835_PLLA 0 ++#define BCM2835_PLLB 1 ++#define BCM2835_PLLC 2 ++#define BCM2835_PLLD 3 ++#define BCM2835_PLLH 4 ++ ++#define BCM2835_PLLA_CORE 5 ++#define BCM2835_PLLA_PER 6 ++#define BCM2835_PLLB_ARM 7 ++#define BCM2835_PLLC_CORE0 8 ++#define BCM2835_PLLC_CORE1 9 ++#define BCM2835_PLLC_CORE2 10 ++#define BCM2835_PLLC_PER 11 ++#define BCM2835_PLLD_CORE 12 ++#define BCM2835_PLLD_PER 13 ++#define BCM2835_PLLH_RCAL 14 ++#define BCM2835_PLLH_AUX 15 ++#define BCM2835_PLLH_PIX 16 ++ ++#define BCM2835_CLOCK_TIMER 17 ++#define BCM2835_CLOCK_OTP 18 ++#define BCM2835_CLOCK_UART 19 ++#define BCM2835_CLOCK_VPU 20 ++#define BCM2835_CLOCK_V3D 21 ++#define BCM2835_CLOCK_ISP 22 ++#define BCM2835_CLOCK_H264 23 ++#define BCM2835_CLOCK_VEC 24 ++#define BCM2835_CLOCK_HSM 25 ++#define BCM2835_CLOCK_SDRAM 26 ++#define BCM2835_CLOCK_TSENS 27 ++#define BCM2835_CLOCK_EMMC 28 ++#define BCM2835_CLOCK_PERI_IMAGE 29 ++ ++#define BCM2835_CLOCK_COUNT 30 + +From 5e9322dc0a21cdc378336d47ae869a6fc139e439 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 8 Oct 2015 18:37:24 -0700 +Subject: [PATCH 235/278] clk: bcm2835: Add support for programming the audio + domain clocks + +This adds support for enabling, disabling, and setting the rate of the +audio domain clocks. It will be necessary for setting the pixel clock +for HDMI in the VC4 driver and let us write a cpufreq driver. It will +also improve compatibility with user changes to the firmware's +config.txt, since our previous fixed clocks are unaware of it. + +The firmware also has support for configuring the clocks through the +mailbox channel, but the pixel clock setup by the firmware doesn't +work, and it's Raspberry Pi specific anyway. The only conflicts we +should have with the firmware would be if we made firmware calls that +result in clock management (like opening firmware V3D or ISP access, +which we don't support in upstream), or on hardware over-thermal or +under-voltage (when the firmware would rewrite PLLB to take the ARM +out of overclock). If that happens, our cached .recalc_rate() results +would be incorrect, but that's no worse than our current state where +we used fixed clocks. + +The existing fixed clocks in the code are left in place to provide +backwards compatibility with old device tree files. + +Signed-off-by: Eric Anholt +Tested-by: Martin Sperl +Acked-by: Stephen Warren +Signed-off-by: Stephen Boyd +(cherry picked from commit 41691b8862e2a32080306f17a723efc4b6ca86ab) +--- + drivers/clk/bcm/clk-bcm2835.c | 1528 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 1527 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index dd295e4..6c9b2e8 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2010 Broadcom ++ * Copyright (C) 2010,2015 Broadcom + * Copyright (C) 2012 Stephen Warren + * + * This program is free software; you can redistribute it and/or modify +@@ -17,10 +17,295 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++/** ++ * DOC: BCM2835 CPRMAN (clock manager for the "audio" domain) ++ * ++ * The clock tree on the 2835 has several levels. There's a root ++ * oscillator running at 19.2Mhz. After the oscillator there are 5 ++ * PLLs, roughly divided as "camera", "ARM", "core", "DSI displays", ++ * and "HDMI displays". Those 5 PLLs each can divide their output to ++ * produce up to 4 channels. Finally, there is the level of clocks to ++ * be consumed by other hardware components (like "H264" or "HDMI ++ * state machine"), which divide off of some subset of the PLL ++ * channels. ++ * ++ * All of the clocks in the tree are exposed in the DT, because the DT ++ * may want to make assignments of the final layer of clocks to the ++ * PLL channels, and some components of the hardware will actually ++ * skip layers of the tree (for example, the pixel clock comes ++ * directly from the PLLH PIX channel without using a CM_*CTL clock ++ * generator). ++ */ ++ + #include + #include + #include ++#include + #include ++#include ++#include ++#include ++ ++#define CM_PASSWORD 0x5a000000 ++ ++#define CM_GNRICCTL 0x000 ++#define CM_GNRICDIV 0x004 ++# define CM_DIV_FRAC_BITS 12 ++ ++#define CM_VPUCTL 0x008 ++#define CM_VPUDIV 0x00c ++#define CM_SYSCTL 0x010 ++#define CM_SYSDIV 0x014 ++#define CM_PERIACTL 0x018 ++#define CM_PERIADIV 0x01c ++#define CM_PERIICTL 0x020 ++#define CM_PERIIDIV 0x024 ++#define CM_H264CTL 0x028 ++#define CM_H264DIV 0x02c ++#define CM_ISPCTL 0x030 ++#define CM_ISPDIV 0x034 ++#define CM_V3DCTL 0x038 ++#define CM_V3DDIV 0x03c ++#define CM_CAM0CTL 0x040 ++#define CM_CAM0DIV 0x044 ++#define CM_CAM1CTL 0x048 ++#define CM_CAM1DIV 0x04c ++#define CM_CCP2CTL 0x050 ++#define CM_CCP2DIV 0x054 ++#define CM_DSI0ECTL 0x058 ++#define CM_DSI0EDIV 0x05c ++#define CM_DSI0PCTL 0x060 ++#define CM_DSI0PDIV 0x064 ++#define CM_DPICTL 0x068 ++#define CM_DPIDIV 0x06c ++#define CM_GP0CTL 0x070 ++#define CM_GP0DIV 0x074 ++#define CM_GP1CTL 0x078 ++#define CM_GP1DIV 0x07c ++#define CM_GP2CTL 0x080 ++#define CM_GP2DIV 0x084 ++#define CM_HSMCTL 0x088 ++#define CM_HSMDIV 0x08c ++#define CM_OTPCTL 0x090 ++#define CM_OTPDIV 0x094 ++#define CM_PWMCTL 0x0a0 ++#define CM_PWMDIV 0x0a4 ++#define CM_SMICTL 0x0b0 ++#define CM_SMIDIV 0x0b4 ++#define CM_TSENSCTL 0x0e0 ++#define CM_TSENSDIV 0x0e4 ++#define CM_TIMERCTL 0x0e8 ++#define CM_TIMERDIV 0x0ec ++#define CM_UARTCTL 0x0f0 ++#define CM_UARTDIV 0x0f4 ++#define CM_VECCTL 0x0f8 ++#define CM_VECDIV 0x0fc ++#define CM_PULSECTL 0x190 ++#define CM_PULSEDIV 0x194 ++#define CM_SDCCTL 0x1a8 ++#define CM_SDCDIV 0x1ac ++#define CM_ARMCTL 0x1b0 ++#define CM_EMMCCTL 0x1c0 ++#define CM_EMMCDIV 0x1c4 ++ ++/* General bits for the CM_*CTL regs */ ++# define CM_ENABLE BIT(4) ++# define CM_KILL BIT(5) ++# define CM_GATE_BIT 6 ++# define CM_GATE BIT(CM_GATE_BIT) ++# define CM_BUSY BIT(7) ++# define CM_BUSYD BIT(8) ++# define CM_SRC_SHIFT 0 ++# define CM_SRC_BITS 4 ++# define CM_SRC_MASK 0xf ++# define CM_SRC_GND 0 ++# define CM_SRC_OSC 1 ++# define CM_SRC_TESTDEBUG0 2 ++# define CM_SRC_TESTDEBUG1 3 ++# define CM_SRC_PLLA_CORE 4 ++# define CM_SRC_PLLA_PER 4 ++# define CM_SRC_PLLC_CORE0 5 ++# define CM_SRC_PLLC_PER 5 ++# define CM_SRC_PLLC_CORE1 8 ++# define CM_SRC_PLLD_CORE 6 ++# define CM_SRC_PLLD_PER 6 ++# define CM_SRC_PLLH_AUX 7 ++# define CM_SRC_PLLC_CORE1 8 ++# define CM_SRC_PLLC_CORE2 9 ++ ++#define CM_OSCCOUNT 0x100 ++ ++#define CM_PLLA 0x104 ++# define CM_PLL_ANARST BIT(8) ++# define CM_PLLA_HOLDPER BIT(7) ++# define CM_PLLA_LOADPER BIT(6) ++# define CM_PLLA_HOLDCORE BIT(5) ++# define CM_PLLA_LOADCORE BIT(4) ++# define CM_PLLA_HOLDCCP2 BIT(3) ++# define CM_PLLA_LOADCCP2 BIT(2) ++# define CM_PLLA_HOLDDSI0 BIT(1) ++# define CM_PLLA_LOADDSI0 BIT(0) ++ ++#define CM_PLLC 0x108 ++# define CM_PLLC_HOLDPER BIT(7) ++# define CM_PLLC_LOADPER BIT(6) ++# define CM_PLLC_HOLDCORE2 BIT(5) ++# define CM_PLLC_LOADCORE2 BIT(4) ++# define CM_PLLC_HOLDCORE1 BIT(3) ++# define CM_PLLC_LOADCORE1 BIT(2) ++# define CM_PLLC_HOLDCORE0 BIT(1) ++# define CM_PLLC_LOADCORE0 BIT(0) ++ ++#define CM_PLLD 0x10c ++# define CM_PLLD_HOLDPER BIT(7) ++# define CM_PLLD_LOADPER BIT(6) ++# define CM_PLLD_HOLDCORE BIT(5) ++# define CM_PLLD_LOADCORE BIT(4) ++# define CM_PLLD_HOLDDSI1 BIT(3) ++# define CM_PLLD_LOADDSI1 BIT(2) ++# define CM_PLLD_HOLDDSI0 BIT(1) ++# define CM_PLLD_LOADDSI0 BIT(0) ++ ++#define CM_PLLH 0x110 ++# define CM_PLLH_LOADRCAL BIT(2) ++# define CM_PLLH_LOADAUX BIT(1) ++# define CM_PLLH_LOADPIX BIT(0) ++ ++#define CM_LOCK 0x114 ++# define CM_LOCK_FLOCKH BIT(12) ++# define CM_LOCK_FLOCKD BIT(11) ++# define CM_LOCK_FLOCKC BIT(10) ++# define CM_LOCK_FLOCKB BIT(9) ++# define CM_LOCK_FLOCKA BIT(8) ++ ++#define CM_EVENT 0x118 ++#define CM_DSI1ECTL 0x158 ++#define CM_DSI1EDIV 0x15c ++#define CM_DSI1PCTL 0x160 ++#define CM_DSI1PDIV 0x164 ++#define CM_DFTCTL 0x168 ++#define CM_DFTDIV 0x16c ++ ++#define CM_PLLB 0x170 ++# define CM_PLLB_HOLDARM BIT(1) ++# define CM_PLLB_LOADARM BIT(0) ++ ++#define A2W_PLLA_CTRL 0x1100 ++#define A2W_PLLC_CTRL 0x1120 ++#define A2W_PLLD_CTRL 0x1140 ++#define A2W_PLLH_CTRL 0x1160 ++#define A2W_PLLB_CTRL 0x11e0 ++# define A2W_PLL_CTRL_PRST_DISABLE BIT(17) ++# define A2W_PLL_CTRL_PWRDN BIT(16) ++# define A2W_PLL_CTRL_PDIV_MASK 0x000007000 ++# define A2W_PLL_CTRL_PDIV_SHIFT 12 ++# define A2W_PLL_CTRL_NDIV_MASK 0x0000003ff ++# define A2W_PLL_CTRL_NDIV_SHIFT 0 ++ ++#define A2W_PLLA_ANA0 0x1010 ++#define A2W_PLLC_ANA0 0x1030 ++#define A2W_PLLD_ANA0 0x1050 ++#define A2W_PLLH_ANA0 0x1070 ++#define A2W_PLLB_ANA0 0x10f0 ++ ++#define A2W_PLL_KA_SHIFT 7 ++#define A2W_PLL_KA_MASK GENMASK(9, 7) ++#define A2W_PLL_KI_SHIFT 19 ++#define A2W_PLL_KI_MASK GENMASK(21, 19) ++#define A2W_PLL_KP_SHIFT 15 ++#define A2W_PLL_KP_MASK GENMASK(18, 15) ++ ++#define A2W_PLLH_KA_SHIFT 19 ++#define A2W_PLLH_KA_MASK GENMASK(21, 19) ++#define A2W_PLLH_KI_LOW_SHIFT 22 ++#define A2W_PLLH_KI_LOW_MASK GENMASK(23, 22) ++#define A2W_PLLH_KI_HIGH_SHIFT 0 ++#define A2W_PLLH_KI_HIGH_MASK GENMASK(0, 0) ++#define A2W_PLLH_KP_SHIFT 1 ++#define A2W_PLLH_KP_MASK GENMASK(4, 1) ++ ++#define A2W_XOSC_CTRL 0x1190 ++# define A2W_XOSC_CTRL_PLLB_ENABLE BIT(7) ++# define A2W_XOSC_CTRL_PLLA_ENABLE BIT(6) ++# define A2W_XOSC_CTRL_PLLD_ENABLE BIT(5) ++# define A2W_XOSC_CTRL_DDR_ENABLE BIT(4) ++# define A2W_XOSC_CTRL_CPR1_ENABLE BIT(3) ++# define A2W_XOSC_CTRL_USB_ENABLE BIT(2) ++# define A2W_XOSC_CTRL_HDMI_ENABLE BIT(1) ++# define A2W_XOSC_CTRL_PLLC_ENABLE BIT(0) ++ ++#define A2W_PLLA_FRAC 0x1200 ++#define A2W_PLLC_FRAC 0x1220 ++#define A2W_PLLD_FRAC 0x1240 ++#define A2W_PLLH_FRAC 0x1260 ++#define A2W_PLLB_FRAC 0x12e0 ++# define A2W_PLL_FRAC_MASK ((1 << A2W_PLL_FRAC_BITS) - 1) ++# define A2W_PLL_FRAC_BITS 20 ++ ++#define A2W_PLL_CHANNEL_DISABLE BIT(8) ++#define A2W_PLL_DIV_BITS 8 ++#define A2W_PLL_DIV_SHIFT 0 ++ ++#define A2W_PLLA_DSI0 0x1300 ++#define A2W_PLLA_CORE 0x1400 ++#define A2W_PLLA_PER 0x1500 ++#define A2W_PLLA_CCP2 0x1600 ++ ++#define A2W_PLLC_CORE2 0x1320 ++#define A2W_PLLC_CORE1 0x1420 ++#define A2W_PLLC_PER 0x1520 ++#define A2W_PLLC_CORE0 0x1620 ++ ++#define A2W_PLLD_DSI0 0x1340 ++#define A2W_PLLD_CORE 0x1440 ++#define A2W_PLLD_PER 0x1540 ++#define A2W_PLLD_DSI1 0x1640 ++ ++#define A2W_PLLH_AUX 0x1360 ++#define A2W_PLLH_RCAL 0x1460 ++#define A2W_PLLH_PIX 0x1560 ++#define A2W_PLLH_STS 0x1660 ++ ++#define A2W_PLLH_CTRLR 0x1960 ++#define A2W_PLLH_FRACR 0x1a60 ++#define A2W_PLLH_AUXR 0x1b60 ++#define A2W_PLLH_RCALR 0x1c60 ++#define A2W_PLLH_PIXR 0x1d60 ++#define A2W_PLLH_STSR 0x1e60 ++ ++#define A2W_PLLB_ARM 0x13e0 ++#define A2W_PLLB_SP0 0x14e0 ++#define A2W_PLLB_SP1 0x15e0 ++#define A2W_PLLB_SP2 0x16e0 ++ ++#define LOCK_TIMEOUT_NS 100000000 ++#define BCM2835_MAX_FB_RATE 1750000000u ++ ++struct bcm2835_cprman { ++ struct device *dev; ++ void __iomem *regs; ++ spinlock_t regs_lock; ++ const char *osc_name; ++ ++ struct clk_onecell_data onecell; ++ struct clk *clks[BCM2835_CLOCK_COUNT]; ++}; ++ ++/* Backport for 4.1's clk core, see . */ ++static inline const char *clk_hw_get_name(struct clk_hw *hw) ++{ ++ return __clk_get_name(hw->clk); ++} ++ ++static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val) ++{ ++ writel(CM_PASSWORD | val, cprman->regs + reg); ++} ++ ++static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) ++{ ++ return readl(cprman->regs + reg); ++} + + /* + * These are fixed clocks. They're probably not all root clocks and it may +@@ -53,3 +338,1244 @@ void __init bcm2835_init_clocks(void) + if (ret) + pr_err("uart1_pclk alias not registered\n"); + } ++ ++struct bcm2835_pll_data { ++ const char *name; ++ u32 cm_ctrl_reg; ++ u32 a2w_ctrl_reg; ++ u32 frac_reg; ++ u32 ana_reg_base; ++ u32 reference_enable_mask; ++ /* Bit in CM_LOCK to indicate when the PLL has locked. */ ++ u32 lock_mask; ++ ++ const struct bcm2835_pll_ana_bits *ana; ++ ++ unsigned long min_rate; ++ unsigned long max_rate; ++ /* ++ * Highest rate for the VCO before we have to use the ++ * pre-divide-by-2. ++ */ ++ unsigned long max_fb_rate; ++}; ++ ++struct bcm2835_pll_ana_bits { ++ u32 mask0; ++ u32 set0; ++ u32 mask1; ++ u32 set1; ++ u32 mask3; ++ u32 set3; ++ u32 fb_prediv_mask; ++}; ++ ++static const struct bcm2835_pll_ana_bits bcm2835_ana_default = { ++ .mask0 = 0, ++ .set0 = 0, ++ .mask1 = ~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK), ++ .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), ++ .mask3 = ~A2W_PLL_KA_MASK, ++ .set3 = (2 << A2W_PLL_KA_SHIFT), ++ .fb_prediv_mask = BIT(14), ++}; ++ ++static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { ++ .mask0 = ~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK), ++ .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), ++ .mask1 = ~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK), ++ .set1 = (6 << A2W_PLLH_KP_SHIFT), ++ .mask3 = 0, ++ .set3 = 0, ++ .fb_prediv_mask = BIT(11), ++}; ++ ++/* ++ * PLLA is the auxiliary PLL, used to drive the CCP2 (Compact Camera ++ * Port 2) transmitter clock. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++ */ ++static const struct bcm2835_pll_data bcm2835_plla_data = { ++ .name = "plla", ++ .cm_ctrl_reg = CM_PLLA, ++ .a2w_ctrl_reg = A2W_PLLA_CTRL, ++ .frac_reg = A2W_PLLA_FRAC, ++ .ana_reg_base = A2W_PLLA_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKA, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 2400000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* PLLB is used for the ARM's clock. */ ++static const struct bcm2835_pll_data bcm2835_pllb_data = { ++ .name = "pllb", ++ .cm_ctrl_reg = CM_PLLB, ++ .a2w_ctrl_reg = A2W_PLLB_CTRL, ++ .frac_reg = A2W_PLLB_FRAC, ++ .ana_reg_base = A2W_PLLB_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKB, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLC is the core PLL, used to drive the core VPU clock. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++*/ ++static const struct bcm2835_pll_data bcm2835_pllc_data = { ++ .name = "pllc", ++ .cm_ctrl_reg = CM_PLLC, ++ .a2w_ctrl_reg = A2W_PLLC_CTRL, ++ .frac_reg = A2W_PLLC_FRAC, ++ .ana_reg_base = A2W_PLLC_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKC, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLD is the display PLL, used to drive DSI display panels. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++ */ ++static const struct bcm2835_pll_data bcm2835_plld_data = { ++ .name = "plld", ++ .cm_ctrl_reg = CM_PLLD, ++ .a2w_ctrl_reg = A2W_PLLD_CTRL, ++ .frac_reg = A2W_PLLD_FRAC, ++ .ana_reg_base = A2W_PLLD_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKD, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 2400000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLH is used to supply the pixel clock or the AUX clock for the TV ++ * encoder. ++ * ++ * It is in the HDMI power domain. ++ */ ++static const struct bcm2835_pll_data bcm2835_pllh_data = { ++ "pllh", ++ .cm_ctrl_reg = CM_PLLH, ++ .a2w_ctrl_reg = A2W_PLLH_CTRL, ++ .frac_reg = A2W_PLLH_FRAC, ++ .ana_reg_base = A2W_PLLH_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKH, ++ ++ .ana = &bcm2835_ana_pllh, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++struct bcm2835_pll_divider_data { ++ const char *name; ++ const struct bcm2835_pll_data *source_pll; ++ u32 cm_reg; ++ u32 a2w_reg; ++ ++ u32 load_mask; ++ u32 hold_mask; ++ u32 fixed_divider; ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plla_core_data = { ++ .name = "plla_core", ++ .source_pll = &bcm2835_plla_data, ++ .cm_reg = CM_PLLA, ++ .a2w_reg = A2W_PLLA_CORE, ++ .load_mask = CM_PLLA_LOADCORE, ++ .hold_mask = CM_PLLA_HOLDCORE, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plla_per_data = { ++ .name = "plla_per", ++ .source_pll = &bcm2835_plla_data, ++ .cm_reg = CM_PLLA, ++ .a2w_reg = A2W_PLLA_PER, ++ .load_mask = CM_PLLA_LOADPER, ++ .hold_mask = CM_PLLA_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllb_arm_data = { ++ .name = "pllb_arm", ++ .source_pll = &bcm2835_pllb_data, ++ .cm_reg = CM_PLLB, ++ .a2w_reg = A2W_PLLB_ARM, ++ .load_mask = CM_PLLB_LOADARM, ++ .hold_mask = CM_PLLB_HOLDARM, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core0_data = { ++ .name = "pllc_core0", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_CORE0, ++ .load_mask = CM_PLLC_LOADCORE0, ++ .hold_mask = CM_PLLC_HOLDCORE0, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core1_data = { ++ .name = "pllc_core1", .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, A2W_PLLC_CORE1, ++ .load_mask = CM_PLLC_LOADCORE1, ++ .hold_mask = CM_PLLC_HOLDCORE1, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core2_data = { ++ .name = "pllc_core2", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_CORE2, ++ .load_mask = CM_PLLC_LOADCORE2, ++ .hold_mask = CM_PLLC_HOLDCORE2, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_per_data = { ++ .name = "pllc_per", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_PER, ++ .load_mask = CM_PLLC_LOADPER, ++ .hold_mask = CM_PLLC_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plld_core_data = { ++ .name = "plld_core", ++ .source_pll = &bcm2835_plld_data, ++ .cm_reg = CM_PLLD, ++ .a2w_reg = A2W_PLLD_CORE, ++ .load_mask = CM_PLLD_LOADCORE, ++ .hold_mask = CM_PLLD_HOLDCORE, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plld_per_data = { ++ .name = "plld_per", ++ .source_pll = &bcm2835_plld_data, ++ .cm_reg = CM_PLLD, ++ .a2w_reg = A2W_PLLD_PER, ++ .load_mask = CM_PLLD_LOADPER, ++ .hold_mask = CM_PLLD_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_rcal_data = { ++ .name = "pllh_rcal", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_RCAL, ++ .load_mask = CM_PLLH_LOADRCAL, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_aux_data = { ++ .name = "pllh_aux", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_AUX, ++ .load_mask = CM_PLLH_LOADAUX, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_pix_data = { ++ .name = "pllh_pix", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_PIX, ++ .load_mask = CM_PLLH_LOADPIX, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++struct bcm2835_clock_data { ++ const char *name; ++ ++ const char *const *parents; ++ int num_mux_parents; ++ ++ u32 ctl_reg; ++ u32 div_reg; ++ ++ /* Number of integer bits in the divider */ ++ u32 int_bits; ++ /* Number of fractional bits in the divider */ ++ u32 frac_bits; ++ ++ bool is_vpu_clock; ++}; ++ ++static const char *const bcm2835_clock_per_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "plla_per", ++ "pllc_per", ++ "plld_per", ++ "pllh_aux", ++}; ++ ++static const char *const bcm2835_clock_vpu_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "plla_core", ++ "pllc_core0", ++ "plld_core", ++ "pllh_aux", ++ "pllc_core1", ++ "pllc_core2", ++}; ++ ++static const char *const bcm2835_clock_osc_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1" ++}; ++ ++/* ++ * Used for a 1Mhz clock for the system clocksource, and also used by ++ * the watchdog timer and the camera pulse generator. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_timer_data = { ++ .name = "timer", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_TIMERCTL, ++ .div_reg = CM_TIMERDIV, ++ .int_bits = 6, ++ .frac_bits = 12, ++}; ++ ++/* One Time Programmable Memory clock. Maximum 10Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_otp_data = { ++ .name = "otp", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_OTPCTL, ++ .div_reg = CM_OTPDIV, ++ .int_bits = 4, ++ .frac_bits = 0, ++}; ++ ++/* ++ * 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 to be ++ * gated for rate changes. It is also known as "clk_audio" in various ++ * hardware documentation. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_vpu_data = { ++ .name = "vpu", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_VPUCTL, ++ .div_reg = CM_VPUDIV, ++ .int_bits = 12, ++ .frac_bits = 8, ++ .is_vpu_clock = true, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_v3d_data = { ++ .name = "v3d", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_V3DCTL, ++ .div_reg = CM_V3DDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_isp_data = { ++ .name = "isp", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_ISPCTL, ++ .div_reg = CM_ISPDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_h264_data = { ++ .name = "h264", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_H264CTL, ++ .div_reg = CM_H264DIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++/* TV encoder clock. Only operating frequency is 108Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_vec_data = { ++ .name = "vec", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_VECCTL, ++ .div_reg = CM_VECDIV, ++ .int_bits = 4, ++ .frac_bits = 0, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_uart_data = { ++ .name = "uart", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_UARTCTL, ++ .div_reg = CM_UARTDIV, ++ .int_bits = 10, ++ .frac_bits = 12, ++}; ++ ++/* HDMI state machine */ ++static const struct bcm2835_clock_data bcm2835_clock_hsm_data = { ++ .name = "hsm", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_HSMCTL, ++ .div_reg = CM_HSMDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++/* ++ * Secondary SDRAM clock. Used for low-voltage modes when the PLL in ++ * the SDRAM controller can't be used. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_sdram_data = { ++ .name = "sdram", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_SDCCTL, ++ .div_reg = CM_SDCDIV, ++ .int_bits = 6, ++ .frac_bits = 0, ++}; ++ ++/* Clock for the temperature sensor. Generally run at 2Mhz, max 5Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_tsens_data = { ++ .name = "tsens", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_TSENSCTL, ++ .div_reg = CM_TSENSDIV, ++ .int_bits = 5, ++ .frac_bits = 0, ++}; ++ ++/* Arasan EMMC clock */ ++static const struct bcm2835_clock_data bcm2835_clock_emmc_data = { ++ .name = "emmc", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_EMMCCTL, ++ .div_reg = CM_EMMCDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++struct bcm2835_pll { ++ struct clk_hw hw; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_pll_data *data; ++}; ++ ++static int bcm2835_pll_is_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ++ return cprman_read(cprman, data->a2w_ctrl_reg) & ++ A2W_PLL_CTRL_PRST_DISABLE; ++} ++ ++static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate, ++ unsigned long parent_rate, ++ u32 *ndiv, u32 *fdiv) ++{ ++ u64 div; ++ ++ div = (u64)rate << A2W_PLL_FRAC_BITS; ++ do_div(div, parent_rate); ++ ++ *ndiv = div >> A2W_PLL_FRAC_BITS; ++ *fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1); ++} ++ ++static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate, ++ u32 ndiv, u32 fdiv, u32 pdiv) ++{ ++ u64 rate; ++ ++ if (pdiv == 0) ++ return 0; ++ ++ rate = (u64)parent_rate * ((ndiv << A2W_PLL_FRAC_BITS) + fdiv); ++ do_div(rate, pdiv); ++ return rate >> A2W_PLL_FRAC_BITS; ++} ++ ++static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ u32 ndiv, fdiv; ++ ++ bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); ++ ++ return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); ++} ++ ++static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ u32 a2wctrl = cprman_read(cprman, data->a2w_ctrl_reg); ++ u32 ndiv, pdiv, fdiv; ++ bool using_prediv; ++ ++ if (parent_rate == 0) ++ return 0; ++ ++ fdiv = cprman_read(cprman, data->frac_reg) & A2W_PLL_FRAC_MASK; ++ ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; ++ pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; ++ using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & ++ data->ana->fb_prediv_mask; ++ ++ if (using_prediv) ++ ndiv *= 2; ++ ++ return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); ++} ++ ++static void bcm2835_pll_off(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ++ cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); ++ cprman_write(cprman, data->a2w_ctrl_reg, A2W_PLL_CTRL_PWRDN); ++} ++ ++static int bcm2835_pll_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ktime_t timeout; ++ ++ /* Take the PLL out of reset. */ ++ cprman_write(cprman, data->cm_ctrl_reg, ++ cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); ++ ++ /* Wait for the PLL to lock. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "%s: couldn't lock PLL\n", ++ clk_hw_get_name(hw)); ++ return -ETIMEDOUT; ++ } ++ ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++ ++static void ++bcm2835_pll_write_ana(struct bcm2835_cprman *cprman, u32 ana_reg_base, u32 *ana) ++{ ++ int i; ++ ++ /* ++ * ANA register setup is done as a series of writes to ++ * ANA3-ANA0, in that order. This lets us write all 4 ++ * registers as a single cycle of the serdes interface (taking ++ * 100 xosc clocks), whereas if we were to update ana0, 1, and ++ * 3 individually through their partial-write registers, each ++ * would be their own serdes cycle. ++ */ ++ for (i = 3; i >= 0; i--) ++ cprman_write(cprman, ana_reg_base + i * 4, ana[i]); ++} ++ ++static int bcm2835_pll_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ bool was_using_prediv, use_fb_prediv, do_ana_setup_first; ++ u32 ndiv, fdiv, a2w_ctl; ++ u32 ana[4]; ++ int i; ++ ++ if (rate < data->min_rate || rate > data->max_rate) { ++ dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n", ++ clk_hw_get_name(hw), rate, ++ data->min_rate, data->max_rate); ++ return -EINVAL; ++ } ++ ++ if (rate > data->max_fb_rate) { ++ use_fb_prediv = true; ++ rate /= 2; ++ } else { ++ use_fb_prediv = false; ++ } ++ ++ bcm2835_pll_choose_ndiv_and_fdiv(rate, parent_rate, &ndiv, &fdiv); ++ ++ for (i = 3; i >= 0; i--) ++ ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); ++ ++ was_using_prediv = ana[1] & data->ana->fb_prediv_mask; ++ ++ ana[0] &= ~data->ana->mask0; ++ ana[0] |= data->ana->set0; ++ ana[1] &= ~data->ana->mask1; ++ ana[1] |= data->ana->set1; ++ ana[3] &= ~data->ana->mask3; ++ ana[3] |= data->ana->set3; ++ ++ if (was_using_prediv && !use_fb_prediv) { ++ ana[1] &= ~data->ana->fb_prediv_mask; ++ do_ana_setup_first = true; ++ } else if (!was_using_prediv && use_fb_prediv) { ++ ana[1] |= data->ana->fb_prediv_mask; ++ do_ana_setup_first = false; ++ } else { ++ do_ana_setup_first = true; ++ } ++ ++ /* Unmask the reference clock from the oscillator. */ ++ cprman_write(cprman, A2W_XOSC_CTRL, ++ cprman_read(cprman, A2W_XOSC_CTRL) | ++ data->reference_enable_mask); ++ ++ if (do_ana_setup_first) ++ bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); ++ ++ /* Set the PLL multiplier from the oscillator. */ ++ cprman_write(cprman, data->frac_reg, fdiv); ++ ++ a2w_ctl = cprman_read(cprman, data->a2w_ctrl_reg); ++ a2w_ctl &= ~A2W_PLL_CTRL_NDIV_MASK; ++ a2w_ctl |= ndiv << A2W_PLL_CTRL_NDIV_SHIFT; ++ a2w_ctl &= ~A2W_PLL_CTRL_PDIV_MASK; ++ a2w_ctl |= 1 << A2W_PLL_CTRL_PDIV_SHIFT; ++ cprman_write(cprman, data->a2w_ctrl_reg, a2w_ctl); ++ ++ if (!do_ana_setup_first) ++ bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_pll_clk_ops = { ++ .is_prepared = bcm2835_pll_is_on, ++ .prepare = bcm2835_pll_on, ++ .unprepare = bcm2835_pll_off, ++ .recalc_rate = bcm2835_pll_get_rate, ++ .set_rate = bcm2835_pll_set_rate, ++ .round_rate = bcm2835_pll_round_rate, ++}; ++ ++struct bcm2835_pll_divider { ++ struct clk_divider div; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_pll_divider_data *data; ++}; ++ ++static struct bcm2835_pll_divider * ++bcm2835_pll_divider_from_hw(struct clk_hw *hw) ++{ ++ return container_of(hw, struct bcm2835_pll_divider, div.hw); ++} ++ ++static int bcm2835_pll_divider_is_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ return !(cprman_read(cprman, data->a2w_reg) & A2W_PLL_CHANNEL_DISABLE); ++} ++ ++static long bcm2835_pll_divider_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, parent_rate); ++} ++ ++static unsigned long bcm2835_pll_divider_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ u32 div = cprman_read(cprman, data->a2w_reg); ++ ++ div &= (1 << A2W_PLL_DIV_BITS) - 1; ++ if (div == 0) ++ div = 256; ++ ++ return parent_rate / div; ++} ++ ++static void bcm2835_pll_divider_off(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ cprman_write(cprman, data->cm_reg, ++ (cprman_read(cprman, data->cm_reg) & ++ ~data->load_mask) | data->hold_mask); ++ cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE); ++} ++ ++static int bcm2835_pll_divider_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ cprman_write(cprman, data->a2w_reg, ++ cprman_read(cprman, data->a2w_reg) & ++ ~A2W_PLL_CHANNEL_DISABLE); ++ ++ cprman_write(cprman, data->cm_reg, ++ cprman_read(cprman, data->cm_reg) & ~data->hold_mask); ++ ++ return 0; ++} ++ ++static int bcm2835_pll_divider_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ u32 cm; ++ int ret; ++ ++ ret = clk_divider_ops.set_rate(hw, rate, parent_rate); ++ if (ret) ++ return ret; ++ ++ cm = cprman_read(cprman, data->cm_reg); ++ cprman_write(cprman, data->cm_reg, cm | data->load_mask); ++ cprman_write(cprman, data->cm_reg, cm & ~data->load_mask); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_pll_divider_clk_ops = { ++ .is_prepared = bcm2835_pll_divider_is_on, ++ .prepare = bcm2835_pll_divider_on, ++ .unprepare = bcm2835_pll_divider_off, ++ .recalc_rate = bcm2835_pll_divider_get_rate, ++ .set_rate = bcm2835_pll_divider_set_rate, ++ .round_rate = bcm2835_pll_divider_round_rate, ++}; ++ ++/* ++ * The CM dividers do fixed-point division, so we can't use the ++ * generic integer divider code like the PLL dividers do (and we can't ++ * fake it by having some fixed shifts preceding it in the clock tree, ++ * because we'd run out of bits in a 32-bit unsigned long). ++ */ ++struct bcm2835_clock { ++ struct clk_hw hw; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_clock_data *data; ++}; ++ ++static struct bcm2835_clock *bcm2835_clock_from_hw(struct clk_hw *hw) ++{ ++ return container_of(hw, struct bcm2835_clock, hw); ++} ++ ++static int bcm2835_clock_is_on(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; ++ ++ return (cprman_read(cprman, data->ctl_reg) & CM_ENABLE) != 0; ++} ++ ++static u32 bcm2835_clock_choose_div(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ const struct bcm2835_clock_data *data = clock->data; ++ u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0); ++ u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS; ++ u32 div; ++ ++ do_div(temp, rate); ++ div = temp; ++ ++ /* Round and mask off the unused bits */ ++ if (unused_frac_mask != 0) { ++ div += unused_frac_mask >> 1; ++ div &= ~unused_frac_mask; ++ } ++ ++ /* Clamp to the limits. */ ++ div = max(div, unused_frac_mask + 1); ++ div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, ++ CM_DIV_FRAC_BITS - data->frac_bits)); ++ ++ return div; ++} ++ ++static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, ++ unsigned long parent_rate, ++ u32 div) ++{ ++ const struct bcm2835_clock_data *data = clock->data; ++ u64 temp; ++ ++ /* ++ * The divisor is a 12.12 fixed point field, but only some of ++ * the bits are populated in any given clock. ++ */ ++ div >>= CM_DIV_FRAC_BITS - data->frac_bits; ++ div &= (1 << (data->int_bits + data->frac_bits)) - 1; ++ ++ if (div == 0) ++ return 0; ++ ++ temp = (u64)parent_rate << data->frac_bits; ++ ++ do_div(temp, div); ++ ++ return temp; ++} ++ ++static long bcm2835_clock_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate); ++ ++ return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div); ++} ++ ++static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ 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); ++ ++ return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); ++} ++ ++static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) ++{ ++ struct bcm2835_cprman *cprman = clock->cprman; ++ const struct bcm2835_clock_data *data = clock->data; ++ ktime_t timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ ++ while (cprman_read(cprman, data->ctl_reg) & CM_BUSY) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "%s: couldn't lock PLL\n", ++ clk_hw_get_name(&clock->hw)); ++ return; ++ } ++ cpu_relax(); ++ } ++} ++ ++static void bcm2835_clock_off(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; ++ ++ spin_lock(&cprman->regs_lock); ++ cprman_write(cprman, data->ctl_reg, ++ cprman_read(cprman, data->ctl_reg) & ~CM_ENABLE); ++ spin_unlock(&cprman->regs_lock); ++ ++ /* BUSY will remain high until the divider completes its cycle. */ ++ bcm2835_clock_wait_busy(clock); ++} ++ ++static int bcm2835_clock_on(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; ++ ++ spin_lock(&cprman->regs_lock); ++ cprman_write(cprman, data->ctl_reg, ++ cprman_read(cprman, data->ctl_reg) | ++ CM_ENABLE | ++ CM_GATE); ++ spin_unlock(&cprman->regs_lock); ++ ++ return 0; ++} ++ ++static int bcm2835_clock_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ 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 = bcm2835_clock_choose_div(hw, rate, parent_rate); ++ ++ cprman_write(cprman, data->div_reg, div); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_clock_clk_ops = { ++ .is_prepared = bcm2835_clock_is_on, ++ .prepare = bcm2835_clock_on, ++ .unprepare = bcm2835_clock_off, ++ .recalc_rate = bcm2835_clock_get_rate, ++ .set_rate = bcm2835_clock_set_rate, ++ .round_rate = bcm2835_clock_round_rate, ++}; ++ ++static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) ++{ ++ return true; ++} ++ ++/* ++ * The VPU clock can never be disabled (it doesn't have an ENABLE ++ * bit), so it gets its own set of clock ops. ++ */ ++static const struct clk_ops bcm2835_vpu_clock_clk_ops = { ++ .is_prepared = bcm2835_vpu_clock_is_on, ++ .recalc_rate = bcm2835_clock_get_rate, ++ .set_rate = bcm2835_clock_set_rate, ++ .round_rate = bcm2835_clock_round_rate, ++}; ++ ++static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, ++ const struct bcm2835_pll_data *data) ++{ ++ struct bcm2835_pll *pll; ++ struct clk_init_data init; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLLs derive from the external oscillator. */ ++ init.parent_names = &cprman->osc_name; ++ init.num_parents = 1; ++ init.name = data->name; ++ init.ops = &bcm2835_pll_clk_ops; ++ init.flags = CLK_IGNORE_UNUSED; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return NULL; ++ ++ pll->cprman = cprman; ++ pll->data = data; ++ pll->hw.init = &init; ++ ++ return devm_clk_register(cprman->dev, &pll->hw); ++} ++ ++static struct clk * ++bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, ++ const struct bcm2835_pll_divider_data *data) ++{ ++ struct bcm2835_pll_divider *divider; ++ struct clk_init_data init; ++ struct clk *clk; ++ const char *divider_name; ++ ++ if (data->fixed_divider != 1) { ++ divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL, ++ "%s_prediv", data->name); ++ if (!divider_name) ++ return NULL; ++ } else { ++ divider_name = data->name; ++ } ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = &data->source_pll->name; ++ init.num_parents = 1; ++ init.name = divider_name; ++ init.ops = &bcm2835_pll_divider_clk_ops; ++ init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; ++ ++ divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); ++ if (!divider) ++ return NULL; ++ ++ divider->div.reg = cprman->regs + data->a2w_reg; ++ divider->div.shift = A2W_PLL_DIV_SHIFT; ++ divider->div.width = A2W_PLL_DIV_BITS; ++ divider->div.flags = 0; ++ divider->div.lock = &cprman->regs_lock; ++ divider->div.hw.init = &init; ++ divider->div.table = NULL; ++ ++ divider->cprman = cprman; ++ divider->data = data; ++ ++ clk = devm_clk_register(cprman->dev, ÷r->div.hw); ++ if (IS_ERR(clk)) ++ return clk; ++ ++ /* ++ * PLLH's channels have a fixed divide by 10 afterwards, which ++ * is what our consumers are actually using. ++ */ ++ if (data->fixed_divider != 1) { ++ return clk_register_fixed_factor(cprman->dev, data->name, ++ divider_name, ++ CLK_SET_RATE_PARENT, ++ 1, ++ data->fixed_divider); ++ } ++ ++ return clk; ++} ++ ++static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, ++ const struct bcm2835_clock_data *data) ++{ ++ struct bcm2835_clock *clock; ++ struct clk_init_data init; ++ const char *parent; ++ ++ /* ++ * Most of the clock generators have a mux field, so we ++ * instantiate a generic mux as our parent to handle it. ++ */ ++ if (data->num_mux_parents) { ++ const char *parents[1 << CM_SRC_BITS]; ++ int i; ++ ++ parent = devm_kasprintf(cprman->dev, GFP_KERNEL, ++ "mux_%s", data->name); ++ if (!parent) ++ return NULL; ++ ++ /* ++ * Replace our "xosc" references with the oscillator's ++ * actual name. ++ */ ++ 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]; ++ } ++ ++ clk_register_mux(cprman->dev, parent, ++ parents, data->num_mux_parents, ++ CLK_SET_RATE_PARENT, ++ cprman->regs + data->ctl_reg, ++ CM_SRC_SHIFT, CM_SRC_BITS, ++ 0, &cprman->regs_lock); ++ } else { ++ parent = data->parents[0]; ++ } ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &parent; ++ init.num_parents = 1; ++ init.name = data->name; ++ init.flags = CLK_IGNORE_UNUSED; ++ ++ if (data->is_vpu_clock) { ++ init.ops = &bcm2835_vpu_clock_clk_ops; ++ } else { ++ init.ops = &bcm2835_clock_clk_ops; ++ init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; ++ } ++ ++ clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->cprman = cprman; ++ clock->data = data; ++ clock->hw.init = &init; ++ ++ return devm_clk_register(cprman->dev, &clock->hw); ++} ++ ++static int bcm2835_clk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct clk **clks; ++ struct bcm2835_cprman *cprman; ++ struct resource *res; ++ ++ cprman = devm_kzalloc(dev, sizeof(*cprman), GFP_KERNEL); ++ if (!cprman) ++ return -ENOMEM; ++ ++ spin_lock_init(&cprman->regs_lock); ++ cprman->dev = dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ cprman->regs = devm_ioremap_resource(dev, res); ++ 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) ++ return -ENODEV; ++ ++ platform_set_drvdata(pdev, cprman); ++ ++ cprman->onecell.clk_num = BCM2835_CLOCK_COUNT; ++ cprman->onecell.clks = cprman->clks; ++ clks = cprman->clks; ++ ++ clks[BCM2835_PLLA] = bcm2835_register_pll(cprman, &bcm2835_plla_data); ++ clks[BCM2835_PLLB] = bcm2835_register_pll(cprman, &bcm2835_pllb_data); ++ clks[BCM2835_PLLC] = bcm2835_register_pll(cprman, &bcm2835_pllc_data); ++ clks[BCM2835_PLLD] = bcm2835_register_pll(cprman, &bcm2835_plld_data); ++ clks[BCM2835_PLLH] = bcm2835_register_pll(cprman, &bcm2835_pllh_data); ++ ++ clks[BCM2835_PLLA_CORE] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plla_core_data); ++ clks[BCM2835_PLLA_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plla_per_data); ++ clks[BCM2835_PLLC_CORE0] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core0_data); ++ clks[BCM2835_PLLC_CORE1] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core1_data); ++ clks[BCM2835_PLLC_CORE2] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core2_data); ++ clks[BCM2835_PLLC_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_per_data); ++ clks[BCM2835_PLLD_CORE] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plld_core_data); ++ clks[BCM2835_PLLD_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plld_per_data); ++ clks[BCM2835_PLLH_RCAL] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_rcal_data); ++ clks[BCM2835_PLLH_AUX] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_aux_data); ++ clks[BCM2835_PLLH_PIX] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_pix_data); ++ ++ clks[BCM2835_CLOCK_TIMER] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_timer_data); ++ clks[BCM2835_CLOCK_OTP] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_otp_data); ++ clks[BCM2835_CLOCK_TSENS] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_tsens_data); ++ clks[BCM2835_CLOCK_VPU] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_vpu_data); ++ clks[BCM2835_CLOCK_V3D] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); ++ clks[BCM2835_CLOCK_ISP] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_isp_data); ++ clks[BCM2835_CLOCK_H264] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_h264_data); ++ clks[BCM2835_CLOCK_V3D] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); ++ clks[BCM2835_CLOCK_SDRAM] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_sdram_data); ++ clks[BCM2835_CLOCK_UART] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_uart_data); ++ clks[BCM2835_CLOCK_VEC] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_vec_data); ++ clks[BCM2835_CLOCK_HSM] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_hsm_data); ++ clks[BCM2835_CLOCK_EMMC] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_emmc_data); ++ ++ /* ++ * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if ++ * you have the debug bit set in the power manager, which we ++ * don't bother exposing) are individual gates off of the ++ * non-stop vpu clock. ++ */ ++ clks[BCM2835_CLOCK_PERI_IMAGE] = ++ clk_register_gate(dev, "peri_image", "vpu", ++ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, ++ cprman->regs + CM_PERIICTL, CM_GATE_BIT, ++ 0, &cprman->regs_lock); ++ ++ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, ++ &cprman->onecell); ++} ++ ++static const struct of_device_id bcm2835_clk_of_match[] = { ++ { .compatible = "brcm,bcm2835-cprman", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match); ++ ++static struct platform_driver bcm2835_clk_driver = { ++ .driver = { ++ .name = "bcm2835-clk", ++ .of_match_table = bcm2835_clk_of_match, ++ }, ++ .probe = bcm2835_clk_probe, ++}; ++ ++module_platform_driver(bcm2835_clk_driver); ++ ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_DESCRIPTION("BCM2835 clock driver"); ++MODULE_LICENSE("GPL v2"); + +From 792857badec33b5a0a1f16c9d83588c524662c14 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 12 Oct 2015 11:23:34 -0700 +Subject: [PATCH 236/278] clk: bcm2835: Also build the driver for downstream + kernels. + +Signed-off-by: Eric Anholt +(cherry picked from commit fc0a178addf1cae65245e129e9bbe4a5daeb2cfd) +--- + drivers/clk/Makefile | 2 +- + drivers/clk/bcm/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 4178cd7..d7031a2 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -45,7 +45,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o + obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o + obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o + obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +-obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ ++obj-y += bcm/ + obj-$(CONFIG_ARCH_BERLIN) += berlin/ + obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ + obj-$(CONFIG_ARCH_HIP04) += hisilicon/ +diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile +index 72e245e..7f6dedf 100644 +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -2,4 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o ++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o + +From 918ccefee165eefdb7d68e61f25e4d1ad24ee40b Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 18 Jan 2016 10:01:11 -0800 +Subject: [PATCH 237/278] bcm2708: Add disabled-by-default cprman to the dtsi. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 463777e..0425419 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -86,6 +86,18 @@ + status = "disabled"; + }; + ++ cprman: cprman@7e101000 { ++ compatible = "brcm,bcm2835-cprman"; ++ #clock-cells = <1>; ++ reg = <0x7e101000 0x2000>; ++ ++ /* CPRMAN derives everything from the platform's ++ * oscillator. ++ */ ++ clocks = <&clk_osc>; ++ status = "disabled"; ++ }; ++ + random: rng@7e104000 { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; +@@ -319,6 +331,14 @@ + clock-div = <1>; + clock-mult = <2>; + }; ++ ++ clk_osc: clock@6 { ++ compatible = "fixed-clock"; ++ reg = <6>; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <19200000>; ++ }; + }; + + __overrides__ { + +From 2430a4bb8e3bb9ed9ff13842195745c151856085 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 18 Dec 2014 16:07:15 -0800 +Subject: [PATCH 238/278] mm: Remove the PFN busy warning + +See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is +expected sometimes when using CMA. However, that commit still spams +my kernel log with these warnings. + +Signed-off-by: Eric Anholt +--- + mm/page_alloc.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 18490f3..23076ed 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -6485,8 +6485,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, + + /* Make sure the range is really isolated. */ + if (test_pages_isolated(outer_start, end, false)) { +- pr_info("%s: [%lx, %lx) PFNs busy\n", +- __func__, outer_start, end); + ret = -EBUSY; + goto done; + } + +From 87f2b93bd74c772dbf4988ef18f0933c2dd682be Mon Sep 17 00:00:00 2001 +From: Ander Conselvan de Oliveira +Date: Tue, 21 Apr 2015 17:13:18 +0300 +Subject: [PATCH 239/278] drm/atomic: Make mode_fixup() optional for + check_modeset() + +So the i915 driver can use the same logic for setting mode and active +changed flags, without having to implement encoder helpers and the +mode_fixup() callback. + +Cc: dri-devel@lists.freedestkop.org +Signed-off-by: Ander Conselvan de Oliveira +Reviewed-by: Maarten Lankhorst +Acked-by: Dave Airlie +Signed-off-by: Daniel Vetter +(cherry picked from commit 840bfe953384a134c8639f2964d9b74bfa671e16) +--- + drivers/gpu/drm/drm_atomic_helper.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 1d2ca52..91011be 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -280,6 +280,8 @@ mode_fixup(struct drm_atomic_state *state) + */ + encoder = conn_state->best_encoder; + funcs = encoder->helper_private; ++ if (!funcs) ++ continue; + + if (encoder->bridge && encoder->bridge->funcs->mode_fixup) { + ret = encoder->bridge->funcs->mode_fixup( +@@ -317,6 +319,9 @@ mode_fixup(struct drm_atomic_state *state) + continue; + + funcs = crtc->helper_private; ++ if (!funcs->mode_fixup) ++ continue; ++ + ret = funcs->mode_fixup(crtc, &crtc_state->mode, + &crtc_state->adjusted_mode); + if (!ret) { + +From ebfe14332d7b3c92f3c2044ed5e103bf7bef3afe Mon Sep 17 00:00:00 2001 +From: Inki Dae +Date: Tue, 11 Aug 2015 21:23:49 +0900 +Subject: [PATCH 240/278] drm/atomic: fix null pointer access to mode_fixup + callback + +This patch fixes null pointer access incurred when +encoder driver didn't set its own mode_fixup callback. + +mode_fixup callback shoudn't be called if the callback +of drm_encoder_helper_funcs is NULL. + +Changelog v2: +- change it to else if + +Signed-off-by: Inki Dae +Reviewed-by: Maarten Lankhorst +Signed-off-by: Daniel Vetter +(cherry picked from commit 845249172a363c2217af5926fac17f58c7228aa4) +--- + drivers/gpu/drm/drm_atomic_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 91011be..03dc131 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -301,7 +301,7 @@ mode_fixup(struct drm_atomic_state *state) + encoder->base.id, encoder->name); + return ret; + } +- } else { ++ } else if (funcs->mode_fixup) { + ret = funcs->mode_fixup(encoder, &crtc_state->mode, + &crtc_state->adjusted_mode); + if (!ret) { + +From c95c2b9d03690c22cb99662c071545a13e29962c Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Thu, 9 Jul 2015 23:44:25 +0200 +Subject: [PATCH 241/278] drm: Add modeset object iterators + +And roll them out across drm_* files. The point here isn't code +prettification (it helps with that too) but that some of these lists +aren't static any more. And having macros will gives us a convenient +place to put locking checks into. + +I didn't add an iterator for props since that's only used by a +list_for_each_entry_safe in the driver teardown code. + +Search&replace was done with the below cocci spatch. Note that there's +a bunch more places that didn't match and which would need some manual +changes, but I've intentially left these out for this mostly automated +patch. + +iterator name drm_for_each_crtc; +struct drm_crtc *crtc; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc (crtc, dev) { +... +} + +@@ +iterator name drm_for_each_encoder; +struct drm_encoder *encoder; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder (encoder, dev) { +... +} + +@@ +iterator name drm_for_each_fb; +struct drm_framebuffer *fb; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(fb, &dev->mode_config.fb_list, head) { ++ drm_for_each_fb (fb, dev) { +... +} + +@@ +iterator name drm_for_each_connector; +struct drm_connector *connector; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector (connector, dev) { +... +} + +Reviewed-by: Maarten Lankhorst +Signed-off-by: Daniel Vetter +(cherry picked from commit 6295d607ad34ee4e43aab3f20714c2ef7a6adea1) +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++----------- + drivers/gpu/drm/drm_crtc_helper.c | 34 +++++++++++++++--------------- + drivers/gpu/drm/drm_fb_helper.c | 10 ++++----- + drivers/gpu/drm/drm_of.c | 2 +- + drivers/gpu/drm/drm_probe_helper.c | 6 +++--- + include/drm/drm_crtc.h | 15 +++++++++++++ + 6 files changed, 72 insertions(+), 38 deletions(-) + +diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c +index 800a025..f8e2659 100644 +--- a/drivers/gpu/drm/drm_crtc.c ++++ b/drivers/gpu/drm/drm_crtc.c +@@ -613,7 +613,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) + if (atomic_read(&fb->refcount.refcount) > 1) { + drm_modeset_lock_all(dev); + /* remove from any CRTC */ +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + memset(&set, 0, sizeof(struct drm_mode_set)); +@@ -625,7 +625,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) + } + } + +- list_for_each_entry(plane, &dev->mode_config.plane_list, head) { ++ drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } +@@ -1289,6 +1289,29 @@ unsigned int drm_plane_index(struct drm_plane *plane) + EXPORT_SYMBOL(drm_plane_index); + + /** ++ * drm_plane_from_index - find the registered plane at an index ++ * @dev: DRM device ++ * @idx: index of registered plane to find for ++ * ++ * Given a plane index, return the registered plane from DRM device's ++ * list of planes with matching index. ++ */ ++struct drm_plane * ++drm_plane_from_index(struct drm_device *dev, int idx) ++{ ++ struct drm_plane *plane; ++ unsigned int i = 0; ++ ++ drm_for_each_plane(plane, dev) { ++ if (i == idx) ++ return plane; ++ i++; ++ } ++ return NULL; ++} ++EXPORT_SYMBOL(drm_plane_from_index); ++ ++/** + * drm_plane_force_disable - Forcibly disable a plane + * @plane: plane to disable + * +@@ -1881,8 +1904,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; + if (!mode_group) { +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, +- head) { ++ drm_for_each_crtc(crtc, dev) { + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; +@@ -1908,9 +1930,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; + if (!mode_group) { +- list_for_each_entry(encoder, +- &dev->mode_config.encoder_list, +- head) { ++ drm_for_each_encoder(encoder, dev) { + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, + encoder->name); + if (put_user(encoder->base.id, encoder_id + +@@ -1939,9 +1959,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; + if (!mode_group) { +- list_for_each_entry(connector, +- &dev->mode_config.connector_list, +- head) { ++ drm_for_each_connector(connector, dev) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); +@@ -2230,7 +2248,7 @@ static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) + + /* For atomic drivers only state objects are synchronously updated and + * protected by modeset locks, so check those first. */ +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (!connector->state) + continue; + +@@ -5051,9 +5069,10 @@ void drm_mode_config_reset(struct drm_device *dev) + if (encoder->funcs->reset) + encoder->funcs->reset(encoder); + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) ++ drm_for_each_connector(connector, dev) { + if (connector->funcs->reset) + connector->funcs->reset(connector); ++ } + } + EXPORT_SYMBOL(drm_mode_config_reset); + +diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c +index ab00286..cc1871b 100644 +--- a/drivers/gpu/drm/drm_crtc_helper.c ++++ b/drivers/gpu/drm/drm_crtc_helper.c +@@ -182,7 +182,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) + + drm_warn_on_modeset_not_all_locked(dev); + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + if (!drm_helper_encoder_in_use(encoder)) { + drm_encoder_disable(encoder); + /* disconnect encoder from any connector */ +@@ -190,7 +190,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) + } + } + +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) { +@@ -232,7 +232,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev) + const struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_encoder *encoder; + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) +@@ -307,7 +307,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -338,7 +338,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + crtc->hwmode = *adjusted_mode; + + /* Prepare the encoders and CRTCs before setting the mode. */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -365,7 +365,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + if (!ret) + goto done; + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -384,7 +384,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ + crtc_funcs->commit(crtc); + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -428,11 +428,11 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) + struct drm_encoder *encoder; + + /* Decouple all encoders and their attached connectors from this crtc */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + if (encoder->crtc != crtc) + continue; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (connector->encoder != encoder) + continue; + +@@ -529,12 +529,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + * restored, not the drivers personal bookkeeping. + */ + count = 0; +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + save_encoders[count++] = *encoder; + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + save_connectors[count++] = *connector; + } + +@@ -572,7 +572,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + + /* a) traverse passed in connector list and get encoders for them */ + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + const struct drm_connector_helper_funcs *connector_funcs = + connector->helper_private; + new_encoder = connector->encoder; +@@ -612,7 +612,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (!connector->encoder) + continue; + +@@ -695,12 +695,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + fail: + /* Restore all previous data. */ + count = 0; +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + *encoder = save_encoders[count++]; + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + *connector = save_connectors[count++]; + } + +@@ -876,7 +876,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) + bool ret; + + drm_modeset_lock_all(dev); +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + + if (!crtc->enabled) + continue; +@@ -890,7 +890,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) + + /* Turn off outputs that were already powered off */ + if (drm_helper_choose_crtc_dpms(crtc)) { +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if(encoder->crtc != crtc) + continue; +diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c +index cac4229..3630d92 100644 +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -98,7 +98,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) + struct drm_connector *connector; + int i; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + struct drm_fb_helper_connector *fb_helper_connector; + + fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); +@@ -269,7 +269,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) + struct drm_device *dev = crtc->dev; + struct drm_crtc *c; + +- list_for_each_entry(c, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(c, dev) { + if (crtc->base.id == c->base.id) + return c->primary->fb; + } +@@ -321,7 +321,7 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) + + drm_warn_on_modeset_not_all_locked(dev); + +- list_for_each_entry(plane, &dev->mode_config.plane_list, head) { ++ drm_for_each_plane(plane, dev) { + if (plane->type != DRM_PLANE_TYPE_PRIMARY) + drm_plane_force_disable(plane); + +@@ -458,7 +458,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) + if (dev->primary->master) + return false; + +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb) + crtcs_bound++; + if (crtc->primary->fb == fb_helper->fb) +@@ -655,7 +655,7 @@ int drm_fb_helper_init(struct drm_device *dev, + } + + i = 0; +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + fb_helper->crtc_info[i].mode_set.crtc = crtc; + i++; + } +diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c +index aaa1307..be38840 100644 +--- a/drivers/gpu/drm/drm_of.c ++++ b/drivers/gpu/drm/drm_of.c +@@ -19,7 +19,7 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, + unsigned int index = 0; + struct drm_crtc *tmp; + +- list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(tmp, dev) { + if (tmp->port == port) + return 1 << index; + +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 0d75e75..1bca49c 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -313,7 +313,7 @@ static void output_poll_execute(struct work_struct *work) + goto out; + + mutex_lock(&dev->mode_config.mutex); +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + + /* Ignore forced connectors. */ + if (connector->force) +@@ -414,7 +414,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) + if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) + return; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT)) + poll = true; +@@ -496,7 +496,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + return false; + + mutex_lock(&dev->mode_config.mutex); +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + + /* Only handle HPD capable connectors. */ + if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) +diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h +index ca71c031..e48d53f 100644 +--- a/include/drm/drm_crtc.h ++++ b/include/drm/drm_crtc.h +@@ -1538,4 +1538,19 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id) + list_for_each_entry(plane, planelist, head) \ + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + ++#define drm_for_each_plane(plane, dev) \ ++ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) ++ ++#define drm_for_each_crtc(crtc, dev) \ ++ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) ++ ++#define drm_for_each_connector(connector, dev) \ ++ list_for_each_entry(connector, &(dev)->mode_config.connector_list, head) ++ ++#define drm_for_each_encoder(encoder, dev) \ ++ list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) ++ ++#define drm_for_each_fb(fb, dev) \ ++ list_for_each_entry(fb, &(dev)->mode_config.fb_list, head) ++ + #endif /* __DRM_CRTC_H__ */ + +From 0934ad7155dcc1f91fd001071ccfb6968aeb74af Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 30 Nov 2015 10:55:13 -0800 +Subject: [PATCH 242/278] drm: Create a driver hook for allocating GEM object + structs. + +The CMA helpers had no way for a driver to extend the struct with its +own fields. Since the CMA helpers are mostly "Allocate a +drm_gem_cma_object, then fill in a few fields", it's hard to write as +pure helpers without passing in a driver callback for the allocate +step. + +Signed-off-by: Eric Anholt +Reviewed-by: Daniel Vetter +(cherry picked from commit 10028c5ab107d3765c7fc282b6c45324d1602155) +--- + drivers/gpu/drm/drm_gem_cma_helper.c | 10 ++++++---- + include/drm/drmP.h | 7 +++++++ + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c +index e419eed..a2f13aa 100644 +--- a/drivers/gpu/drm/drm_gem_cma_helper.c ++++ b/drivers/gpu/drm/drm_gem_cma_helper.c +@@ -59,11 +59,13 @@ __drm_gem_cma_create(struct drm_device *drm, size_t size) + struct drm_gem_object *gem_obj; + int ret; + +- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); +- if (!cma_obj) ++ if (drm->driver->gem_create_object) ++ gem_obj = drm->driver->gem_create_object(drm, size); ++ else ++ gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); ++ if (!gem_obj) + return ERR_PTR(-ENOMEM); +- +- gem_obj = &cma_obj->base; ++ cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base); + + ret = drm_gem_object_init(drm, gem_obj, size); + if (ret) +diff --git a/include/drm/drmP.h b/include/drm/drmP.h +index 62c40777..2cadcb8 100644 +--- a/include/drm/drmP.h ++++ b/include/drm/drmP.h +@@ -567,6 +567,13 @@ struct drm_driver { + int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); + void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + ++ /** ++ * Hook for allocating the GEM object struct, for use by core ++ * helpers. ++ */ ++ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, ++ size_t size); ++ + /* prime: */ + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, + +From e5971ca2847e8949fd1032ea5e59300667c127c5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 18 Jan 2016 09:28:46 -0800 +Subject: [PATCH 243/278] drm/vc4: Import driver from rpi-4.4.y. + +There are minor backports involved (atomic_flush, enable_vblank, +disable_vblank, drm_atomic_helper_commit_planes arguments). + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/Kconfig | 2 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/vc4/Kconfig | 14 + + drivers/gpu/drm/vc4/Makefile | 26 + + drivers/gpu/drm/vc4/vc4_bo.c | 574 ++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_crtc.c | 769 ++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_debugfs.c | 42 ++ + drivers/gpu/drm/vc4/vc4_drv.c | 331 +++++++++++ + drivers/gpu/drm/vc4/vc4_drv.h | 462 +++++++++++++++ + drivers/gpu/drm/vc4/vc4_gem.c | 867 +++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi.c | 592 +++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hvs.c | 163 ++++++ + drivers/gpu/drm/vc4/vc4_irq.c | 210 +++++++ + drivers/gpu/drm/vc4/vc4_kms.c | 214 +++++++ + drivers/gpu/drm/vc4/vc4_packet.h | 399 +++++++++++++ + drivers/gpu/drm/vc4/vc4_plane.c | 386 +++++++++++++ + drivers/gpu/drm/vc4/vc4_qpu_defines.h | 264 +++++++++ + drivers/gpu/drm/vc4/vc4_regs.h | 570 ++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_render_cl.c | 634 ++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_trace.h | 63 ++ + drivers/gpu/drm/vc4/vc4_trace_points.c | 14 + + drivers/gpu/drm/vc4/vc4_v3d.c | 270 +++++++++ + drivers/gpu/drm/vc4/vc4_validate.c | 900 +++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 513 ++++++++++++++++ + include/uapi/drm/vc4_drm.h | 279 +++++++++ + 25 files changed, 8559 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/Kconfig + create mode 100644 drivers/gpu/drm/vc4/Makefile + create mode 100644 drivers/gpu/drm/vc4/vc4_bo.c + create mode 100644 drivers/gpu/drm/vc4/vc4_crtc.c + create mode 100644 drivers/gpu/drm/vc4/vc4_debugfs.c + create mode 100644 drivers/gpu/drm/vc4/vc4_drv.c + create mode 100644 drivers/gpu/drm/vc4/vc4_drv.h + create mode 100644 drivers/gpu/drm/vc4/vc4_gem.c + create mode 100644 drivers/gpu/drm/vc4/vc4_hdmi.c + create mode 100644 drivers/gpu/drm/vc4/vc4_hvs.c + create mode 100644 drivers/gpu/drm/vc4/vc4_irq.c + create mode 100644 drivers/gpu/drm/vc4/vc4_kms.c + create mode 100644 drivers/gpu/drm/vc4/vc4_packet.h + create mode 100644 drivers/gpu/drm/vc4/vc4_plane.c + create mode 100644 drivers/gpu/drm/vc4/vc4_qpu_defines.h + create mode 100644 drivers/gpu/drm/vc4/vc4_regs.h + create mode 100644 drivers/gpu/drm/vc4/vc4_render_cl.c + create mode 100644 drivers/gpu/drm/vc4/vc4_trace.h + create mode 100644 drivers/gpu/drm/vc4/vc4_trace_points.c + create mode 100644 drivers/gpu/drm/vc4/vc4_v3d.c + create mode 100644 drivers/gpu/drm/vc4/vc4_validate.c + create mode 100644 drivers/gpu/drm/vc4/vc4_validate_shaders.c + create mode 100644 include/uapi/drm/vc4_drm.h + +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index 47f2ce8..3151dc8 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -217,3 +217,5 @@ source "drivers/gpu/drm/sti/Kconfig" + source "drivers/gpu/drm/amd/amdkfd/Kconfig" + + source "drivers/gpu/drm/imx/Kconfig" ++ ++source "drivers/gpu/drm/vc4/Kconfig" +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 7d4944e..c6417cf 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_DRM_MGAG200) += mgag200/ + obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ + obj-$(CONFIG_DRM_SIS) += sis/ + obj-$(CONFIG_DRM_SAVAGE)+= savage/ ++obj-$(CONFIG_DRM_VC4)+= vc4/ + obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ + obj-$(CONFIG_DRM_VIA) +=via/ + obj-$(CONFIG_DRM_VGEM) += vgem/ +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +new file mode 100644 +index 0000000..71f019f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -0,0 +1,14 @@ ++config DRM_VC4 ++ tristate "Broadcom VC4 Graphics" ++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST ++ depends on DRM && HAVE_DMA_ATTRS ++ select DRM_KMS_HELPER ++ select DRM_KMS_CMA_HELPER ++ select DRM_GEM_CMA_HELPER ++ help ++ Choose this option if you have a system that has a Broadcom ++ VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. ++ ++ This driver requires that "avoid_warnings=2" be present in ++ the config.txt for the firmware, to keep it from smashing ++ our display setup. +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +new file mode 100644 +index 0000000..4c6a99f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -0,0 +1,26 @@ ++ccflags-y := -Iinclude/drm ++ ++# Please keep these build lists sorted! ++ ++# core driver code ++vc4-y := \ ++ vc4_bo.o \ ++ vc4_crtc.o \ ++ vc4_drv.o \ ++ vc4_kms.o \ ++ vc4_gem.o \ ++ vc4_hdmi.o \ ++ vc4_hvs.o \ ++ vc4_irq.o \ ++ vc4_plane.o \ ++ vc4_render_cl.o \ ++ vc4_trace_points.o \ ++ vc4_v3d.o \ ++ vc4_validate.o \ ++ vc4_validate_shaders.o ++ ++vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o ++ ++obj-$(CONFIG_DRM_VC4) += vc4.o ++ ++CFLAGS_vc4_trace_points.o := -I$(src) +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +new file mode 100644 +index 0000000..6247ff8 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -0,0 +1,574 @@ ++/* ++ * Copyright © 2015 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. ++ */ ++ ++/* DOC: VC4 GEM BO management support. ++ * ++ * The VC4 GPU architecture (both scanout and rendering) has direct ++ * access to system memory with no MMU in between. To support it, we ++ * use the GEM CMA helper functions to allocate contiguous ranges of ++ * physical memory for our BOs. ++ * ++ * Since the CMA allocator is very slow, we keep a cache of recently ++ * freed BOs around so that the kernel's allocation of objects for 3D ++ * rendering can return quickly. ++ */ ++ ++#include "vc4_drv.h" ++#include "uapi/drm/vc4_drm.h" ++ ++static void vc4_bo_stats_dump(struct vc4_dev *vc4) ++{ ++ DRM_INFO("num bos allocated: %d\n", ++ vc4->bo_stats.num_allocated); ++ DRM_INFO("size bos allocated: %dkb\n", ++ vc4->bo_stats.size_allocated / 1024); ++ DRM_INFO("num bos used: %d\n", ++ vc4->bo_stats.num_allocated - vc4->bo_stats.num_cached); ++ DRM_INFO("size bos used: %dkb\n", ++ (vc4->bo_stats.size_allocated - ++ vc4->bo_stats.size_cached) / 1024); ++ DRM_INFO("num bos cached: %d\n", ++ vc4->bo_stats.num_cached); ++ DRM_INFO("size bos cached: %dkb\n", ++ vc4->bo_stats.size_cached / 1024); ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_bo_stats_debugfs(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_bo_stats stats; ++ ++ /* Take a snapshot of the current stats with the lock held. */ ++ mutex_lock(&vc4->bo_lock); ++ stats = vc4->bo_stats; ++ mutex_unlock(&vc4->bo_lock); ++ ++ seq_printf(m, "num bos allocated: %d\n", ++ stats.num_allocated); ++ seq_printf(m, "size bos allocated: %dkb\n", ++ stats.size_allocated / 1024); ++ seq_printf(m, "num bos used: %d\n", ++ stats.num_allocated - stats.num_cached); ++ seq_printf(m, "size bos used: %dkb\n", ++ (stats.size_allocated - stats.size_cached) / 1024); ++ seq_printf(m, "num bos cached: %d\n", ++ stats.num_cached); ++ seq_printf(m, "size bos cached: %dkb\n", ++ stats.size_cached / 1024); ++ ++ return 0; ++} ++#endif ++ ++static uint32_t bo_page_index(size_t size) ++{ ++ return (size / PAGE_SIZE) - 1; ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_destroy(struct vc4_bo *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev); ++ ++ if (bo->validated_shader) { ++ kfree(bo->validated_shader->texture_samples); ++ kfree(bo->validated_shader); ++ bo->validated_shader = NULL; ++ } ++ ++ vc4->bo_stats.num_allocated--; ++ vc4->bo_stats.size_allocated -= obj->size; ++ drm_gem_cma_free_object(obj); ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_remove_from_cache(struct vc4_bo *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev); ++ ++ vc4->bo_stats.num_cached--; ++ vc4->bo_stats.size_cached -= obj->size; ++ ++ list_del(&bo->unref_head); ++ list_del(&bo->size_head); ++} ++ ++static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev, ++ size_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t page_index = bo_page_index(size); ++ ++ if (vc4->bo_cache.size_list_size <= page_index) { ++ uint32_t new_size = max(vc4->bo_cache.size_list_size * 2, ++ page_index + 1); ++ struct list_head *new_list; ++ uint32_t i; ++ ++ new_list = kmalloc_array(new_size, sizeof(struct list_head), ++ GFP_KERNEL); ++ if (!new_list) ++ return NULL; ++ ++ /* Rebase the old cached BO lists to their new list ++ * head locations. ++ */ ++ for (i = 0; i < vc4->bo_cache.size_list_size; i++) { ++ struct list_head *old_list = ++ &vc4->bo_cache.size_list[i]; ++ ++ if (list_empty(old_list)) ++ INIT_LIST_HEAD(&new_list[i]); ++ else ++ list_replace(old_list, &new_list[i]); ++ } ++ /* And initialize the brand new BO list heads. */ ++ for (i = vc4->bo_cache.size_list_size; i < new_size; i++) ++ INIT_LIST_HEAD(&new_list[i]); ++ ++ kfree(vc4->bo_cache.size_list); ++ vc4->bo_cache.size_list = new_list; ++ vc4->bo_cache.size_list_size = new_size; ++ } ++ ++ return &vc4->bo_cache.size_list[page_index]; ++} ++ ++void vc4_bo_cache_purge(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mutex_lock(&vc4->bo_lock); ++ while (!list_empty(&vc4->bo_cache.time_list)) { ++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, ++ struct vc4_bo, unref_head); ++ vc4_bo_remove_from_cache(bo); ++ vc4_bo_destroy(bo); ++ } ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev, ++ uint32_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t page_index = bo_page_index(size); ++ struct vc4_bo *bo = NULL; ++ ++ size = roundup(size, PAGE_SIZE); ++ ++ mutex_lock(&vc4->bo_lock); ++ if (page_index >= vc4->bo_cache.size_list_size) ++ goto out; ++ ++ if (list_empty(&vc4->bo_cache.size_list[page_index])) ++ goto out; ++ ++ bo = list_first_entry(&vc4->bo_cache.size_list[page_index], ++ struct vc4_bo, size_head); ++ vc4_bo_remove_from_cache(bo); ++ kref_init(&bo->base.base.refcount); ++ ++out: ++ mutex_unlock(&vc4->bo_lock); ++ return bo; ++} ++ ++/** ++ * vc4_gem_create_object - Implementation of driver->gem_create_object. ++ * ++ * This lets the CMA helpers allocate object structs for us, and keep ++ * our BO stats correct. ++ */ ++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_bo *bo; ++ ++ bo = kzalloc(sizeof(*bo), GFP_KERNEL); ++ if (!bo) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_lock(&vc4->bo_lock); ++ vc4->bo_stats.num_allocated++; ++ vc4->bo_stats.size_allocated += size; ++ mutex_unlock(&vc4->bo_lock); ++ ++ return &bo->base.base; ++} ++ ++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, ++ bool from_cache) ++{ ++ size_t size = roundup(unaligned_size, PAGE_SIZE); ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_gem_cma_object *cma_obj; ++ int pass; ++ ++ if (size == 0) ++ return NULL; ++ ++ /* 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; ++ } ++ ++ /* Otherwise, make a new BO. */ ++ for (pass = 0; ; pass++) { ++ cma_obj = drm_gem_cma_create(dev, size); ++ if (!IS_ERR(cma_obj)) ++ break; ++ ++ switch (pass) { ++ case 0: ++ /* ++ * If we've run out of CMA memory, kill the cache of ++ * CMA allocations we've got laying around and try again. ++ */ ++ vc4_bo_cache_purge(dev); ++ break; ++ case 1: ++ /* ++ * Getting desperate, so try to wait for any ++ * previous rendering to finish, free its ++ * unreferenced BOs to the cache, and then ++ * free the cache. ++ */ ++ vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true); ++ vc4_job_handle_completed(vc4); ++ vc4_bo_cache_purge(dev); ++ break; ++ case 3: ++ DRM_ERROR("Failed to allocate from CMA:\n"); ++ vc4_bo_stats_dump(vc4); ++ return NULL; ++ } ++ } ++ ++ return to_vc4_bo(&cma_obj->base); ++} ++ ++int vc4_dumb_create(struct drm_file *file_priv, ++ struct drm_device *dev, ++ struct drm_mode_create_dumb *args) ++{ ++ int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ if (args->pitch < min_pitch) ++ args->pitch = min_pitch; ++ ++ if (args->size < args->pitch * args->height) ++ args->size = args->pitch * args->height; ++ ++ bo = vc4_bo_create(dev, args->size, false); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_cache_free_old(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long expire_time = jiffies - msecs_to_jiffies(1000); ++ ++ while (!list_empty(&vc4->bo_cache.time_list)) { ++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, ++ struct vc4_bo, unref_head); ++ if (time_before(expire_time, bo->free_time)) { ++ mod_timer(&vc4->bo_cache.time_timer, ++ round_jiffies_up(jiffies + ++ msecs_to_jiffies(1000))); ++ return; ++ } ++ ++ vc4_bo_remove_from_cache(bo); ++ vc4_bo_destroy(bo); ++ } ++} ++ ++/* Called on the last userspace/kernel unreference of the BO. Returns ++ * it to the BO cache if possible, otherwise frees it. ++ * ++ * Note that this is called with the struct_mutex held. ++ */ ++void vc4_free_object(struct drm_gem_object *gem_bo) ++{ ++ struct drm_device *dev = gem_bo->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_bo *bo = to_vc4_bo(gem_bo); ++ struct list_head *cache_list; ++ ++ mutex_lock(&vc4->bo_lock); ++ /* If the object references someone else's memory, we can't cache it. ++ */ ++ if (gem_bo->import_attach) { ++ vc4_bo_destroy(bo); ++ goto out; ++ } ++ ++ /* Don't cache if it was publicly named. */ ++ if (gem_bo->name) { ++ 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); ++ goto out; ++ } ++ ++ if (bo->validated_shader) { ++ kfree(bo->validated_shader->texture_samples); ++ kfree(bo->validated_shader); ++ bo->validated_shader = NULL; ++ } ++ ++ bo->free_time = jiffies; ++ list_add(&bo->size_head, cache_list); ++ list_add(&bo->unref_head, &vc4->bo_cache.time_list); ++ ++ vc4->bo_stats.num_cached++; ++ vc4->bo_stats.size_cached += gem_bo->size; ++ ++ vc4_bo_cache_free_old(dev); ++ ++out: ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static void vc4_bo_cache_time_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, bo_cache.time_work); ++ struct drm_device *dev = vc4->dev; ++ ++ mutex_lock(&vc4->bo_lock); ++ vc4_bo_cache_free_old(dev); ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static void vc4_bo_cache_time_timer(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ schedule_work(&vc4->bo_cache.time_work); ++} ++ ++struct dma_buf * ++vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("Attempting to export shader BO\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return drm_gem_prime_export(dev, obj, flags); ++} ++ ++int vc4_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct drm_gem_object *gem_obj; ++ struct vc4_bo *bo; ++ int ret; ++ ++ ret = drm_gem_mmap(filp, vma); ++ if (ret) ++ return ret; ++ ++ gem_obj = vma->vm_private_data; ++ bo = to_vc4_bo(gem_obj); ++ ++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { ++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the ++ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map ++ * the whole buffer. ++ */ ++ vma->vm_flags &= ~VM_PFNMAP; ++ vma->vm_pgoff = 0; ++ ++ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma, ++ bo->base.vaddr, bo->base.paddr, ++ vma->vm_end - vma->vm_start); ++ if (ret) ++ drm_gem_vm_close(vma); ++ ++ return ret; ++} ++ ++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { ++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n"); ++ return -EINVAL; ++ } ++ ++ return drm_gem_cma_prime_mmap(obj, vma); ++} ++ ++void *vc4_prime_vmap(struct drm_gem_object *obj) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("mmaping of shader BOs not allowed.\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return drm_gem_cma_prime_vmap(obj); ++} ++ ++int vc4_create_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_create_bo *args = data; ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ /* ++ * We can't allocate from the BO cache, because the BOs don't ++ * get zeroed, and that might leak data between users. ++ */ ++ bo = vc4_bo_create(dev, args->size, false); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_mmap_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ ++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); ++ return -EINVAL; ++ } ++ ++ /* The mmap offset was set up at BO allocation time. */ ++ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); ++ ++ drm_gem_object_unreference_unlocked(gem_obj); ++ return 0; ++} ++ ++int ++vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_create_shader_bo *args = data; ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ if (args->size == 0) ++ return -EINVAL; ++ ++ if (args->size % sizeof(u64) != 0) ++ return -EINVAL; ++ ++ if (args->flags != 0) { ++ DRM_INFO("Unknown flags set: 0x%08x\n", args->flags); ++ return -EINVAL; ++ } ++ ++ if (args->pad != 0) { ++ DRM_INFO("Pad set: 0x%08x\n", args->pad); ++ return -EINVAL; ++ } ++ ++ bo = vc4_bo_create(dev, args->size, true); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = copy_from_user(bo->base.vaddr, ++ (void __user *)(uintptr_t)args->data, ++ args->size); ++ if (ret != 0) ++ goto fail; ++ /* Clear the rest of the memory from allocating from the BO ++ * cache. ++ */ ++ memset(bo->base.vaddr + args->size, 0, ++ bo->base.base.size - args->size); ++ ++ bo->validated_shader = vc4_validate_shader(&bo->base); ++ if (!bo->validated_shader) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ /* We have to create the handle after validation, to avoid ++ * races for users to do doing things like mmap the shader BO. ++ */ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ ++ fail: ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++void vc4_bo_cache_init(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mutex_init(&vc4->bo_lock); ++ ++ INIT_LIST_HEAD(&vc4->bo_cache.time_list); ++ ++ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work); ++ setup_timer(&vc4->bo_cache.time_timer, ++ vc4_bo_cache_time_timer, ++ (unsigned long)dev); ++} ++ ++void vc4_bo_cache_destroy(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ del_timer(&vc4->bo_cache.time_timer); ++ cancel_work_sync(&vc4->bo_cache.time_work); ++ ++ vc4_bo_cache_purge(dev); ++ ++ if (vc4->bo_stats.num_allocated) { ++ DRM_ERROR("Destroying BO cache while BOs still allocated:\n"); ++ vc4_bo_stats_dump(vc4); ++ } ++} +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +new file mode 100644 +index 0000000..c28090b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 CRTC module ++ * ++ * In VC4, the Pixel Valve is what most closely corresponds to the ++ * DRM's concept of a CRTC. The PV generates video timings from the ++ * output's clock plus its configuration. It pulls scaled pixels from ++ * the HVS at that timing, and feeds it to the encoder. ++ * ++ * However, the DRM CRTC also collects the configuration of all the ++ * DRM planes attached to it. As a result, this file also manages ++ * setup of the VC4 HVS's display elements on the CRTC. ++ * ++ * The 2835 has 3 different pixel valves. pv0 in the audio power ++ * domain feeds DSI0 or DPI, while pv1 feeds DS1 or SMI. pv2 in the ++ * image domain can feed either HDMI or the SDTV controller. The ++ * pixel valve chooses from the CPRMAN clocks (HSM for HDMI, VEC for ++ * SDTV, etc.) according to which output type is chosen in the mux. ++ * ++ * For power management, the pixel valve's registers are all clocked ++ * by the AXI clock, while the timings and FIFOs make use of the ++ * output-specific clock. Since the encoders also directly consume ++ * the CPRMAN clocks, and know what timings they need, they are the ++ * ones that set the clock. ++ */ ++ ++#include "drm_atomic.h" ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "linux/clk.h" ++#include "drm_fb_cma_helper.h" ++#include "linux/component.h" ++#include "linux/of_device.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++struct vc4_crtc { ++ struct drm_crtc base; ++ const struct vc4_crtc_data *data; ++ void __iomem *regs; ++ ++ /* Which HVS channel we're using for our CRTC. */ ++ int channel; ++ ++ /* Pointer to the actual hardware display list memory for the ++ * crtc. ++ */ ++ u32 __iomem *dlist; ++ ++ u32 dlist_size; /* in dwords */ ++ ++ struct drm_pending_vblank_event *event; ++}; ++ ++static inline struct vc4_crtc * ++to_vc4_crtc(struct drm_crtc *crtc) ++{ ++ return (struct vc4_crtc *)crtc; ++} ++ ++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; ++}; ++ ++#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) ++#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) ++ ++#define CRTC_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} crtc_regs[] = { ++ CRTC_REG(PV_CONTROL), ++ CRTC_REG(PV_V_CONTROL), ++ CRTC_REG(PV_VSYNCD), ++ CRTC_REG(PV_HORZA), ++ CRTC_REG(PV_HORZB), ++ CRTC_REG(PV_VERTA), ++ CRTC_REG(PV_VERTB), ++ CRTC_REG(PV_VERTA_EVEN), ++ CRTC_REG(PV_VERTB_EVEN), ++ CRTC_REG(PV_INTEN), ++ CRTC_REG(PV_INTSTAT), ++ CRTC_REG(PV_STAT), ++ CRTC_REG(PV_HACT_ACT), ++}; ++ ++static void vc4_crtc_dump_regs(struct vc4_crtc *vc4_crtc) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ crtc_regs[i].reg, crtc_regs[i].name, ++ CRTC_READ(crtc_regs[i].reg)); ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_crtc_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; ++ int crtc_index = (uintptr_t)node->info_ent->data; ++ struct drm_crtc *crtc; ++ struct vc4_crtc *vc4_crtc; ++ int i; ++ ++ i = 0; ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ if (i == crtc_index) ++ break; ++ i++; ++ } ++ if (!crtc) ++ return 0; ++ vc4_crtc = to_vc4_crtc(crtc); ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ crtc_regs[i].name, crtc_regs[i].reg, ++ CRTC_READ(crtc_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void vc4_crtc_destroy(struct drm_crtc *crtc) ++{ ++ drm_crtc_cleanup(crtc); ++} ++ ++static u32 vc4_get_fifo_full_level(u32 format) ++{ ++ static const u32 fifo_len_bytes = 64; ++ static const u32 hvs_latency_pix = 6; ++ ++ switch (format) { ++ case PV_CONTROL_FORMAT_DSIV_16: ++ case PV_CONTROL_FORMAT_DSIC_16: ++ return fifo_len_bytes - 2 * hvs_latency_pix; ++ case PV_CONTROL_FORMAT_DSIV_18: ++ return fifo_len_bytes - 14; ++ case PV_CONTROL_FORMAT_24: ++ case PV_CONTROL_FORMAT_DSIV_24: ++ default: ++ return fifo_len_bytes - 3 * hvs_latency_pix; ++ } ++} ++ ++/* ++ * Returns the clock select bit for the connector attached to the ++ * CRTC. ++ */ ++static int vc4_get_clock_select(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 -1; ++} ++ ++static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) ++{ ++ 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 vactive = (mode->vdisplay >> (interlace ? 1 : 0)); ++ u32 format = 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)); ++ vc4_crtc_dump_regs(vc4_crtc); ++ } ++ ++ /* Reset the PV fifo. */ ++ CRTC_WRITE(PV_CONTROL, 0); ++ CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); ++ CRTC_WRITE(PV_CONTROL, 0); ++ ++ CRTC_WRITE(PV_HORZA, ++ VC4_SET_FIELD(mode->htotal - mode->hsync_end, ++ PV_HORZA_HBP) | ++ VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, ++ PV_HORZA_HSYNC)); ++ CRTC_WRITE(PV_HORZB, ++ VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, ++ PV_HORZB_HFP) | ++ VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); ++ ++ if (interlace) { ++ CRTC_WRITE(PV_VERTA_EVEN, ++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, ++ PV_VERTA_VBP) | ++ VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, ++ PV_VERTA_VSYNC)); ++ CRTC_WRITE(PV_VERTB_EVEN, ++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, ++ PV_VERTB_VFP) | ++ VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); ++ } ++ ++ CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); ++ ++ CRTC_WRITE(PV_V_CONTROL, ++ PV_VCONTROL_CONTINUOUS | ++ (interlace ? PV_VCONTROL_INTERLACE : 0)); ++ ++ CRTC_WRITE(PV_CONTROL, ++ VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | ++ VC4_SET_FIELD(vc4_get_fifo_full_level(format), ++ PV_CONTROL_FIFO_LEVEL) | ++ PV_CONTROL_CLR_AT_START | ++ PV_CONTROL_TRIGGER_UNDERFLOW | ++ PV_CONTROL_WAIT_HSTART | ++ VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | ++ PV_CONTROL_FIFO_CLR | ++ PV_CONTROL_EN); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc)); ++ vc4_crtc_dump_regs(vc4_crtc); ++ } ++} ++ ++static void require_hvs_enabled(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) != ++ SCALER_DISPCTRL_ENABLE); ++} ++ ++static void vc4_crtc_disable(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ u32 chan = vc4_crtc->channel; ++ int ret; ++ require_hvs_enabled(dev); ++ ++ CRTC_WRITE(PV_V_CONTROL, ++ CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN); ++ ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); ++ WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n"); ++ ++ if (HVS_READ(SCALER_DISPCTRLX(chan)) & ++ SCALER_DISPCTRLX_ENABLE) { ++ HVS_WRITE(SCALER_DISPCTRLX(chan), ++ SCALER_DISPCTRLX_RESET); ++ ++ /* While the docs say that reset is self-clearing, it ++ * seems it doesn't actually. ++ */ ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); ++ } ++ ++ /* Once we leave, the scaler should be disabled and its fifo empty. */ ++ ++ WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); ++ ++ WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), ++ SCALER_DISPSTATX_MODE) != ++ SCALER_DISPSTATX_MODE_DISABLED); ++ ++ WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & ++ (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != ++ SCALER_DISPSTATX_EMPTY); ++} ++ ++static void vc4_crtc_enable(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_crtc_state *state = crtc->state; ++ struct drm_display_mode *mode = &state->adjusted_mode; ++ ++ require_hvs_enabled(dev); ++ ++ /* Turn on the scaler, which will wait for vstart to start ++ * compositing. ++ */ ++ HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), ++ VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | ++ SCALER_DISPCTRLX_ENABLE); ++ ++ /* Turn on the pixel valve, which will emit the vstart signal. */ ++ CRTC_WRITE(PV_V_CONTROL, ++ CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); ++} ++ ++static int vc4_crtc_atomic_check(struct drm_crtc *crtc, ++ struct drm_crtc_state *state) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane; ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ u32 dlist_count = 0; ++ ++ /* The pixelvalve can only feed one encoder (and encoders are ++ * 1:1 with connectors.) ++ */ ++ if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1) ++ return -EINVAL; ++ ++ drm_atomic_crtc_state_for_each_plane(plane, state) { ++ struct drm_plane_state *plane_state = ++ state->state->plane_states[drm_plane_index(plane)]; ++ ++ /* plane might not have changed, in which case take ++ * current state: ++ */ ++ if (!plane_state) ++ plane_state = plane->state; ++ ++ dlist_count += vc4_plane_dlist_size(plane_state); ++ } ++ ++ dlist_count++; /* Account for SCALER_CTL0_END. */ ++ ++ if (!vc4_crtc->dlist || dlist_count > vc4_crtc->dlist_size) { ++ vc4_crtc->dlist = ((u32 __iomem *)vc4->hvs->dlist + ++ HVS_BOOTLOADER_DLIST_END); ++ vc4_crtc->dlist_size = ((SCALER_DLIST_SIZE >> 2) - ++ HVS_BOOTLOADER_DLIST_END); ++ ++ if (dlist_count > vc4_crtc->dlist_size) { ++ DRM_DEBUG_KMS("dlist too large for CRTC (%d > %d).\n", ++ dlist_count, vc4_crtc->dlist_size); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static void vc4_crtc_atomic_flush(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_plane *plane; ++ bool debug_dump_regs = false; ++ u32 __iomem *dlist_next = vc4_crtc->dlist; ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); ++ vc4_hvs_dump_state(dev); ++ } ++ ++ /* Copy all the active planes' dlist contents to the hardware dlist. ++ * ++ * XXX: If the new display list was large enough that it ++ * overlapped a currently-read display list, we need to do ++ * something like disable scanout before putting in the new ++ * list. For now, we're safe because we only have the two ++ * planes. ++ */ ++ drm_atomic_crtc_for_each_plane(plane, crtc) { ++ dlist_next += vc4_plane_write_dlist(plane, dlist_next); ++ } ++ ++ if (dlist_next == vc4_crtc->dlist) { ++ /* If no planes were enabled, use the SCALER_CTL0_END ++ * at the start of the display list memory (in the ++ * bootloader section). We'll rewrite that ++ * SCALER_CTL0_END, just in case, though. ++ */ ++ writel(SCALER_CTL0_END, vc4->hvs->dlist); ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), 0); ++ } else { ++ writel(SCALER_CTL0_END, dlist_next); ++ dlist_next++; ++ ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ (u32 __iomem *)vc4_crtc->dlist - ++ (u32 __iomem *)vc4->hvs->dlist); ++ ++ /* Make the next display list start after ours. */ ++ vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist); ++ vc4_crtc->dlist = dlist_next; ++ } ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); ++ vc4_hvs_dump_state(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; ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ crtc->state->event = NULL; ++ } ++} ++ ++int vc4_enable_vblank(struct drm_device *dev, int crtc_id) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; ++ ++ CRTC_WRITE(PV_INTEN, PV_INT_VFP_START); ++ ++ return 0; ++} ++ ++void vc4_disable_vblank(struct drm_device *dev, int crtc_id) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; ++ ++ CRTC_WRITE(PV_INTEN, 0); ++} ++ ++static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) ++{ ++ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ if (vc4_crtc->event) { ++ drm_crtc_send_vblank_event(crtc, vc4_crtc->event); ++ vc4_crtc->event = NULL; ++ } ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++} ++ ++static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) ++{ ++ struct vc4_crtc *vc4_crtc = data; ++ u32 stat = CRTC_READ(PV_INTSTAT); ++ irqreturn_t ret = IRQ_NONE; ++ ++ if (stat & PV_INT_VFP_START) { ++ CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); ++ drm_crtc_handle_vblank(&vc4_crtc->base); ++ vc4_crtc_handle_page_flip(vc4_crtc); ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++struct vc4_async_flip_state { ++ struct drm_crtc *crtc; ++ struct drm_framebuffer *fb; ++ struct drm_pending_vblank_event *event; ++ ++ struct vc4_seqno_cb cb; ++}; ++ ++/* Called when the V3D execution for the BO being flipped to is done, so that ++ * we can actually update the plane's address to point to it. ++ */ ++static void ++vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) ++{ ++ struct vc4_async_flip_state *flip_state = ++ container_of(cb, struct vc4_async_flip_state, cb); ++ struct drm_crtc *crtc = flip_state->crtc; ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane = crtc->primary; ++ ++ vc4_plane_async_set_fb(plane, flip_state->fb); ++ if (flip_state->event) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, flip_state->event); ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } ++ ++ drm_framebuffer_unreference(flip_state->fb); ++ kfree(flip_state); ++ ++ up(&vc4->async_modeset); ++} ++ ++/* Implements async (non-vblank-synced) page flips. ++ * ++ * The page flip ioctl needs to return immediately, so we grab the ++ * modeset semaphore on the pipe, and queue the address update for ++ * when V3D is done with the BO being flipped to. ++ */ ++static int vc4_async_page_flip(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, ++ struct drm_pending_vblank_event *event, ++ uint32_t flags) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane = crtc->primary; ++ int ret = 0; ++ struct vc4_async_flip_state *flip_state; ++ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); ++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); ++ ++ flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL); ++ if (!flip_state) ++ return -ENOMEM; ++ ++ drm_framebuffer_reference(fb); ++ flip_state->fb = fb; ++ flip_state->crtc = crtc; ++ flip_state->event = event; ++ ++ /* Make sure all other async modesetes have landed. */ ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(flip_state); ++ return ret; ++ } ++ ++ /* Immediately update the plane's legacy fb pointer, so that later ++ * modeset prep sees the state that will be present when the semaphore ++ * is released. ++ */ ++ drm_atomic_set_fb_for_plane(plane->state, fb); ++ plane->fb = fb; ++ ++ vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, ++ vc4_async_page_flip_complete); ++ ++ /* Driver takes ownership of state on successful async commit. */ ++ return 0; ++} ++ ++static int vc4_page_flip(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, ++ struct drm_pending_vblank_event *event, ++ uint32_t flags) ++{ ++ if (flags & DRM_MODE_PAGE_FLIP_ASYNC) ++ return vc4_async_page_flip(crtc, fb, event, flags); ++ else ++ return drm_atomic_helper_page_flip(crtc, fb, event, flags); ++} ++ ++static const struct drm_crtc_funcs vc4_crtc_funcs = { ++ .set_config = drm_atomic_helper_set_config, ++ .destroy = vc4_crtc_destroy, ++ .page_flip = vc4_page_flip, ++ .set_property = NULL, ++ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ ++ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */ ++ .reset = drm_atomic_helper_crtc_reset, ++ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, ++}; ++ ++static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { ++ .mode_set_nofb = vc4_crtc_mode_set_nofb, ++ .disable = vc4_crtc_disable, ++ .enable = vc4_crtc_enable, ++ .atomic_check = vc4_crtc_atomic_check, ++ .atomic_flush = vc4_crtc_atomic_flush, ++}; ++ ++/* Frees the page flip event when the DRM device is closed with the ++ * event still outstanding. ++ */ ++void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ ++ if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) { ++ vc4_crtc->event->base.destroy(&vc4_crtc->event->base); ++ drm_crtc_vblank_put(crtc); ++ vc4_crtc->event = NULL; ++ } ++ ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++} ++ ++static const struct vc4_crtc_data pv0_data = { ++ .hvs_channel = 0, ++ .encoder0_type = VC4_ENCODER_TYPE_DSI0, ++ .encoder1_type = 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, ++}; ++ ++static const struct vc4_crtc_data pv2_data = { ++ .hvs_channel = 1, ++ .encoder0_type = VC4_ENCODER_TYPE_VEC, ++ .encoder1_type = VC4_ENCODER_TYPE_HDMI, ++}; ++ ++static const struct of_device_id vc4_crtc_dt_match[] = { ++ { .compatible = "brcm,bcm2835-pixelvalve0", .data = &pv0_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve1", .data = &pv1_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve2", .data = &pv2_data }, ++ {} ++}; ++ ++static void vc4_set_crtc_possible_masks(struct drm_device *drm, ++ struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ 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); ++ } ++ } ++} ++ ++static int vc4_crtc_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_crtc *vc4_crtc; ++ struct drm_crtc *crtc; ++ struct drm_plane *primary_plane, *cursor_plane; ++ const struct of_device_id *match; ++ int ret; ++ ++ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); ++ if (!vc4_crtc) ++ return -ENOMEM; ++ crtc = &vc4_crtc->base; ++ ++ match = of_match_device(vc4_crtc_dt_match, dev); ++ if (!match) ++ return -ENODEV; ++ vc4_crtc->data = match->data; ++ ++ vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(vc4_crtc->regs)) ++ return PTR_ERR(vc4_crtc->regs); ++ ++ /* For now, we create just the primary and the legacy cursor ++ * planes. We should be able to stack more planes on easily, ++ * but to do that we would need to compute the bandwidth ++ * requirement of the plane configuration, and reject ones ++ * that will take too much. ++ */ ++ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); ++ if (IS_ERR(primary_plane)) { ++ dev_err(dev, "failed to construct primary plane\n"); ++ ret = PTR_ERR(primary_plane); ++ goto err; ++ } ++ ++ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); ++ if (IS_ERR(cursor_plane)) { ++ dev_err(dev, "failed to construct cursor plane\n"); ++ ret = PTR_ERR(cursor_plane); ++ goto err_primary; ++ } ++ ++ drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane, ++ &vc4_crtc_funcs); ++ drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); ++ primary_plane->crtc = crtc; ++ cursor_plane->crtc = crtc; ++ vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc; ++ vc4_crtc->channel = vc4_crtc->data->hvs_channel; ++ ++ CRTC_WRITE(PV_INTEN, 0); ++ CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc); ++ if (ret) ++ goto err_cursor; ++ ++ vc4_set_crtc_possible_masks(drm, crtc); ++ ++ platform_set_drvdata(pdev, vc4_crtc); ++ ++ return 0; ++ ++err_cursor: ++ cursor_plane->funcs->destroy(cursor_plane); ++err_primary: ++ primary_plane->funcs->destroy(primary_plane); ++err: ++ return ret; ++} ++ ++static void vc4_crtc_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); ++ ++ vc4_crtc_destroy(&vc4_crtc->base); ++ ++ CRTC_WRITE(PV_INTEN, 0); ++ ++ platform_set_drvdata(pdev, NULL); ++} ++ ++static const struct component_ops vc4_crtc_ops = { ++ .bind = vc4_crtc_bind, ++ .unbind = vc4_crtc_unbind, ++}; ++ ++static int vc4_crtc_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_crtc_ops); ++} ++ ++static int vc4_crtc_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_crtc_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_crtc_driver = { ++ .probe = vc4_crtc_dev_probe, ++ .remove = vc4_crtc_dev_remove, ++ .driver = { ++ .name = "vc4_crtc", ++ .of_match_table = vc4_crtc_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +new file mode 100644 +index 0000000..d76ad10 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -0,0 +1,42 @@ ++/* ++ * Copyright © 2014 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++static const struct drm_info_list vc4_debugfs_list[] = { ++ {"bo_stats", vc4_bo_stats_debugfs, 0}, ++ {"hdmi_regs", vc4_hdmi_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}, ++ {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2}, ++ {"v3d_ident", vc4_v3d_debugfs_ident, 0}, ++ {"v3d_regs", vc4_v3d_debugfs_regs, 0}, ++}; ++ ++#define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list) ++ ++int ++vc4_debugfs_init(struct drm_minor *minor) ++{ ++ return drm_debugfs_create_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, ++ minor->debugfs_root, minor); ++} ++ ++void ++vc4_debugfs_cleanup(struct drm_minor *minor) ++{ ++ drm_debugfs_remove_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +new file mode 100644 +index 0000000..22061ae +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -0,0 +1,331 @@ ++/* ++ * Copyright (C) 2014-2015 Broadcom ++ * Copyright (C) 2013 Red Hat ++ * ++ * 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 ++#include "drm_fb_cma_helper.h" ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define DRIVER_NAME "vc4" ++#define DRIVER_DESC "Broadcom VC4 graphics" ++#define DRIVER_DATE "20140616" ++#define DRIVER_MAJOR 0 ++#define DRIVER_MINOR 0 ++#define DRIVER_PATCHLEVEL 0 ++ ++/* Helper function for mapping the regs on a platform device. */ ++void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index) ++{ ++ struct resource *res; ++ void __iomem *map; ++ ++ res = platform_get_resource(dev, IORESOURCE_MEM, index); ++ map = devm_ioremap_resource(&dev->dev, res); ++ if (IS_ERR(map)) { ++ DRM_ERROR("Failed to map registers: %ld\n", PTR_ERR(map)); ++ return map; ++ } ++ ++ return map; ++} ++ ++static void vc4_drm_preclose(struct drm_device *dev, struct drm_file *file) ++{ ++ struct drm_crtc *crtc; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) ++ vc4_cancel_page_flip(crtc, file); ++} ++ ++static void vc4_lastclose(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_restore_mode(vc4->fbdev); ++} ++ ++static const struct file_operations vc4_drm_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .unlocked_ioctl = drm_ioctl, ++ .mmap = vc4_mmap, ++ .poll = drm_poll, ++ .read = drm_read, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = drm_compat_ioctl, ++#endif ++ .llseek = noop_llseek, ++}; ++ ++static const struct drm_ioctl_desc vc4_drm_ioctls[] = { ++ DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, ++ DRM_ROOT_ONLY), ++}; ++ ++static struct drm_driver vc4_drm_driver = { ++ .driver_features = (DRIVER_MODESET | ++ DRIVER_ATOMIC | ++ DRIVER_GEM | ++ DRIVER_HAVE_IRQ | ++ DRIVER_PRIME), ++ .lastclose = vc4_lastclose, ++ .preclose = vc4_drm_preclose, ++ ++ .irq_handler = vc4_irq, ++ .irq_preinstall = vc4_irq_preinstall, ++ .irq_postinstall = vc4_irq_postinstall, ++ .irq_uninstall = vc4_irq_uninstall, ++ ++ .enable_vblank = vc4_enable_vblank, ++ .disable_vblank = vc4_disable_vblank, ++ .get_vblank_counter = drm_vblank_count, ++ ++#if defined(CONFIG_DEBUG_FS) ++ .debugfs_init = vc4_debugfs_init, ++ .debugfs_cleanup = vc4_debugfs_cleanup, ++#endif ++ ++ .gem_create_object = vc4_create_object, ++ .gem_free_object = vc4_free_object, ++ .gem_vm_ops = &drm_gem_cma_vm_ops, ++ ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import = drm_gem_prime_import, ++ .gem_prime_export = vc4_prime_export, ++ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, ++ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, ++ .gem_prime_vmap = vc4_prime_vmap, ++ .gem_prime_vunmap = drm_gem_cma_prime_vunmap, ++ .gem_prime_mmap = vc4_prime_mmap, ++ ++ .dumb_create = vc4_dumb_create, ++ .dumb_map_offset = drm_gem_cma_dumb_map_offset, ++ .dumb_destroy = drm_gem_dumb_destroy, ++ ++ .ioctls = vc4_drm_ioctls, ++ .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), ++ .fops = &vc4_drm_fops, ++ ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++static int compare_dev(struct device *dev, void *data) ++{ ++ return dev == data; ++} ++ ++static void vc4_match_add_drivers(struct device *dev, ++ struct component_match **match, ++ struct platform_driver *const *drivers, ++ int count) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) { ++ struct device_driver *drv = &drivers[i]->driver; ++ struct device *p = NULL, *d; ++ ++ while ((d = bus_find_device(&platform_bus_type, p, drv, ++ (void *)platform_bus_type.match))) { ++ put_device(p); ++ component_match_add(dev, match, compare_dev, d); ++ p = d; ++ } ++ put_device(p); ++ } ++} ++ ++static int vc4_drm_bind(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm; ++ struct drm_connector *connector; ++ struct vc4_dev *vc4; ++ struct device_node *firmware_node; ++ int ret = 0; ++ ++ dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL); ++ if (!vc4) ++ return -ENOMEM; ++ ++ firmware_node = of_parse_phandle(dev->of_node, "firmware", 0); ++ vc4->firmware = rpi_firmware_get(firmware_node); ++ if (!vc4->firmware) { ++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); ++ return -EPROBE_DEFER; ++ } ++ of_node_put(firmware_node); ++ ++ drm = drm_dev_alloc(&vc4_drm_driver, dev); ++ if (!drm) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, drm); ++ vc4->dev = drm; ++ drm->dev_private = vc4; ++ ++ drm_dev_set_unique(drm, dev_name(dev)); ++ ++ vc4_bo_cache_init(drm); ++ ++ drm_mode_config_init(drm); ++ if (ret) ++ goto unref; ++ ++ vc4_gem_init(drm); ++ ++ ret = component_bind_all(dev, drm); ++ if (ret) ++ goto gem_destroy; ++ ++ ret = drm_dev_register(drm, 0); ++ if (ret < 0) ++ goto unbind_all; ++ ++ /* Connector registration has to occur after DRM device ++ * registration, because it creates sysfs entries based on the ++ * DRM device. ++ */ ++ list_for_each_entry(connector, &drm->mode_config.connector_list, head) { ++ ret = drm_connector_register(connector); ++ if (ret) ++ goto unregister; ++ } ++ ++ vc4_kms_load(drm); ++ ++ return 0; ++ ++unregister: ++ drm_dev_unregister(drm); ++unbind_all: ++ component_unbind_all(dev, drm); ++gem_destroy: ++ vc4_gem_destroy(drm); ++unref: ++ drm_dev_unref(drm); ++ vc4_bo_cache_destroy(drm); ++ return ret; ++} ++ ++static void vc4_drm_unbind(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_fini(vc4->fbdev); ++ ++ drm_mode_config_cleanup(drm); ++ ++ drm_put_dev(drm); ++} ++ ++static const struct component_master_ops vc4_drm_ops = { ++ .bind = vc4_drm_bind, ++ .unbind = vc4_drm_unbind, ++}; ++ ++static struct platform_driver *const component_drivers[] = { ++ &vc4_hdmi_driver, ++ &vc4_crtc_driver, ++ &vc4_hvs_driver, ++ &vc4_v3d_driver, ++}; ++ ++static int vc4_platform_drm_probe(struct platform_device *pdev) ++{ ++ struct component_match *match = NULL; ++ struct device *dev = &pdev->dev; ++ ++ vc4_match_add_drivers(dev, &match, ++ component_drivers, ARRAY_SIZE(component_drivers)); ++ ++ return component_master_add_with_match(dev, &vc4_drm_ops, match); ++} ++ ++static int vc4_platform_drm_remove(struct platform_device *pdev) ++{ ++ component_master_del(&pdev->dev, &vc4_drm_ops); ++ ++ return 0; ++} ++ ++static const struct of_device_id vc4_of_match[] = { ++ { .compatible = "brcm,bcm2835-vc4", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, vc4_of_match); ++ ++static struct platform_driver vc4_platform_driver = { ++ .probe = vc4_platform_drm_probe, ++ .remove = vc4_platform_drm_remove, ++ .driver = { ++ .name = "vc4-drm", ++ .of_match_table = vc4_of_match, ++ }, ++}; ++ ++static int __init vc4_drm_register(void) ++{ ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(component_drivers); i++) { ++ ret = platform_driver_register(component_drivers[i]); ++ if (ret) { ++ while (--i >= 0) ++ platform_driver_unregister(component_drivers[i]); ++ return ret; ++ } ++ } ++ return platform_driver_register(&vc4_platform_driver); ++} ++ ++static void __exit vc4_drm_unregister(void) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(component_drivers) - 1; i >= 0; i--) ++ platform_driver_unregister(component_drivers[i]); ++ ++ platform_driver_unregister(&vc4_platform_driver); ++} ++ ++module_init(vc4_drm_register); ++module_exit(vc4_drm_unregister); ++ ++MODULE_ALIAS("platform:vc4-drm"); ++MODULE_DESCRIPTION("Broadcom VC4 DRM Driver"); ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +new file mode 100644 +index 0000000..03e037e +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -0,0 +1,462 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#include "drmP.h" ++#include "drm_gem_cma_helper.h" ++ ++struct vc4_dev { ++ struct drm_device *dev; ++ ++ struct vc4_hdmi *hdmi; ++ struct vc4_hvs *hvs; ++ struct vc4_crtc *crtc[3]; ++ struct vc4_v3d *v3d; ++ ++ struct drm_fbdev_cma *fbdev; ++ struct rpi_firmware *firmware; ++ ++ struct vc4_hang_state *hang_state; ++ ++ /* The kernel-space BO cache. Tracks buffers that have been ++ * unreferenced by all other users (refcounts of 0!) but not ++ * yet freed, so we can do cheap allocations. ++ */ ++ struct vc4_bo_cache { ++ /* Array of list heads for entries in the BO cache, ++ * based on number of pages, so we can do O(1) lookups ++ * in the cache when allocating. ++ */ ++ struct list_head *size_list; ++ uint32_t size_list_size; ++ ++ /* List of all BOs in the cache, ordered by age, so we ++ * can do O(1) lookups when trying to free old ++ * buffers. ++ */ ++ struct list_head time_list; ++ struct work_struct time_work; ++ struct timer_list time_timer; ++ } bo_cache; ++ ++ struct vc4_bo_stats { ++ u32 num_allocated; ++ u32 size_allocated; ++ u32 num_cached; ++ u32 size_cached; ++ } bo_stats; ++ ++ /* Protects bo_cache and the BO stats. */ ++ struct mutex bo_lock; ++ ++ /* Sequence number for the last job queued in job_list. ++ * Starts at 0 (no jobs emitted). ++ */ ++ uint64_t emit_seqno; ++ ++ /* Sequence number for the last completed job on the GPU. ++ * Starts at 0 (no jobs completed). ++ */ ++ uint64_t finished_seqno; ++ ++ /* List of all struct vc4_exec_info for jobs to be executed. ++ * The first job in the list is the one currently programmed ++ * into ct0ca/ct1ca for execution. ++ */ ++ struct list_head job_list; ++ /* List of the finished vc4_exec_infos waiting to be freed by ++ * job_done_work. ++ */ ++ struct list_head job_done_list; ++ /* Spinlock used to synchronize the job_list and seqno ++ * accesses between the IRQ handler and GEM ioctls. ++ */ ++ spinlock_t job_lock; ++ wait_queue_head_t job_wait_queue; ++ struct work_struct job_done_work; ++ ++ /* List of struct vc4_seqno_cb for callbacks to be made from a ++ * workqueue when the given seqno is passed. ++ */ ++ struct list_head seqno_cb_list; ++ ++ /* The binner overflow memory that's currently set up in ++ * BPOA/BPOS registers. When overflow occurs and a new one is ++ * allocated, the previous one will be moved to ++ * vc4->current_exec's free list. ++ */ ++ struct vc4_bo *overflow_mem; ++ struct work_struct overflow_mem_work; ++ ++ struct { ++ uint32_t last_ct0ca, last_ct1ca; ++ struct timer_list timer; ++ struct work_struct reset_work; ++ } hangcheck; ++ ++ struct semaphore async_modeset; ++}; ++ ++static inline struct vc4_dev * ++to_vc4_dev(struct drm_device *dev) ++{ ++ return (struct vc4_dev *)dev->dev_private; ++} ++ ++struct vc4_bo { ++ struct drm_gem_cma_object base; ++ ++ /* seqno of the last job to render to this BO. */ ++ uint64_t seqno; ++ ++ /* List entry for the BO's position in either ++ * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list ++ */ ++ struct list_head unref_head; ++ ++ /* Time in jiffies when the BO was put in vc4->bo_cache. */ ++ unsigned long free_time; ++ ++ /* List entry for the BO's position in vc4_dev->bo_cache.size_list */ ++ struct list_head size_head; ++ ++ /* Struct for shader validation state, if created by ++ * DRM_IOCTL_VC4_CREATE_SHADER_BO. ++ */ ++ struct vc4_validated_shader_info *validated_shader; ++}; ++ ++static inline struct vc4_bo * ++to_vc4_bo(struct drm_gem_object *bo) ++{ ++ return (struct vc4_bo *)bo; ++} ++ ++struct vc4_seqno_cb { ++ struct work_struct work; ++ uint64_t seqno; ++ void (*func)(struct vc4_seqno_cb *cb); ++}; ++ ++struct vc4_v3d { ++ struct platform_device *pdev; ++ void __iomem *regs; ++}; ++ ++struct vc4_hvs { ++ struct platform_device *pdev; ++ void __iomem *regs; ++ void __iomem *dlist; ++}; ++ ++struct vc4_plane { ++ struct drm_plane base; ++}; ++ ++static inline struct vc4_plane * ++to_vc4_plane(struct drm_plane *plane) ++{ ++ return (struct vc4_plane *)plane; ++} ++ ++enum vc4_encoder_type { ++ VC4_ENCODER_TYPE_HDMI, ++ VC4_ENCODER_TYPE_VEC, ++ VC4_ENCODER_TYPE_DSI0, ++ VC4_ENCODER_TYPE_DSI1, ++ VC4_ENCODER_TYPE_SMI, ++ VC4_ENCODER_TYPE_DPI, ++}; ++ ++struct vc4_encoder { ++ struct drm_encoder base; ++ enum vc4_encoder_type type; ++ u32 clock_select; ++}; ++ ++static inline struct vc4_encoder * ++to_vc4_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_encoder, base); ++} ++ ++#define V3D_READ(offset) readl(vc4->v3d->regs + offset) ++#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset) ++#define HVS_READ(offset) readl(vc4->hvs->regs + offset) ++#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset) ++ ++struct vc4_exec_info { ++ /* Sequence number for this bin/render job. */ ++ uint64_t seqno; ++ ++ /* Kernel-space copy of the ioctl arguments */ ++ struct drm_vc4_submit_cl *args; ++ ++ /* This is the array of BOs that were looked up at the start of exec. ++ * Command validation will use indices into this array. ++ */ ++ struct drm_gem_cma_object **bo; ++ uint32_t bo_count; ++ ++ /* Pointers for our position in vc4->job_list */ ++ struct list_head head; ++ ++ /* List of other BOs used in the job that need to be released ++ * once the job is complete. ++ */ ++ struct list_head unref_list; ++ ++ /* Current unvalidated indices into @bo loaded by the non-hardware ++ * VC4_PACKET_GEM_HANDLES. ++ */ ++ uint32_t bo_index[2]; ++ ++ /* This is the BO where we store the validated command lists, shader ++ * records, and uniforms. ++ */ ++ struct drm_gem_cma_object *exec_bo; ++ ++ /** ++ * This tracks the per-shader-record state (packet 64) that ++ * determines the length of the shader record and the offset ++ * it's expected to be found at. It gets read in from the ++ * command lists. ++ */ ++ struct vc4_shader_state { ++ uint32_t addr; ++ /* Maximum vertex index referenced by any primitive using this ++ * shader state. ++ */ ++ uint32_t max_index; ++ } *shader_state; ++ ++ /** How many shader states the user declared they were using. */ ++ uint32_t shader_state_size; ++ /** How many shader state records the validator has seen. */ ++ uint32_t shader_state_count; ++ ++ bool found_tile_binning_mode_config_packet; ++ bool found_start_tile_binning_packet; ++ bool found_increment_semaphore_packet; ++ bool found_flush; ++ uint8_t bin_tiles_x, bin_tiles_y; ++ struct drm_gem_cma_object *tile_bo; ++ uint32_t tile_alloc_offset; ++ ++ /** ++ * Computed addresses pointing into exec_bo where we start the ++ * bin thread (ct0) and render thread (ct1). ++ */ ++ uint32_t ct0ca, ct0ea; ++ uint32_t ct1ca, ct1ea; ++ ++ /* Pointer to the unvalidated bin CL (if present). */ ++ void *bin_u; ++ ++ /* Pointers to the shader recs. These paddr gets incremented as CL ++ * packets are relocated in validate_gl_shader_state, and the vaddrs ++ * (u and v) get incremented and size decremented as the shader recs ++ * themselves are validated. ++ */ ++ void *shader_rec_u; ++ void *shader_rec_v; ++ uint32_t shader_rec_p; ++ uint32_t shader_rec_size; ++ ++ /* Pointers to the uniform data. These pointers are incremented, and ++ * size decremented, as each batch of uniforms is uploaded. ++ */ ++ void *uniforms_u; ++ void *uniforms_v; ++ uint32_t uniforms_p; ++ uint32_t uniforms_size; ++}; ++ ++static inline struct vc4_exec_info * ++vc4_first_job(struct vc4_dev *vc4) ++{ ++ if (list_empty(&vc4->job_list)) ++ return NULL; ++ return list_first_entry(&vc4->job_list, struct vc4_exec_info, head); ++} ++ ++/** ++ * struct vc4_texture_sample_info - saves the offsets into the UBO for texture ++ * setup parameters. ++ * ++ * This will be used at draw time to relocate the reference to the texture ++ * contents in p0, and validate that the offset combined with ++ * width/height/stride/etc. from p1 and p2/p3 doesn't sample outside the BO. ++ * Note that the hardware treats unprovided config parameters as 0, so not all ++ * of them need to be set up for every texure sample, and we'll store ~0 as ++ * the offset to mark the unused ones. ++ * ++ * See the VC4 3D architecture guide page 41 ("Texture and Memory Lookup Unit ++ * Setup") for definitions of the texture parameters. ++ */ ++struct vc4_texture_sample_info { ++ bool is_direct; ++ uint32_t p_offset[4]; ++}; ++ ++/** ++ * struct vc4_validated_shader_info - information about validated shaders that ++ * needs to be used from command list validation. ++ * ++ * For a given shader, each time a shader state record references it, we need ++ * to verify that the shader doesn't read more uniforms than the shader state ++ * record's uniform BO pointer can provide, and we need to apply relocations ++ * and validate the shader state record's uniforms that define the texture ++ * samples. ++ */ ++struct vc4_validated_shader_info { ++ uint32_t uniforms_size; ++ uint32_t uniforms_src_size; ++ uint32_t num_texture_samples; ++ struct vc4_texture_sample_info *texture_samples; ++}; ++ ++/** ++ * _wait_for - magic (register) wait macro ++ * ++ * Does the right thing for modeset paths when run under kdgb or similar atomic ++ * contexts. Note that it's important that we check the condition again after ++ * having timed out, since the timeout could be due to preemption or similar and ++ * we've never had a chance to check the condition before the timeout. ++ */ ++#define _wait_for(COND, MS, W) ({ \ ++ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \ ++ int ret__ = 0; \ ++ while (!(COND)) { \ ++ if (time_after(jiffies, timeout__)) { \ ++ if (!(COND)) \ ++ ret__ = -ETIMEDOUT; \ ++ break; \ ++ } \ ++ if (W && drm_can_sleep()) { \ ++ msleep(W); \ ++ } else { \ ++ cpu_relax(); \ ++ } \ ++ } \ ++ ret__; \ ++}) ++ ++#define wait_for(COND, MS) _wait_for(COND, MS, 1) ++ ++/* vc4_bo.c */ ++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size); ++void vc4_free_object(struct drm_gem_object *gem_obj); ++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size, ++ bool from_cache); ++int vc4_dumb_create(struct drm_file *file_priv, ++ struct drm_device *dev, ++ struct drm_mode_create_dumb *args); ++struct dma_buf *vc4_prime_export(struct drm_device *dev, ++ struct drm_gem_object *obj, int flags); ++int vc4_create_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_mmap(struct file *filp, struct vm_area_struct *vma); ++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); ++void *vc4_prime_vmap(struct drm_gem_object *obj); ++void vc4_bo_cache_init(struct drm_device *dev); ++void vc4_bo_cache_destroy(struct drm_device *dev); ++int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); ++ ++/* vc4_crtc.c */ ++extern struct platform_driver vc4_crtc_driver; ++int vc4_enable_vblank(struct drm_device *dev, int crtc_id); ++void vc4_disable_vblank(struct drm_device *dev, int crtc_id); ++void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); ++int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); ++ ++/* vc4_debugfs.c */ ++int vc4_debugfs_init(struct drm_minor *minor); ++void vc4_debugfs_cleanup(struct drm_minor *minor); ++ ++/* vc4_drv.c */ ++void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); ++ ++/* vc4_gem.c */ ++void vc4_gem_init(struct drm_device *dev); ++void vc4_gem_destroy(struct drm_device *dev); ++int vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_wait_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++void vc4_submit_next_job(struct drm_device *dev); ++int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, ++ uint64_t timeout_ns, bool interruptible); ++void vc4_job_handle_completed(struct vc4_dev *vc4); ++int vc4_queue_seqno_cb(struct drm_device *dev, ++ struct vc4_seqno_cb *cb, uint64_t seqno, ++ void (*func)(struct vc4_seqno_cb *cb)); ++ ++/* vc4_hdmi.c */ ++extern struct platform_driver vc4_hdmi_driver; ++int vc4_hdmi_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); ++int vc4_irq_postinstall(struct drm_device *dev); ++void vc4_irq_uninstall(struct drm_device *dev); ++void vc4_irq_reset(struct drm_device *dev); ++ ++/* vc4_hvs.c */ ++extern struct platform_driver vc4_hvs_driver; ++void vc4_hvs_dump_state(struct drm_device *dev); ++int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused); ++ ++/* vc4_kms.c */ ++int vc4_kms_load(struct drm_device *dev); ++ ++/* vc4_plane.c */ ++struct drm_plane *vc4_plane_init(struct drm_device *dev, ++ enum drm_plane_type type); ++u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); ++u32 vc4_plane_dlist_size(struct drm_plane_state *state); ++void vc4_plane_async_set_fb(struct drm_plane *plane, ++ struct drm_framebuffer *fb); ++ ++/* vc4_v3d.c */ ++extern struct platform_driver vc4_v3d_driver; ++int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); ++int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); ++int vc4_v3d_set_power(struct vc4_dev *vc4, bool on); ++ ++/* vc4_validate.c */ ++int ++vc4_validate_bin_cl(struct drm_device *dev, ++ void *validated, ++ void *unvalidated, ++ struct vc4_exec_info *exec); ++ ++int ++vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec); ++ ++struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec, ++ uint32_t hindex); ++ ++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec); ++ ++bool vc4_check_tex_size(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *fbo, ++ uint32_t offset, uint8_t tiling_format, ++ uint32_t width, uint32_t height, uint8_t cpp); ++ ++/* vc4_validate_shader.c */ ++struct vc4_validated_shader_info * ++vc4_validate_shader(struct drm_gem_cma_object *shader_obj); +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +new file mode 100644 +index 0000000..39f29e7 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -0,0 +1,867 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++#include "vc4_trace.h" ++ ++static void ++vc4_queue_hangcheck(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mod_timer(&vc4->hangcheck.timer, ++ round_jiffies_up(jiffies + msecs_to_jiffies(100))); ++} ++ ++struct vc4_hang_state { ++ struct drm_vc4_get_hang_state user_state; ++ ++ u32 bo_count; ++ struct drm_gem_object **bo; ++}; ++ ++static void ++vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state) ++{ ++ unsigned int i; ++ ++ mutex_lock(&dev->struct_mutex); ++ for (i = 0; i < state->user_state.bo_count; i++) ++ drm_gem_object_unreference(state->bo[i]); ++ mutex_unlock(&dev->struct_mutex); ++ ++ kfree(state); ++} ++ ++int ++vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_get_hang_state *get_state = data; ++ struct drm_vc4_get_hang_state_bo *bo_state; ++ struct vc4_hang_state *kernel_state; ++ struct drm_vc4_get_hang_state *state; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; ++ u32 i; ++ int ret; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ kernel_state = vc4->hang_state; ++ if (!kernel_state) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return -ENOENT; ++ } ++ state = &kernel_state->user_state; ++ ++ /* If the user's array isn't big enough, just return the ++ * required array size. ++ */ ++ if (get_state->bo_count < state->bo_count) { ++ get_state->bo_count = state->bo_count; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return 0; ++ } ++ ++ vc4->hang_state = NULL; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ /* Save the user's BO pointer, so we don't stomp it with the memcpy. */ ++ state->bo = get_state->bo; ++ memcpy(get_state, state, sizeof(*state)); ++ ++ bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL); ++ if (!bo_state) { ++ ret = -ENOMEM; ++ goto err_free; ++ } ++ ++ for (i = 0; i < state->bo_count; i++) { ++ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]); ++ u32 handle; ++ ++ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i], ++ &handle); ++ ++ if (ret) { ++ state->bo_count = i - 1; ++ goto err; ++ } ++ bo_state[i].handle = handle; ++ bo_state[i].paddr = vc4_bo->base.paddr; ++ bo_state[i].size = vc4_bo->base.base.size; ++ } ++ ++ ret = copy_to_user((void __user *)(uintptr_t)get_state->bo, ++ bo_state, ++ state->bo_count * sizeof(*bo_state)); ++ kfree(bo_state); ++ ++err_free: ++ ++ vc4_free_hang_state(dev, kernel_state); ++ ++err: ++ return ret; ++} ++ ++static void ++vc4_save_hang_state(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_vc4_get_hang_state *state; ++ struct vc4_hang_state *kernel_state; ++ struct vc4_exec_info *exec; ++ struct vc4_bo *bo; ++ unsigned long irqflags; ++ unsigned int i, unref_list_count; ++ ++ kernel_state = kcalloc(1, sizeof(*state), GFP_KERNEL); ++ if (!kernel_state) ++ return; ++ ++ state = &kernel_state->user_state; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ exec = vc4_first_job(vc4); ++ if (!exec) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return; ++ } ++ ++ unref_list_count = 0; ++ list_for_each_entry(bo, &exec->unref_list, unref_head) ++ unref_list_count++; ++ ++ state->bo_count = exec->bo_count + unref_list_count; ++ kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo), ++ GFP_ATOMIC); ++ if (!kernel_state->bo) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return; ++ } ++ ++ for (i = 0; i < exec->bo_count; i++) { ++ drm_gem_object_reference(&exec->bo[i]->base); ++ kernel_state->bo[i] = &exec->bo[i]->base; ++ } ++ ++ list_for_each_entry(bo, &exec->unref_list, unref_head) { ++ drm_gem_object_reference(&bo->base.base); ++ kernel_state->bo[i] = &bo->base.base; ++ i++; ++ } ++ ++ state->start_bin = exec->ct0ca; ++ state->start_render = exec->ct1ca; ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ state->ct0ca = V3D_READ(V3D_CTNCA(0)); ++ state->ct0ea = V3D_READ(V3D_CTNEA(0)); ++ ++ state->ct1ca = V3D_READ(V3D_CTNCA(1)); ++ state->ct1ea = V3D_READ(V3D_CTNEA(1)); ++ ++ state->ct0cs = V3D_READ(V3D_CTNCS(0)); ++ state->ct1cs = V3D_READ(V3D_CTNCS(1)); ++ ++ state->ct0ra0 = V3D_READ(V3D_CT00RA0); ++ state->ct1ra0 = V3D_READ(V3D_CT01RA0); ++ ++ state->bpca = V3D_READ(V3D_BPCA); ++ state->bpcs = V3D_READ(V3D_BPCS); ++ state->bpoa = V3D_READ(V3D_BPOA); ++ state->bpos = V3D_READ(V3D_BPOS); ++ ++ state->vpmbase = V3D_READ(V3D_VPMBASE); ++ ++ state->dbge = V3D_READ(V3D_DBGE); ++ state->fdbgo = V3D_READ(V3D_FDBGO); ++ state->fdbgb = V3D_READ(V3D_FDBGB); ++ state->fdbgr = V3D_READ(V3D_FDBGR); ++ state->fdbgs = V3D_READ(V3D_FDBGS); ++ state->errstat = V3D_READ(V3D_ERRSTAT); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ if (vc4->hang_state) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ vc4_free_hang_state(dev, kernel_state); ++ } else { ++ vc4->hang_state = kernel_state; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ } ++} ++ ++static void ++vc4_reset(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ DRM_INFO("Resetting GPU.\n"); ++ vc4_v3d_set_power(vc4, false); ++ vc4_v3d_set_power(vc4, true); ++ ++ vc4_irq_reset(dev); ++ ++ /* Rearm the hangcheck -- another job might have been waiting ++ * for our hung one to get kicked off, and vc4_irq_reset() ++ * would have started it. ++ */ ++ vc4_queue_hangcheck(dev); ++} ++ ++static void ++vc4_reset_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, hangcheck.reset_work); ++ ++ vc4_save_hang_state(vc4->dev); ++ ++ vc4_reset(vc4->dev); ++} ++ ++static void ++vc4_hangcheck_elapsed(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t ct0ca, ct1ca; ++ ++ /* If idle, we can stop watching for hangs. */ ++ if (list_empty(&vc4->job_list)) ++ return; ++ ++ ct0ca = V3D_READ(V3D_CTNCA(0)); ++ ct1ca = V3D_READ(V3D_CTNCA(1)); ++ ++ /* If we've made any progress in execution, rearm the timer ++ * and wait. ++ */ ++ if (ct0ca != vc4->hangcheck.last_ct0ca || ++ ct1ca != vc4->hangcheck.last_ct1ca) { ++ vc4->hangcheck.last_ct0ca = ct0ca; ++ vc4->hangcheck.last_ct1ca = ct1ca; ++ vc4_queue_hangcheck(dev); ++ return; ++ } ++ ++ /* We've gone too long with no progress, reset. This has to ++ * be done from a work struct, since resetting can sleep and ++ * this timer hook isn't allowed to. ++ */ ++ schedule_work(&vc4->hangcheck.reset_work); ++} ++ ++static void ++submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Set the current and end address of the control list. ++ * Writing the end register is what starts the job. ++ */ ++ V3D_WRITE(V3D_CTNCA(thread), start); ++ V3D_WRITE(V3D_CTNEA(thread), end); ++} ++ ++int ++vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, ++ bool interruptible) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ unsigned long timeout_expire; ++ DEFINE_WAIT(wait); ++ ++ if (vc4->finished_seqno >= seqno) ++ return 0; ++ ++ if (timeout_ns == 0) ++ return -ETIME; ++ ++ timeout_expire = jiffies + nsecs_to_jiffies(timeout_ns); ++ ++ trace_vc4_wait_for_seqno_begin(dev, seqno, timeout_ns); ++ for (;;) { ++ prepare_to_wait(&vc4->job_wait_queue, &wait, ++ interruptible ? TASK_INTERRUPTIBLE : ++ TASK_UNINTERRUPTIBLE); ++ ++ if (interruptible && signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; ++ } ++ ++ if (vc4->finished_seqno >= seqno) ++ break; ++ ++ if (timeout_ns != ~0ull) { ++ if (time_after_eq(jiffies, timeout_expire)) { ++ ret = -ETIME; ++ break; ++ } ++ schedule_timeout(timeout_expire - jiffies); ++ } else { ++ schedule(); ++ } ++ } ++ ++ finish_wait(&vc4->job_wait_queue, &wait); ++ trace_vc4_wait_for_seqno_end(dev, seqno); ++ ++ if (ret && ret != -ERESTARTSYS) { ++ DRM_ERROR("timeout waiting for render thread idle\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ++vc4_flush_caches(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Flush the GPU L2 caches. These caches sit on top of system ++ * L3 (the 128kb or so shared with the CPU), and are ++ * non-allocating in the L3. ++ */ ++ V3D_WRITE(V3D_L2CACTL, ++ V3D_L2CACTL_L2CCLR); ++ ++ V3D_WRITE(V3D_SLCACTL, ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T1CC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T0CC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_UCC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_ICC)); ++} ++ ++/* Sets the registers for the next job to be actually be executed in ++ * the hardware. ++ * ++ * The job_lock should be held during this. ++ */ ++void ++vc4_submit_next_job(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_exec_info *exec = vc4_first_job(vc4); ++ ++ if (!exec) ++ return; ++ ++ vc4_flush_caches(dev); ++ ++ /* Disable the binner's pre-loaded overflow memory address */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ if (exec->ct0ca != exec->ct0ea) ++ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea); ++ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea); ++} ++ ++static void ++vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) ++{ ++ struct vc4_bo *bo; ++ unsigned i; ++ ++ for (i = 0; i < exec->bo_count; i++) { ++ bo = to_vc4_bo(&exec->bo[i]->base); ++ bo->seqno = seqno; ++ } ++ ++ list_for_each_entry(bo, &exec->unref_list, unref_head) { ++ bo->seqno = seqno; ++ } ++} ++ ++/* Queues a struct vc4_exec_info for execution. If no job is ++ * currently executing, then submits it. ++ * ++ * Unlike most GPUs, our hardware only handles one command list at a ++ * time. To queue multiple jobs at once, we'd need to edit the ++ * previous command list to have a jump to the new one at the end, and ++ * then bump the end address. That's a change for a later date, ++ * though. ++ */ ++static void ++vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint64_t seqno; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ ++ seqno = ++vc4->emit_seqno; ++ exec->seqno = seqno; ++ vc4_update_bo_seqnos(exec, seqno); ++ ++ list_add_tail(&exec->head, &vc4->job_list); ++ ++ /* If no job was executing, kick ours off. Otherwise, it'll ++ * get started when the previous job's frame done interrupt ++ * occurs. ++ */ ++ if (vc4_first_job(vc4) == exec) { ++ vc4_submit_next_job(dev); ++ vc4_queue_hangcheck(dev); ++ } ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} ++ ++/** ++ * Looks up a bunch of GEM handles for BOs and stores the array for ++ * use in the command validator that actually writes relocated ++ * addresses pointing to them. ++ */ ++static int ++vc4_cl_lookup_bos(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct vc4_exec_info *exec) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ uint32_t *handles; ++ int ret = 0; ++ int i; ++ ++ exec->bo_count = args->bo_handle_count; ++ ++ if (!exec->bo_count) { ++ /* See comment on bo_index for why we have to check ++ * this. ++ */ ++ DRM_ERROR("Rendering requires BOs to validate\n"); ++ return -EINVAL; ++ } ++ ++ exec->bo = kcalloc(exec->bo_count, sizeof(struct drm_gem_cma_object *), ++ GFP_KERNEL); ++ if (!exec->bo) { ++ DRM_ERROR("Failed to allocate validated BO pointers\n"); ++ return -ENOMEM; ++ } ++ ++ handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t)); ++ if (!handles) { ++ DRM_ERROR("Failed to allocate incoming GEM handles\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(handles, ++ (void __user *)(uintptr_t)args->bo_handles, ++ exec->bo_count * sizeof(uint32_t)); ++ if (ret) { ++ DRM_ERROR("Failed to copy in GEM handles\n"); ++ goto fail; ++ } ++ ++ spin_lock(&file_priv->table_lock); ++ for (i = 0; i < exec->bo_count; i++) { ++ struct drm_gem_object *bo = idr_find(&file_priv->object_idr, ++ handles[i]); ++ if (!bo) { ++ DRM_ERROR("Failed to look up GEM BO %d: %d\n", ++ i, handles[i]); ++ ret = -EINVAL; ++ spin_unlock(&file_priv->table_lock); ++ goto fail; ++ } ++ drm_gem_object_reference(bo); ++ exec->bo[i] = (struct drm_gem_cma_object *)bo; ++ } ++ spin_unlock(&file_priv->table_lock); ++ ++fail: ++ kfree(handles); ++ return 0; ++} ++ ++static int ++vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ void *temp = NULL; ++ void *bin; ++ int ret = 0; ++ uint32_t bin_offset = 0; ++ uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size, ++ 16); ++ uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size; ++ uint32_t exec_size = uniforms_offset + args->uniforms_size; ++ uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) * ++ args->shader_rec_count); ++ struct vc4_bo *bo; ++ ++ if (uniforms_offset < shader_rec_offset || ++ exec_size < uniforms_offset || ++ args->shader_rec_count >= (UINT_MAX / ++ sizeof(struct vc4_shader_state)) || ++ temp_size < exec_size) { ++ DRM_ERROR("overflow in exec arguments\n"); ++ goto fail; ++ } ++ ++ /* Allocate space where we'll store the copied in user command lists ++ * and shader records. ++ * ++ * We don't just copy directly into the BOs because we need to ++ * read the contents back for validation, and I think the ++ * bo->vaddr is uncached access. ++ */ ++ temp = kmalloc(temp_size, GFP_KERNEL); ++ if (!temp) { ++ DRM_ERROR("Failed to allocate storage for copying " ++ "in bin/render CLs.\n"); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ bin = temp + bin_offset; ++ exec->shader_rec_u = temp + shader_rec_offset; ++ exec->uniforms_u = temp + uniforms_offset; ++ exec->shader_state = temp + exec_size; ++ exec->shader_state_size = args->shader_rec_count; ++ ++ ret = copy_from_user(bin, ++ (void __user *)(uintptr_t)args->bin_cl, ++ args->bin_cl_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in bin cl\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(exec->shader_rec_u, ++ (void __user *)(uintptr_t)args->shader_rec, ++ args->shader_rec_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in shader recs\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(exec->uniforms_u, ++ (void __user *)(uintptr_t)args->uniforms, ++ args->uniforms_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in uniforms cl\n"); ++ goto fail; ++ } ++ ++ bo = vc4_bo_create(dev, exec_size, true); ++ if (!bo) { ++ DRM_ERROR("Couldn't allocate BO for binning\n"); ++ ret = PTR_ERR(exec->exec_bo); ++ goto fail; ++ } ++ exec->exec_bo = &bo->base; ++ ++ list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head, ++ &exec->unref_list); ++ ++ exec->ct0ca = exec->exec_bo->paddr + bin_offset; ++ ++ exec->bin_u = bin; ++ ++ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset; ++ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset; ++ exec->shader_rec_size = args->shader_rec_size; ++ ++ exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset; ++ exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset; ++ exec->uniforms_size = args->uniforms_size; ++ ++ ret = vc4_validate_bin_cl(dev, ++ exec->exec_bo->vaddr + bin_offset, ++ bin, ++ exec); ++ if (ret) ++ goto fail; ++ ++ ret = vc4_validate_shader_recs(dev, exec); ++ ++fail: ++ kfree(temp); ++ return ret; ++} ++ ++static void ++vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ unsigned i; ++ ++ /* Need the struct lock for drm_gem_object_unreference(). */ ++ mutex_lock(&dev->struct_mutex); ++ if (exec->bo) { ++ for (i = 0; i < exec->bo_count; i++) ++ drm_gem_object_unreference(&exec->bo[i]->base); ++ kfree(exec->bo); ++ } ++ ++ while (!list_empty(&exec->unref_list)) { ++ struct vc4_bo *bo = list_first_entry(&exec->unref_list, ++ struct vc4_bo, unref_head); ++ list_del(&bo->unref_head); ++ drm_gem_object_unreference(&bo->base.base); ++ } ++ mutex_unlock(&dev->struct_mutex); ++ ++ kfree(exec); ++} ++ ++void ++vc4_job_handle_completed(struct vc4_dev *vc4) ++{ ++ unsigned long irqflags; ++ struct vc4_seqno_cb *cb, *cb_temp; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ while (!list_empty(&vc4->job_done_list)) { ++ struct vc4_exec_info *exec = ++ list_first_entry(&vc4->job_done_list, ++ struct vc4_exec_info, head); ++ list_del(&exec->head); ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ vc4_complete_exec(vc4->dev, exec); ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ } ++ ++ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) { ++ if (cb->seqno <= vc4->finished_seqno) { ++ list_del_init(&cb->work.entry); ++ schedule_work(&cb->work); ++ } ++ } ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} ++ ++static void vc4_seqno_cb_work(struct work_struct *work) ++{ ++ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work); ++ ++ cb->func(cb); ++} ++ ++int vc4_queue_seqno_cb(struct drm_device *dev, ++ struct vc4_seqno_cb *cb, uint64_t seqno, ++ void (*func)(struct vc4_seqno_cb *cb)) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ unsigned long irqflags; ++ ++ cb->func = func; ++ INIT_WORK(&cb->work, vc4_seqno_cb_work); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ if (seqno > vc4->finished_seqno) { ++ cb->seqno = seqno; ++ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list); ++ } else { ++ schedule_work(&cb->work); ++ } ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ return ret; ++} ++ ++/* Scheduled when any job has been completed, this walks the list of ++ * jobs that had completed and unrefs their BOs and frees their exec ++ * structs. ++ */ ++static void ++vc4_job_done_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, job_done_work); ++ ++ vc4_job_handle_completed(vc4); ++} ++ ++static int ++vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev, ++ uint64_t seqno, ++ uint64_t *timeout_ns) ++{ ++ unsigned long start = jiffies; ++ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns, true); ++ ++ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) { ++ uint64_t delta = jiffies_to_nsecs(jiffies - start); ++ ++ if (*timeout_ns >= delta) ++ *timeout_ns -= delta; ++ } ++ ++ return ret; ++} ++ ++int ++vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_wait_seqno *args = data; ++ ++ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno, ++ &args->timeout_ns); ++} ++ ++int ++vc4_wait_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ int ret; ++ struct drm_vc4_wait_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ struct vc4_bo *bo; ++ ++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); ++ return -EINVAL; ++ } ++ bo = to_vc4_bo(gem_obj); ++ ++ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, ++ &args->timeout_ns); ++ ++ drm_gem_object_unreference_unlocked(gem_obj); ++ return ret; ++} ++ ++/** ++ * Submits a command list to the VC4. ++ * ++ * This is what is called batchbuffer emitting on other hardware. ++ */ ++int ++vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_vc4_submit_cl *args = data; ++ struct vc4_exec_info *exec; ++ int ret; ++ ++ if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { ++ DRM_ERROR("Unknown flags: 0x%02x\n", args->flags); ++ return -EINVAL; ++ } ++ ++ exec = kcalloc(1, sizeof(*exec), GFP_KERNEL); ++ if (!exec) { ++ DRM_ERROR("malloc failure on exec struct\n"); ++ return -ENOMEM; ++ } ++ ++ exec->args = args; ++ INIT_LIST_HEAD(&exec->unref_list); ++ ++ ret = vc4_cl_lookup_bos(dev, file_priv, exec); ++ if (ret) ++ goto fail; ++ ++ if (exec->args->bin_cl_size != 0) { ++ ret = vc4_get_bcl(dev, exec); ++ if (ret) ++ goto fail; ++ } else { ++ exec->ct0ca = 0; ++ exec->ct0ea = 0; ++ } ++ ++ ret = vc4_get_rcl(dev, exec); ++ if (ret) ++ goto fail; ++ ++ /* Clear this out of the struct we'll be putting in the queue, ++ * since it's part of our stack. ++ */ ++ exec->args = NULL; ++ ++ vc4_queue_submit(dev, exec); ++ ++ /* Return the seqno for our job. */ ++ args->seqno = vc4->emit_seqno; ++ ++ return 0; ++ ++fail: ++ vc4_complete_exec(vc4->dev, exec); ++ ++ return ret; ++} ++ ++void ++vc4_gem_init(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ INIT_LIST_HEAD(&vc4->job_list); ++ INIT_LIST_HEAD(&vc4->job_done_list); ++ INIT_LIST_HEAD(&vc4->seqno_cb_list); ++ spin_lock_init(&vc4->job_lock); ++ ++ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work); ++ setup_timer(&vc4->hangcheck.timer, ++ vc4_hangcheck_elapsed, ++ (unsigned long)dev); ++ ++ INIT_WORK(&vc4->job_done_work, vc4_job_done_work); ++} ++ ++void ++vc4_gem_destroy(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Waiting for exec to finish would need to be done before ++ * unregistering V3D. ++ */ ++ WARN_ON(vc4->emit_seqno != vc4->finished_seqno); ++ ++ /* V3D should already have disabled its interrupt and cleared ++ * the overflow allocation registers. Now free the object. ++ */ ++ if (vc4->overflow_mem) { ++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); ++ vc4->overflow_mem = NULL; ++ } ++ ++ vc4_bo_cache_destroy(dev); ++ ++ if (vc4->hang_state) ++ vc4_free_hang_state(dev, vc4->hang_state); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +new file mode 100644 +index 0000000..d15c529 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -0,0 +1,592 @@ ++/* ++ * Copyright (C) 2015 Broadcom ++ * Copyright (c) 2014 The Linux Foundation. All rights reserved. ++ * Copyright (C) 2013 Red Hat ++ * Author: Rob Clark ++ * ++ * 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 Falcon HDMI module ++ * ++ * The HDMI core has a state machine and a PHY. Most of the unit ++ * operates off of the HSM clock from CPRMAN. It also internally uses ++ * the PLLH_PIX clock for the PHY. ++ */ ++ ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_edid.h" ++#include "linux/clk.h" ++#include "linux/component.h" ++#include "linux/i2c.h" ++#include "linux/of_gpio.h" ++#include "linux/of_platform.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++/* General HDMI hardware state. */ ++struct vc4_hdmi { ++ struct platform_device *pdev; ++ ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ ++ struct i2c_adapter *ddc; ++ void __iomem *hdmicore_regs; ++ void __iomem *hd_regs; ++ int hpd_gpio; ++ ++ struct clk *pixel_clock; ++ struct clk *hsm_clock; ++}; ++ ++#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) ++#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) ++#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) ++#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) ++ ++/* VC4 HDMI encoder KMS struct */ ++struct vc4_hdmi_encoder { ++ struct vc4_encoder base; ++ bool hdmi_monitor; ++}; ++ ++static inline struct vc4_hdmi_encoder * ++to_vc4_hdmi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_hdmi_encoder, base.base); ++} ++ ++/* VC4 HDMI connector KMS struct */ ++struct vc4_hdmi_connector { ++ struct drm_connector base; ++ ++ /* 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_hdmi_connector * ++to_vc4_hdmi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_hdmi_connector, base); ++} ++ ++#define HDMI_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} hdmi_regs[] = { ++ HDMI_REG(VC4_HDMI_CORE_REV), ++ HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), ++ HDMI_REG(VC4_HDMI_HOTPLUG_INT), ++ HDMI_REG(VC4_HDMI_HOTPLUG), ++ HDMI_REG(VC4_HDMI_HORZA), ++ HDMI_REG(VC4_HDMI_HORZB), ++ HDMI_REG(VC4_HDMI_FIFO_CTL), ++ HDMI_REG(VC4_HDMI_SCHEDULER_CONTROL), ++ HDMI_REG(VC4_HDMI_VERTA0), ++ HDMI_REG(VC4_HDMI_VERTA1), ++ HDMI_REG(VC4_HDMI_VERTB0), ++ HDMI_REG(VC4_HDMI_VERTB1), ++ HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), ++}; ++ ++static const struct { ++ u32 reg; ++ const char *name; ++} hd_regs[] = { ++ HDMI_REG(VC4_HD_M_CTL), ++ HDMI_REG(VC4_HD_MAI_CTL), ++ HDMI_REG(VC4_HD_VID_CTL), ++ HDMI_REG(VC4_HD_CSC_CTL), ++ HDMI_REG(VC4_HD_FRAME_COUNT), ++}; ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_hdmi_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hdmi_regs[i].name, hdmi_regs[i].reg, ++ HDMI_READ(hdmi_regs[i].reg)); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hd_regs[i].name, hd_regs[i].reg, ++ HD_READ(hd_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++static void vc4_hdmi_dump_regs(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hdmi_regs[i].reg, hdmi_regs[i].name, ++ HDMI_READ(hdmi_regs[i].reg)); ++ } ++ for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hd_regs[i].reg, hd_regs[i].name, ++ HD_READ(hd_regs[i].reg)); ++ } ++} ++ ++static enum drm_connector_status ++vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct drm_device *dev = connector->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ return connector_status_connected; ++ ++ if (vc4->hdmi->hpd_gpio) { ++ if (gpio_get_value(vc4->hdmi->hpd_gpio)) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++ } ++ ++ if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++} ++ ++static void vc4_hdmi_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct vc4_hdmi_connector *vc4_connector = ++ to_vc4_hdmi_connector(connector); ++ struct drm_encoder *encoder = vc4_connector->encoder; ++ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); ++ struct drm_device *dev = connector->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ struct edid *edid; ++ ++ edid = drm_get_edid(connector, vc4->hdmi->ddc); ++ if (!edid) ++ return -ENODEV; ++ ++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); ++ drm_mode_connector_update_edid_property(connector, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ ++ return ret; ++} ++ ++static struct drm_encoder * ++vc4_hdmi_connector_best_encoder(struct drm_connector *connector) ++{ ++ struct vc4_hdmi_connector *hdmi_connector = ++ to_vc4_hdmi_connector(connector); ++ return hdmi_connector->encoder; ++} ++ ++static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_hdmi_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = vc4_hdmi_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_hdmi_connector_helper_funcs = { ++ .get_modes = vc4_hdmi_connector_get_modes, ++ .best_encoder = vc4_hdmi_connector_best_encoder, ++}; ++ ++static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, ++ struct drm_encoder *encoder) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_hdmi_connector *hdmi_connector; ++ int ret = 0; ++ ++ hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), ++ GFP_KERNEL); ++ if (!hdmi_connector) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ connector = &hdmi_connector->base; ++ ++ hdmi_connector->encoder = encoder; ++ ++ drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA); ++ drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); ++ ++ connector->polled = (DRM_CONNECTOR_POLL_CONNECT | ++ DRM_CONNECTOR_POLL_DISCONNECT); ++ ++ connector->interlace_allowed = 0; ++ connector->doublescan_allowed = 0; ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ ++ return connector; ++ ++ fail: ++ if (connector) ++ vc4_hdmi_connector_destroy(connector); ++ ++ return ERR_PTR(ret); ++} ++ ++static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++} ++ ++static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { ++ .destroy = vc4_hdmi_encoder_destroy, ++}; ++ ++static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *unadjusted_mode, ++ struct drm_display_mode *mode) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ bool debug_dump_regs = false; ++ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; ++ bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; ++ u32 vactive = (mode->vdisplay >> ++ ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); ++ u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, ++ VC4_HDMI_VERTA_VSP) | ++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, ++ VC4_HDMI_VERTA_VFP) | ++ VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); ++ u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end, ++ VC4_HDMI_VERTB_VBP)); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("HDMI regs before:\n"); ++ vc4_hdmi_dump_regs(dev); ++ } ++ ++ HD_WRITE(VC4_HD_VID_CTL, 0); ++ ++ clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000); ++ ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | ++ VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); ++ ++ HDMI_WRITE(VC4_HDMI_HORZA, ++ (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | ++ (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | ++ VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP)); ++ ++ HDMI_WRITE(VC4_HDMI_HORZB, ++ VC4_SET_FIELD(mode->htotal - mode->hsync_end, ++ VC4_HDMI_HORZB_HBP) | ++ VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, ++ VC4_HDMI_HORZB_HSP) | ++ VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, ++ VC4_HDMI_HORZB_HFP)); ++ ++ HDMI_WRITE(VC4_HDMI_VERTA0, verta); ++ HDMI_WRITE(VC4_HDMI_VERTA1, verta); ++ ++ HDMI_WRITE(VC4_HDMI_VERTB0, vertb); ++ HDMI_WRITE(VC4_HDMI_VERTB1, vertb); ++ ++ HD_WRITE(VC4_HD_VID_CTL, ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ ++ /* The RGB order applies even when CSC is disabled. */ ++ HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, ++ VC4_HD_CSC_CTL_ORDER)); ++ ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("HDMI regs after:\n"); ++ vc4_hdmi_dump_regs(dev); ++ } ++} ++ ++static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ HD_WRITE(VC4_HD_VID_CTL, ++ HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); ++} ++ ++static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ ++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); ++ ++ HD_WRITE(VC4_HD_VID_CTL, ++ HD_READ(VC4_HD_VID_CTL) | ++ VC4_HD_VID_CTL_ENABLE | ++ VC4_HD_VID_CTL_UNDERFLOW_ENABLE | ++ VC4_HD_VID_CTL_FRAME_COUNTER_RESET); ++ ++ if (vc4_encoder->hdmi_monitor) { ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ++ ++ ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); ++ } else { ++ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, ++ HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ ~(VC4_HDMI_RAM_PACKET_ENABLE)); ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ++ ++ ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); ++ } ++ ++ if (vc4_encoder->hdmi_monitor) { ++ u32 drift; ++ ++ WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); ++ ++ /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set ++ * up the infoframe. ++ */ ++ ++ drift = HDMI_READ(VC4_HDMI_FIFO_CTL); ++ drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; ++ ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift & ~VC4_HDMI_FIFO_CTL_RECENTER); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift | VC4_HDMI_FIFO_CTL_RECENTER); ++ udelay(1000); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift & ~VC4_HDMI_FIFO_CTL_RECENTER); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift | VC4_HDMI_FIFO_CTL_RECENTER); ++ ++ ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) & ++ VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); ++ } ++} ++ ++static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { ++ .mode_set = vc4_hdmi_encoder_mode_set, ++ .disable = vc4_hdmi_encoder_disable, ++ .enable = vc4_hdmi_encoder_enable, ++}; ++ ++static int vc4_hdmi_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 = drm->dev_private; ++ struct vc4_hdmi *hdmi; ++ struct vc4_hdmi_encoder *vc4_hdmi_encoder; ++ struct device_node *ddc_node; ++ u32 value; ++ int ret; ++ ++ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); ++ if (!hdmi) ++ return -ENOMEM; ++ ++ vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder), ++ GFP_KERNEL); ++ if (!vc4_hdmi_encoder) ++ return -ENOMEM; ++ vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI; ++ hdmi->encoder = &vc4_hdmi_encoder->base.base; ++ ++ hdmi->pdev = pdev; ++ hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(hdmi->hdmicore_regs)) ++ return PTR_ERR(hdmi->hdmicore_regs); ++ ++ hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); ++ if (IS_ERR(hdmi->hd_regs)) ++ return PTR_ERR(hdmi->hd_regs); ++ ++ ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); ++ if (!ddc_node) { ++ DRM_ERROR("Failed to find ddc node in device tree\n"); ++ return -ENODEV; ++ } ++ ++ hdmi->pixel_clock = devm_clk_get(dev, "pixel"); ++ if (IS_ERR(hdmi->pixel_clock)) { ++ DRM_ERROR("Failed to get pixel clock\n"); ++ return PTR_ERR(hdmi->pixel_clock); ++ } ++ hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); ++ if (IS_ERR(hdmi->hsm_clock)) { ++ DRM_ERROR("Failed to get HDMI state machine clock\n"); ++ return PTR_ERR(hdmi->hsm_clock); ++ } ++ ++ hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); ++ if (!hdmi->ddc) { ++ DRM_DEBUG("Failed to get ddc i2c adapter by node\n"); ++ return -EPROBE_DEFER; ++ } ++ ++ /* Enable the clocks at startup. We can't quite recover from ++ * turning off the pixel clock during disable/enables yet, so ++ * it's always running. ++ */ ++ ret = clk_prepare_enable(hdmi->pixel_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); ++ goto err_put_i2c; ++ } ++ ++ ret = clk_prepare_enable(hdmi->hsm_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", ++ ret); ++ goto err_unprepare_pix; ++ } ++ ++ /* Only use the GPIO HPD pin if present in the DT, otherwise ++ * we'll use the HDMI core's register. ++ */ ++ if (of_find_property(dev->of_node, "hpd-gpios", &value)) { ++ hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0); ++ if (hdmi->hpd_gpio < 0) { ++ ret = hdmi->hpd_gpio; ++ goto err_unprepare_hsm; ++ } ++ } ++ ++ vc4->hdmi = hdmi; ++ ++ /* HDMI core must be enabled. */ ++ WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0); ++ ++ drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, ++ DRM_MODE_ENCODER_TMDS); ++ drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs); ++ ++ hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder); ++ if (IS_ERR(hdmi->connector)) { ++ ret = PTR_ERR(hdmi->connector); ++ goto err_destroy_encoder; ++ } ++ ++ return 0; ++ ++err_destroy_encoder: ++ vc4_hdmi_encoder_destroy(hdmi->encoder); ++err_unprepare_hsm: ++ clk_disable_unprepare(hdmi->hsm_clock); ++err_unprepare_pix: ++ clk_disable_unprepare(hdmi->pixel_clock); ++err_put_i2c: ++ put_device(&vc4->hdmi->ddc->dev); ++ ++ return ret; ++} ++ ++static void vc4_hdmi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = drm->dev_private; ++ struct vc4_hdmi *hdmi = vc4->hdmi; ++ ++ vc4_hdmi_connector_destroy(hdmi->connector); ++ vc4_hdmi_encoder_destroy(hdmi->encoder); ++ ++ clk_disable_unprepare(hdmi->pixel_clock); ++ clk_disable_unprepare(hdmi->hsm_clock); ++ put_device(&hdmi->ddc->dev); ++ ++ vc4->hdmi = NULL; ++} ++ ++static const struct component_ops vc4_hdmi_ops = { ++ .bind = vc4_hdmi_bind, ++ .unbind = vc4_hdmi_unbind, ++}; ++ ++static int vc4_hdmi_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_hdmi_ops); ++} ++ ++static int vc4_hdmi_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_hdmi_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_hdmi_dt_match[] = { ++ { .compatible = "brcm,bcm2835-hdmi" }, ++ {} ++}; ++ ++struct platform_driver vc4_hdmi_driver = { ++ .probe = vc4_hdmi_dev_probe, ++ .remove = vc4_hdmi_dev_remove, ++ .driver = { ++ .name = "vc4_hdmi", ++ .of_match_table = vc4_hdmi_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c +new file mode 100644 +index 0000000..8098c5b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 HVS module. ++ * ++ * The HVS is the piece of hardware that does translation, scaling, ++ * colorspace conversion, and compositing of pixels stored in ++ * framebuffers into a FIFO of pixels going out to the Pixel Valve ++ * (CRTC). It operates at the system clock rate (the system audio ++ * clock gate, specifically), which is much higher than the pixel ++ * clock rate. ++ * ++ * There is a single global HVS, with multiple output FIFOs that can ++ * be consumed by the PVs. This file just manages the resources for ++ * the HVS, while the vc4_crtc.c code actually drives HVS setup for ++ * each CRTC. ++ */ ++ ++#include "linux/component.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define HVS_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} hvs_regs[] = { ++ HVS_REG(SCALER_DISPCTRL), ++ HVS_REG(SCALER_DISPSTAT), ++ HVS_REG(SCALER_DISPID), ++ HVS_REG(SCALER_DISPECTRL), ++ HVS_REG(SCALER_DISPPROF), ++ HVS_REG(SCALER_DISPDITHER), ++ HVS_REG(SCALER_DISPEOLN), ++ HVS_REG(SCALER_DISPLIST0), ++ HVS_REG(SCALER_DISPLIST1), ++ HVS_REG(SCALER_DISPLIST2), ++ HVS_REG(SCALER_DISPLSTAT), ++ HVS_REG(SCALER_DISPLACT0), ++ HVS_REG(SCALER_DISPLACT1), ++ HVS_REG(SCALER_DISPLACT2), ++ HVS_REG(SCALER_DISPCTRL0), ++ HVS_REG(SCALER_DISPBKGND0), ++ HVS_REG(SCALER_DISPSTAT0), ++ HVS_REG(SCALER_DISPBASE0), ++ HVS_REG(SCALER_DISPCTRL1), ++ HVS_REG(SCALER_DISPBKGND1), ++ HVS_REG(SCALER_DISPSTAT1), ++ HVS_REG(SCALER_DISPBASE1), ++ HVS_REG(SCALER_DISPCTRL2), ++ HVS_REG(SCALER_DISPBKGND2), ++ HVS_REG(SCALER_DISPSTAT2), ++ HVS_REG(SCALER_DISPBASE2), ++ HVS_REG(SCALER_DISPALPHA2), ++}; ++ ++void vc4_hvs_dump_state(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hvs_regs[i].reg, hvs_regs[i].name, ++ HVS_READ(hvs_regs[i].reg)); ++ } ++ ++ DRM_INFO("HVS ctx:\n"); ++ for (i = 0; i < 64; i += 4) { ++ DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 0), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 1), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 2), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 3)); ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_hvs_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hvs_regs[i].name, hvs_regs[i].reg, ++ HVS_READ(hvs_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static int vc4_hvs_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 = drm->dev_private; ++ struct vc4_hvs *hvs = NULL; ++ ++ hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); ++ if (!hvs) ++ return -ENOMEM; ++ ++ hvs->pdev = pdev; ++ ++ hvs->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(hvs->regs)) ++ return PTR_ERR(hvs->regs); ++ ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; ++ ++ vc4->hvs = hvs; ++ return 0; ++} ++ ++static void vc4_hvs_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = drm->dev_private; ++ ++ vc4->hvs = NULL; ++} ++ ++static const struct component_ops vc4_hvs_ops = { ++ .bind = vc4_hvs_bind, ++ .unbind = vc4_hvs_unbind, ++}; ++ ++static int vc4_hvs_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_hvs_ops); ++} ++ ++static int vc4_hvs_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_hvs_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_hvs_dt_match[] = { ++ { .compatible = "brcm,bcm2835-hvs" }, ++ {} ++}; ++ ++struct platform_driver vc4_hvs_driver = { ++ .probe = vc4_hvs_dev_probe, ++ .remove = vc4_hvs_dev_remove, ++ .driver = { ++ .name = "vc4_hvs", ++ .of_match_table = vc4_hvs_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +new file mode 100644 +index 0000000..b68060e +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -0,0 +1,210 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Interrupt management for the V3D engine. ++ * ++ * We have an interrupt status register (V3D_INTCTL) which reports ++ * interrupts, and where writing 1 bits clears those interrupts. ++ * There are also a pair of interrupt registers ++ * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or ++ * disables that specific interrupt, and 0s written are ignored ++ * (reading either one returns the set of enabled interrupts). ++ * ++ * When we take a render frame interrupt, we need to wake the ++ * processes waiting for some frame to be done, and get the next frame ++ * submitted ASAP (so the hardware doesn't sit idle when there's work ++ * to do). ++ * ++ * When we take the binner out of memory interrupt, we need to ++ * allocate some new memory and pass it to the binner so that the ++ * current job can make progress. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \ ++ V3D_INT_FRDONE) ++ ++DECLARE_WAIT_QUEUE_HEAD(render_wait); ++ ++static void ++vc4_overflow_mem_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, overflow_mem_work); ++ struct drm_device *dev = vc4->dev; ++ struct vc4_bo *bo; ++ ++ bo = vc4_bo_create(dev, 256 * 1024, true); ++ if (!bo) { ++ DRM_ERROR("Couldn't allocate binner overflow mem\n"); ++ return; ++ } ++ ++ /* If there's a job executing currently, then our previous ++ * overflow allocation is getting used in that job and we need ++ * to queue it to be released when the job is done. But if no ++ * job is executing at all, then we can free the old overflow ++ * object direcctly. ++ * ++ * No lock necessary for this pointer since we're the only ++ * ones that update the pointer, and our workqueue won't ++ * reenter. ++ */ ++ if (vc4->overflow_mem) { ++ struct vc4_exec_info *current_exec; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ current_exec = vc4_first_job(vc4); ++ if (current_exec) { ++ vc4->overflow_mem->seqno = vc4->finished_seqno + 1; ++ list_add_tail(&vc4->overflow_mem->unref_head, ++ ¤t_exec->unref_list); ++ vc4->overflow_mem = NULL; ++ } ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ } ++ ++ if (vc4->overflow_mem) ++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); ++ vc4->overflow_mem = bo; ++ ++ V3D_WRITE(V3D_BPOA, bo->base.paddr); ++ V3D_WRITE(V3D_BPOS, bo->base.base.size); ++ V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); ++ V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); ++} ++ ++static void ++vc4_irq_finish_job(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_exec_info *exec = vc4_first_job(vc4); ++ ++ if (!exec) ++ return; ++ ++ vc4->finished_seqno++; ++ list_move_tail(&exec->head, &vc4->job_done_list); ++ vc4_submit_next_job(dev); ++ ++ wake_up_all(&vc4->job_wait_queue); ++ schedule_work(&vc4->job_done_work); ++} ++ ++irqreturn_t ++vc4_irq(int irq, void *arg) ++{ ++ struct drm_device *dev = arg; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t intctl; ++ irqreturn_t status = IRQ_NONE; ++ ++ barrier(); ++ intctl = V3D_READ(V3D_INTCTL); ++ ++ /* Acknowledge the interrupts we're handling here. The render ++ * frame done interrupt will be cleared, while OUTOMEM will ++ * stay high until the underlying cause is cleared. ++ */ ++ V3D_WRITE(V3D_INTCTL, intctl); ++ ++ if (intctl & V3D_INT_OUTOMEM) { ++ /* Disable OUTOMEM until the work is done. */ ++ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM); ++ schedule_work(&vc4->overflow_mem_work); ++ status = IRQ_HANDLED; ++ } ++ ++ if (intctl & V3D_INT_FRDONE) { ++ spin_lock(&vc4->job_lock); ++ vc4_irq_finish_job(dev); ++ spin_unlock(&vc4->job_lock); ++ status = IRQ_HANDLED; ++ } ++ ++ return status; ++} ++ ++void ++vc4_irq_preinstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ init_waitqueue_head(&vc4->job_wait_queue); ++ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work); ++ ++ /* Clear any pending interrupts someone might have left around ++ * for us. ++ */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++} ++ ++int ++vc4_irq_postinstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Enable both the render done and out of memory interrupts. */ ++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); ++ ++ return 0; ++} ++ ++void ++vc4_irq_uninstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Disable sending interrupts for our driver's IRQs. */ ++ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS); ++ ++ /* Clear any pending interrupts we might have left. */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++ ++ cancel_work_sync(&vc4->overflow_mem_work); ++} ++ ++/** Reinitializes interrupt registers when a GPU reset is performed. */ ++void vc4_irq_reset(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; ++ ++ /* Acknowledge any stale IRQs. */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++ ++ /* ++ * Turn all our interrupts on. Binner out of memory is the ++ * only one we expect to trigger at this point, since we've ++ * just come from poweron and haven't supplied any overflow ++ * memory yet. ++ */ ++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ vc4_irq_finish_job(dev); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c +new file mode 100644 +index 0000000..918c9da +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -0,0 +1,214 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 KMS ++ * ++ * This is the general code for implementing KMS mode setting that ++ * doesn't clearly associate with any of the other objects (plane, ++ * crtc, HDMI encoder). ++ */ ++ ++#include "drm_crtc.h" ++#include "drm_atomic.h" ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_plane_helper.h" ++#include "drm_fb_cma_helper.h" ++#include "vc4_drv.h" ++ ++static void vc4_output_poll_changed(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_hotplug_event(vc4->fbdev); ++} ++ ++struct vc4_commit { ++ struct drm_device *dev; ++ struct drm_atomic_state *state; ++ struct vc4_seqno_cb cb; ++}; ++ ++static void ++vc4_atomic_complete_commit(struct vc4_commit *c) ++{ ++ struct drm_atomic_state *state = c->state; ++ struct drm_device *dev = state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ drm_atomic_helper_commit_modeset_disables(dev, state); ++ ++ drm_atomic_helper_commit_planes(dev, state); ++ ++ drm_atomic_helper_commit_modeset_enables(dev, state); ++ ++ drm_atomic_helper_wait_for_vblanks(dev, state); ++ ++ drm_atomic_helper_cleanup_planes(dev, state); ++ ++ drm_atomic_state_free(state); ++ ++ up(&vc4->async_modeset); ++ ++ kfree(c); ++} ++ ++static void ++vc4_atomic_complete_commit_seqno_cb(struct vc4_seqno_cb *cb) ++{ ++ struct vc4_commit *c = container_of(cb, struct vc4_commit, cb); ++ ++ vc4_atomic_complete_commit(c); ++} ++ ++static struct vc4_commit *commit_init(struct drm_atomic_state *state) ++{ ++ struct vc4_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); ++ ++ if (!c) ++ return NULL; ++ c->dev = state->dev; ++ c->state = state; ++ ++ return c; ++} ++ ++/** ++ * vc4_atomic_commit - commit validated state object ++ * @dev: DRM device ++ * @state: the driver state object ++ * @async: asynchronous commit ++ * ++ * This function commits a with drm_atomic_helper_check() pre-validated state ++ * object. This can still fail when e.g. the framebuffer reservation fails. For ++ * now this doesn't implement asynchronous commits. ++ * ++ * RETURNS ++ * Zero for success or -errno. ++ */ ++static int vc4_atomic_commit(struct drm_device *dev, ++ struct drm_atomic_state *state, ++ bool async) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ int i; ++ uint64_t wait_seqno = 0; ++ struct vc4_commit *c; ++ ++ c = commit_init(state); ++ if (!c) ++ return -ENOMEM; ++ ++ /* Make sure that any outstanding modesets have finished. */ ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(c); ++ return ret; ++ } ++ ++ ret = drm_atomic_helper_prepare_planes(dev, state); ++ if (ret) { ++ kfree(c); ++ up(&vc4->async_modeset); ++ return ret; ++ } ++ ++ for (i = 0; i < dev->mode_config.num_total_plane; i++) { ++ struct drm_plane *plane = state->planes[i]; ++ struct drm_plane_state *new_state = state->plane_states[i]; ++ ++ if (!plane) ++ continue; ++ ++ if ((plane->state->fb != new_state->fb) && new_state->fb) { ++ struct drm_gem_cma_object *cma_bo = ++ drm_fb_cma_get_gem_obj(new_state->fb, 0); ++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); ++ ++ wait_seqno = max(bo->seqno, wait_seqno); ++ } ++ } ++ ++ /* ++ * This is the point of no return - everything below never fails except ++ * when the hw goes bonghits. Which means we can commit the new state on ++ * the software side now. ++ */ ++ ++ drm_atomic_helper_swap_state(dev, state); ++ ++ /* ++ * Everything below can be run asynchronously without the need to grab ++ * any modeset locks at all under one condition: It must be guaranteed ++ * that the asynchronous work has either been cancelled (if the driver ++ * supports it, which at least requires that the framebuffers get ++ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed ++ * before the new state gets committed on the software side with ++ * drm_atomic_helper_swap_state(). ++ * ++ * This scheme allows new atomic state updates to be prepared and ++ * checked in parallel to the asynchronous completion of the previous ++ * update. Which is important since compositors need to figure out the ++ * composition of the next frame right after having submitted the ++ * current layout. ++ */ ++ ++ if (async) { ++ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno, ++ vc4_atomic_complete_commit_seqno_cb); ++ } else { ++ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false); ++ vc4_atomic_complete_commit(c); ++ } ++ ++ return 0; ++} ++ ++static const struct drm_mode_config_funcs vc4_mode_funcs = { ++ .output_poll_changed = vc4_output_poll_changed, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = vc4_atomic_commit, ++ .fb_create = drm_fb_cma_create, ++}; ++ ++int vc4_kms_load(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ ++ sema_init(&vc4->async_modeset, 1); ++ ++ ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ++ if (ret < 0) { ++ dev_err(dev->dev, "failed to initialize vblank\n"); ++ return ret; ++ } ++ ++ dev->mode_config.max_width = 2048; ++ dev->mode_config.max_height = 2048; ++ dev->mode_config.funcs = &vc4_mode_funcs; ++ dev->mode_config.preferred_depth = 24; ++ dev->mode_config.async_page_flip = true; ++ ++ dev->vblank_disable_allowed = true; ++ ++ drm_mode_config_reset(dev); ++ ++ vc4->fbdev = drm_fbdev_cma_init(dev, 32, ++ dev->mode_config.num_crtc, ++ dev->mode_config.num_connector); ++ if (IS_ERR(vc4->fbdev)) ++ vc4->fbdev = NULL; ++ ++ drm_kms_helper_poll_init(dev); ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/vc4/vc4_packet.h b/drivers/gpu/drm/vc4/vc4_packet.h +new file mode 100644 +index 0000000..0f31cc0 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_packet.h +@@ -0,0 +1,399 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef VC4_PACKET_H ++#define VC4_PACKET_H ++ ++#include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */ ++ ++enum vc4_packet { ++ VC4_PACKET_HALT = 0, ++ VC4_PACKET_NOP = 1, ++ ++ VC4_PACKET_FLUSH = 4, ++ VC4_PACKET_FLUSH_ALL = 5, ++ VC4_PACKET_START_TILE_BINNING = 6, ++ VC4_PACKET_INCREMENT_SEMAPHORE = 7, ++ VC4_PACKET_WAIT_ON_SEMAPHORE = 8, ++ ++ VC4_PACKET_BRANCH = 16, ++ VC4_PACKET_BRANCH_TO_SUB_LIST = 17, ++ ++ VC4_PACKET_STORE_MS_TILE_BUFFER = 24, ++ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25, ++ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26, ++ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27, ++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28, ++ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29, ++ ++ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32, ++ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33, ++ ++ VC4_PACKET_COMPRESSED_PRIMITIVE = 48, ++ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49, ++ ++ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56, ++ ++ VC4_PACKET_GL_SHADER_STATE = 64, ++ VC4_PACKET_NV_SHADER_STATE = 65, ++ VC4_PACKET_VG_SHADER_STATE = 66, ++ ++ VC4_PACKET_CONFIGURATION_BITS = 96, ++ VC4_PACKET_FLAT_SHADE_FLAGS = 97, ++ VC4_PACKET_POINT_SIZE = 98, ++ VC4_PACKET_LINE_WIDTH = 99, ++ VC4_PACKET_RHT_X_BOUNDARY = 100, ++ VC4_PACKET_DEPTH_OFFSET = 101, ++ VC4_PACKET_CLIP_WINDOW = 102, ++ VC4_PACKET_VIEWPORT_OFFSET = 103, ++ VC4_PACKET_Z_CLIPPING = 104, ++ VC4_PACKET_CLIPPER_XY_SCALING = 105, ++ VC4_PACKET_CLIPPER_Z_SCALING = 106, ++ ++ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112, ++ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113, ++ VC4_PACKET_CLEAR_COLORS = 114, ++ VC4_PACKET_TILE_COORDINATES = 115, ++ ++ /* Not an actual hardware packet -- this is what we use to put ++ * references to GEM bos in the command stream, since we need the u32 ++ * int the actual address packet in order to store the offset from the ++ * start of the BO. ++ */ ++ VC4_PACKET_GEM_HANDLES = 254, ++} __attribute__ ((__packed__)); ++ ++#define VC4_PACKET_HALT_SIZE 1 ++#define VC4_PACKET_NOP_SIZE 1 ++#define VC4_PACKET_FLUSH_SIZE 1 ++#define VC4_PACKET_FLUSH_ALL_SIZE 1 ++#define VC4_PACKET_START_TILE_BINNING_SIZE 1 ++#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1 ++#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1 ++#define VC4_PACKET_BRANCH_SIZE 5 ++#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5 ++#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1 ++#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1 ++#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5 ++#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5 ++#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7 ++#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7 ++#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14 ++#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10 ++#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1 ++#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1 ++#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2 ++#define VC4_PACKET_GL_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_NV_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_VG_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4 ++#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5 ++#define VC4_PACKET_POINT_SIZE_SIZE 5 ++#define VC4_PACKET_LINE_WIDTH_SIZE 5 ++#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3 ++#define VC4_PACKET_DEPTH_OFFSET_SIZE 5 ++#define VC4_PACKET_CLIP_WINDOW_SIZE 9 ++#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5 ++#define VC4_PACKET_Z_CLIPPING_SIZE 9 ++#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9 ++#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9 ++#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16 ++#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11 ++#define VC4_PACKET_CLEAR_COLORS_SIZE 14 ++#define VC4_PACKET_TILE_COORDINATES_SIZE 3 ++#define VC4_PACKET_GEM_HANDLES_SIZE 9 ++ ++/* Number of multisamples supported. */ ++#define VC4_MAX_SAMPLES 4 ++/* Size of a full resolution color or Z tile buffer load/store. */ ++#define VC4_TILE_BUFFER_SIZE (64 * 64 * 4) ++ ++/** @{ ++ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG. ++*/ ++#define VC4_TILING_FORMAT_LINEAR 0 ++#define VC4_TILING_FORMAT_T 1 ++#define VC4_TILING_FORMAT_LT 2 ++/** @} */ ++ ++/** @{ ++ * ++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and ++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER. ++ */ ++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0) ++ ++/** @{ ++ * ++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and ++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER. ++ */ ++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0) ++ ++/** @{ ++ * ++ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address) ++ */ ++ ++#define VC4_LOADSTORE_TILE_BUFFER_EOF BIT(3) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK BIT(2) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS BIT(1) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR BIT(0) ++ ++/** @} */ ++ ++/** @{ ++ * ++ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL ++ */ ++#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR BIT(15) ++#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR BIT(14) ++#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR BIT(13) ++#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP BIT(12) ++ ++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8) ++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8 ++#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0 ++#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1 ++#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2 ++/** @} */ ++ ++/** @{ ++ * ++ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL ++ */ ++#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6) ++#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6 ++#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6) ++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6) ++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6) ++ ++/** The values of the field are VC4_TILING_FORMAT_* */ ++#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4) ++#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4 ++ ++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0) ++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0 ++#define VC4_LOADSTORE_TILE_BUFFER_NONE 0 ++#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1 ++#define VC4_LOADSTORE_TILE_BUFFER_ZS 2 ++#define VC4_LOADSTORE_TILE_BUFFER_Z 3 ++#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4 ++#define VC4_LOADSTORE_TILE_BUFFER_FULL 5 ++/** @} */ ++ ++#define VC4_INDEX_BUFFER_U8 (0 << 4) ++#define VC4_INDEX_BUFFER_U16 (1 << 4) ++ ++/* This flag is only present in NV shader state. */ ++#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS BIT(3) ++#define VC4_SHADER_FLAG_ENABLE_CLIPPING BIT(2) ++#define VC4_SHADER_FLAG_VS_POINT_SIZE BIT(1) ++#define VC4_SHADER_FLAG_FS_SINGLE_THREAD BIT(0) ++ ++/** @{ byte 2 of config bits. */ ++#define VC4_CONFIG_BITS_EARLY_Z_UPDATE BIT(1) ++#define VC4_CONFIG_BITS_EARLY_Z BIT(0) ++/** @} */ ++ ++/** @{ byte 1 of config bits. */ ++#define VC4_CONFIG_BITS_Z_UPDATE BIT(7) ++/** same values in this 3-bit field as PIPE_FUNC_* */ ++#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4 ++#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE BIT(3) ++ ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1) ++ ++#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT BIT(0) ++/** @} */ ++ ++/** @{ byte 0 of config bits. */ ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6) ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6) ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6) ++ ++#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES BIT(4) ++#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET BIT(3) ++#define VC4_CONFIG_BITS_CW_PRIMITIVES BIT(2) ++#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK BIT(1) ++#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT BIT(0) ++/** @} */ ++ ++/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */ ++#define VC4_BIN_CONFIG_DB_NON_MS BIT(7) ++ ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5) ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3 ++ ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3) ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3 ++ ++#define VC4_BIN_CONFIG_AUTO_INIT_TSDA BIT(2) ++#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT BIT(1) ++#define VC4_BIN_CONFIG_MS_MODE_4X BIT(0) ++/** @} */ ++ ++/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */ ++#define VC4_RENDER_CONFIG_DB_NON_MS BIT(12) ++#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE BIT(11) ++#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G BIT(10) ++#define VC4_RENDER_CONFIG_COVERAGE_MODE BIT(9) ++#define VC4_RENDER_CONFIG_ENABLE_VG_MASK BIT(8) ++ ++/** The values of the field are VC4_TILING_FORMAT_* */ ++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6) ++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6 ++ ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4) ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4) ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4) ++ ++#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2) ++#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2 ++#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0 ++#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1 ++#define VC4_RENDER_CONFIG_FORMAT_BGR565 2 ++ ++#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT BIT(1) ++#define VC4_RENDER_CONFIG_MS_MODE_4X BIT(0) ++ ++#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4) ++#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0) ++ ++enum vc4_texture_data_type { ++ VC4_TEXTURE_TYPE_RGBA8888 = 0, ++ VC4_TEXTURE_TYPE_RGBX8888 = 1, ++ VC4_TEXTURE_TYPE_RGBA4444 = 2, ++ VC4_TEXTURE_TYPE_RGBA5551 = 3, ++ VC4_TEXTURE_TYPE_RGB565 = 4, ++ VC4_TEXTURE_TYPE_LUMINANCE = 5, ++ VC4_TEXTURE_TYPE_ALPHA = 6, ++ VC4_TEXTURE_TYPE_LUMALPHA = 7, ++ VC4_TEXTURE_TYPE_ETC1 = 8, ++ VC4_TEXTURE_TYPE_S16F = 9, ++ VC4_TEXTURE_TYPE_S8 = 10, ++ VC4_TEXTURE_TYPE_S16 = 11, ++ VC4_TEXTURE_TYPE_BW1 = 12, ++ VC4_TEXTURE_TYPE_A4 = 13, ++ VC4_TEXTURE_TYPE_A1 = 14, ++ VC4_TEXTURE_TYPE_RGBA64 = 15, ++ VC4_TEXTURE_TYPE_RGBA32R = 16, ++ VC4_TEXTURE_TYPE_YUV422R = 17, ++}; ++ ++#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12) ++#define VC4_TEX_P0_OFFSET_SHIFT 12 ++#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10) ++#define VC4_TEX_P0_CSWIZ_SHIFT 10 ++#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9) ++#define VC4_TEX_P0_CMMODE_SHIFT 9 ++#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8) ++#define VC4_TEX_P0_FLIPY_SHIFT 8 ++#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4) ++#define VC4_TEX_P0_TYPE_SHIFT 4 ++#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0) ++#define VC4_TEX_P0_MIPLVLS_SHIFT 0 ++ ++#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31) ++#define VC4_TEX_P1_TYPE4_SHIFT 31 ++#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20) ++#define VC4_TEX_P1_HEIGHT_SHIFT 20 ++#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19) ++#define VC4_TEX_P1_ETCFLIP_SHIFT 19 ++#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8) ++#define VC4_TEX_P1_WIDTH_SHIFT 8 ++ ++#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7) ++#define VC4_TEX_P1_MAGFILT_SHIFT 7 ++# define VC4_TEX_P1_MAGFILT_LINEAR 0 ++# define VC4_TEX_P1_MAGFILT_NEAREST 1 ++ ++#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4) ++#define VC4_TEX_P1_MINFILT_SHIFT 4 ++# define VC4_TEX_P1_MINFILT_LINEAR 0 ++# define VC4_TEX_P1_MINFILT_NEAREST 1 ++# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2 ++# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3 ++# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4 ++# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5 ++ ++#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2) ++#define VC4_TEX_P1_WRAP_T_SHIFT 2 ++#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0) ++#define VC4_TEX_P1_WRAP_S_SHIFT 0 ++# define VC4_TEX_P1_WRAP_REPEAT 0 ++# define VC4_TEX_P1_WRAP_CLAMP 1 ++# define VC4_TEX_P1_WRAP_MIRROR 2 ++# define VC4_TEX_P1_WRAP_BORDER 3 ++ ++#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30) ++#define VC4_TEX_P2_PTYPE_SHIFT 30 ++# define VC4_TEX_P2_PTYPE_IGNORED 0 ++# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1 ++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2 ++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3 ++ ++/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */ ++#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12) ++#define VC4_TEX_P2_CMST_SHIFT 12 ++#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0) ++#define VC4_TEX_P2_BSLOD_SHIFT 0 ++ ++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */ ++#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12) ++#define VC4_TEX_P2_CHEIGHT_SHIFT 12 ++#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0) ++#define VC4_TEX_P2_CWIDTH_SHIFT 0 ++ ++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */ ++#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12) ++#define VC4_TEX_P2_CYOFF_SHIFT 12 ++#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0) ++#define VC4_TEX_P2_CXOFF_SHIFT 0 ++ ++#endif /* VC4_PACKET_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c +new file mode 100644 +index 0000000..0f85eb5 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 plane module ++ * ++ * Each DRM plane is a layer of pixels being scanned out by the HVS. ++ * ++ * At atomic modeset check time, we compute the HVS display element ++ * state that would be necessary for displaying the plane (giving us a ++ * chance to figure out if a plane configuration is invalid), then at ++ * atomic flush time the CRTC will ask us to write our element state ++ * into the region of the HVS that it has allocated for us. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++#include "drm_atomic_helper.h" ++#include "drm_fb_cma_helper.h" ++#include "drm_plane_helper.h" ++ ++struct vc4_plane_state { ++ struct drm_plane_state base; ++ u32 *dlist; ++ u32 dlist_size; /* Number of dwords in allocated for the display list */ ++ u32 dlist_count; /* Number of used dwords in the display list. */ ++ ++ /* Offset in the dlist to pointer word 0. */ ++ u32 pw0_offset; ++ ++ /* Offset where the plane's dlist was last stored in the ++ hardware at vc4_crtc_atomic_flush() time. ++ */ ++ u32 *hw_dlist; ++}; ++ ++static inline struct vc4_plane_state * ++to_vc4_plane_state(struct drm_plane_state *state) ++{ ++ return (struct vc4_plane_state *)state; ++} ++ ++static const struct hvs_format { ++ u32 drm; /* DRM_FORMAT_* */ ++ u32 hvs; /* HVS_FORMAT_* */ ++ u32 pixel_order; ++ bool has_alpha; ++} hvs_formats[] = { ++ { ++ .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, ++ }, ++ { ++ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, ++ }, ++ { ++ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, ++ }, ++}; ++ ++static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) ++{ ++ unsigned i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { ++ if (hvs_formats[i].drm == drm_format) ++ return &hvs_formats[i]; ++ } ++ ++ return NULL; ++} ++ ++static bool plane_enabled(struct drm_plane_state *state) ++{ ++ return state->fb && state->crtc; ++} ++ ++static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ if (WARN_ON(!plane->state)) ++ return NULL; ++ ++ vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return NULL; ++ ++ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); ++ ++ if (vc4_state->dlist) { ++ vc4_state->dlist = kmemdup(vc4_state->dlist, ++ vc4_state->dlist_count * 4, ++ GFP_KERNEL); ++ if (!vc4_state->dlist) { ++ kfree(vc4_state); ++ return NULL; ++ } ++ vc4_state->dlist_size = vc4_state->dlist_count; ++ } ++ ++ return &vc4_state->base; ++} ++ ++static void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ kfree(vc4_state->dlist); ++ __drm_atomic_helper_plane_destroy_state(plane, &vc4_state->base); ++ kfree(state); ++} ++ ++/* Called during init to allocate the plane's atomic state. */ ++static void vc4_plane_reset(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ WARN_ON(plane->state); ++ ++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return; ++ ++ plane->state = &vc4_state->base; ++ vc4_state->base.plane = plane; ++} ++ ++static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) ++{ ++ if (vc4_state->dlist_count == vc4_state->dlist_size) { ++ u32 new_size = max(4u, vc4_state->dlist_count * 2); ++ u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL); ++ ++ if (!new_dlist) ++ return; ++ memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4); ++ ++ kfree(vc4_state->dlist); ++ vc4_state->dlist = new_dlist; ++ vc4_state->dlist_size = new_size; ++ } ++ ++ vc4_state->dlist[vc4_state->dlist_count++] = val; ++} ++ ++/* Writes out a full display list for an active plane to the plane's ++ * private dlist state. ++ */ ++static int vc4_plane_mode_set(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_framebuffer *fb = state->fb; ++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); ++ u32 ctl0_offset = vc4_state->dlist_count; ++ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format); ++ uint32_t offset = fb->offsets[0]; ++ int crtc_x = state->crtc_x; ++ int crtc_y = state->crtc_y; ++ int crtc_w = state->crtc_w; ++ int crtc_h = state->crtc_h; ++ ++ if (state->crtc_w << 16 != state->src_w || ++ state->crtc_h << 16 != state->src_h) { ++ /* We don't support scaling yet, which involves ++ * allocating the LBM memory for scaling temporary ++ * storage, and putting filter kernels in the HVS ++ * context. ++ */ ++ return -EINVAL; ++ } ++ ++ if (crtc_x < 0) { ++ offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x; ++ crtc_w += crtc_x; ++ crtc_x = 0; ++ } ++ ++ if (crtc_y < 0) { ++ offset += fb->pitches[0] * -crtc_y; ++ crtc_h += crtc_y; ++ crtc_y = 0; ++ } ++ ++ vc4_dlist_write(vc4_state, ++ SCALER_CTL0_VALID | ++ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | ++ (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | ++ SCALER_CTL0_UNITY); ++ ++ /* Position Word 0: Image Positions and Alpha Value */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) | ++ VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) | ++ VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y)); ++ ++ /* Position Word 1: Scaled Image Dimensions. ++ * Skipped due to SCALER_CTL0_UNITY scaling. ++ */ ++ ++ /* Position Word 2: Source Image Size, Alpha Mode */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(format->has_alpha ? ++ SCALER_POS2_ALPHA_MODE_PIPELINE : ++ SCALER_POS2_ALPHA_MODE_FIXED, ++ SCALER_POS2_ALPHA_MODE) | ++ VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) | ++ VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT)); ++ ++ /* Position Word 3: Context. Written by the HVS. */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ vc4_state->pw0_offset = vc4_state->dlist_count; ++ ++ /* Pointer Word 0: RGB / Y Pointer */ ++ vc4_dlist_write(vc4_state, bo->paddr + offset); ++ ++ /* Pointer Context Word 0: Written by the HVS */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ /* Pitch word 0: Pointer 0 Pitch */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); ++ ++ vc4_state->dlist[ctl0_offset] |= ++ VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); ++ ++ return 0; ++} ++ ++/* If a modeset involves changing the setup of a plane, the atomic ++ * infrastructure will call this to validate a proposed plane setup. ++ * However, if a plane isn't getting updated, this (and the ++ * corresponding vc4_plane_atomic_update) won't get called. Thus, we ++ * compute the dlist here and have all active plane dlists get updated ++ * in the CRTC's flush. ++ */ ++static int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ vc4_state->dlist_count = 0; ++ ++ if (plane_enabled(state)) ++ return vc4_plane_mode_set(plane, state); ++ else ++ return 0; ++} ++ ++static void vc4_plane_atomic_update(struct drm_plane *plane, ++ struct drm_plane_state *old_state) ++{ ++ /* No contents here. Since we don't know where in the CRTC's ++ * dlist we should be stored, our dlist is uploaded to the ++ * hardware with vc4_plane_write_dlist() at CRTC atomic_flush ++ * time. ++ */ ++} ++ ++u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); ++ int i; ++ ++ vc4_state->hw_dlist = dlist; ++ ++ /* Can't memcpy_toio() because it needs to be 32-bit writes. */ ++ for (i = 0; i < vc4_state->dlist_count; i++) ++ writel(vc4_state->dlist[i], &dlist[i]); ++ ++ return vc4_state->dlist_count; ++} ++ ++u32 vc4_plane_dlist_size(struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ return vc4_state->dlist_count; ++} ++ ++/* Updates the plane to immediately (well, once the FIFO needs ++ * refilling) scan out from at a new framebuffer. ++ */ ++void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); ++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); ++ uint32_t addr; ++ ++ /* We're skipping the address adjustment for negative origin, ++ * because this is only called on the primary plane. ++ */ ++ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); ++ addr = bo->paddr + fb->offsets[0]; ++ ++ /* Write the new address into the hardware immediately. The ++ * scanout will start from this address as soon as the FIFO ++ * needs to refill with pixels. ++ */ ++ writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]); ++ ++ /* Also update the CPU-side dlist copy, so that any later ++ * atomic updates that don't do a new modeset on our plane ++ * also use our updated address. ++ */ ++ vc4_state->dlist[vc4_state->pw0_offset] = addr; ++} ++ ++static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { ++ .prepare_fb = NULL, ++ .cleanup_fb = NULL, ++ .atomic_check = vc4_plane_atomic_check, ++ .atomic_update = vc4_plane_atomic_update, ++}; ++ ++static void vc4_plane_destroy(struct drm_plane *plane) ++{ ++ drm_plane_helper_disable(plane); ++ drm_plane_cleanup(plane); ++} ++ ++static const struct drm_plane_funcs vc4_plane_funcs = { ++ .update_plane = drm_atomic_helper_update_plane, ++ .disable_plane = drm_atomic_helper_disable_plane, ++ .destroy = vc4_plane_destroy, ++ .set_property = NULL, ++ .reset = vc4_plane_reset, ++ .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .atomic_destroy_state = vc4_plane_destroy_state, ++}; ++ ++struct drm_plane *vc4_plane_init(struct drm_device *dev, ++ enum drm_plane_type type) ++{ ++ struct drm_plane *plane = NULL; ++ struct vc4_plane *vc4_plane; ++ u32 formats[ARRAY_SIZE(hvs_formats)]; ++ int ret = 0; ++ unsigned i; ++ ++ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), ++ GFP_KERNEL); ++ if (!vc4_plane) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) ++ formats[i] = hvs_formats[i].drm; ++ plane = &vc4_plane->base; ++ ret = drm_universal_plane_init(dev, plane, 0xff, ++ &vc4_plane_funcs, ++ formats, ARRAY_SIZE(formats), ++ type); ++ ++ drm_plane_helper_add(plane, &vc4_plane_helper_funcs); ++ ++ return plane; ++fail: ++ if (plane) ++ vc4_plane_destroy(plane); ++ ++ return ERR_PTR(ret); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_qpu_defines.h b/drivers/gpu/drm/vc4/vc4_qpu_defines.h +new file mode 100644 +index 0000000..d5c2f3c +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h +@@ -0,0 +1,264 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef VC4_QPU_DEFINES_H ++#define VC4_QPU_DEFINES_H ++ ++enum qpu_op_add { ++ QPU_A_NOP, ++ QPU_A_FADD, ++ QPU_A_FSUB, ++ QPU_A_FMIN, ++ QPU_A_FMAX, ++ QPU_A_FMINABS, ++ QPU_A_FMAXABS, ++ QPU_A_FTOI, ++ QPU_A_ITOF, ++ QPU_A_ADD = 12, ++ QPU_A_SUB, ++ QPU_A_SHR, ++ QPU_A_ASR, ++ QPU_A_ROR, ++ QPU_A_SHL, ++ QPU_A_MIN, ++ QPU_A_MAX, ++ QPU_A_AND, ++ QPU_A_OR, ++ QPU_A_XOR, ++ QPU_A_NOT, ++ QPU_A_CLZ, ++ QPU_A_V8ADDS = 30, ++ QPU_A_V8SUBS = 31, ++}; ++ ++enum qpu_op_mul { ++ QPU_M_NOP, ++ QPU_M_FMUL, ++ QPU_M_MUL24, ++ QPU_M_V8MULD, ++ QPU_M_V8MIN, ++ QPU_M_V8MAX, ++ QPU_M_V8ADDS, ++ QPU_M_V8SUBS, ++}; ++ ++enum qpu_raddr { ++ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */ ++ /* 0-31 are the plain regfile a or b fields */ ++ QPU_R_UNIF = 32, ++ QPU_R_VARY = 35, ++ QPU_R_ELEM_QPU = 38, ++ QPU_R_NOP, ++ QPU_R_XY_PIXEL_COORD = 41, ++ QPU_R_MS_REV_FLAGS = 41, ++ QPU_R_VPM = 48, ++ QPU_R_VPM_LD_BUSY, ++ QPU_R_VPM_LD_WAIT, ++ QPU_R_MUTEX_ACQUIRE, ++}; ++ ++enum qpu_waddr { ++ /* 0-31 are the plain regfile a or b fields */ ++ QPU_W_ACC0 = 32, /* aka r0 */ ++ QPU_W_ACC1, ++ QPU_W_ACC2, ++ QPU_W_ACC3, ++ QPU_W_TMU_NOSWAP, ++ QPU_W_ACC5, ++ QPU_W_HOST_INT, ++ QPU_W_NOP, ++ QPU_W_UNIFORMS_ADDRESS, ++ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */ ++ QPU_W_MS_FLAGS = 42, ++ QPU_W_REV_FLAG = 42, ++ QPU_W_TLB_STENCIL_SETUP = 43, ++ QPU_W_TLB_Z, ++ QPU_W_TLB_COLOR_MS, ++ QPU_W_TLB_COLOR_ALL, ++ QPU_W_TLB_ALPHA_MASK, ++ QPU_W_VPM, ++ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */ ++ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */ ++ QPU_W_MUTEX_RELEASE, ++ QPU_W_SFU_RECIP, ++ QPU_W_SFU_RECIPSQRT, ++ QPU_W_SFU_EXP, ++ QPU_W_SFU_LOG, ++ QPU_W_TMU0_S, ++ QPU_W_TMU0_T, ++ QPU_W_TMU0_R, ++ QPU_W_TMU0_B, ++ QPU_W_TMU1_S, ++ QPU_W_TMU1_T, ++ QPU_W_TMU1_R, ++ QPU_W_TMU1_B, ++}; ++ ++enum qpu_sig_bits { ++ QPU_SIG_SW_BREAKPOINT, ++ QPU_SIG_NONE, ++ QPU_SIG_THREAD_SWITCH, ++ QPU_SIG_PROG_END, ++ QPU_SIG_WAIT_FOR_SCOREBOARD, ++ QPU_SIG_SCOREBOARD_UNLOCK, ++ QPU_SIG_LAST_THREAD_SWITCH, ++ QPU_SIG_COVERAGE_LOAD, ++ QPU_SIG_COLOR_LOAD, ++ QPU_SIG_COLOR_LOAD_END, ++ QPU_SIG_LOAD_TMU0, ++ QPU_SIG_LOAD_TMU1, ++ QPU_SIG_ALPHA_MASK_LOAD, ++ QPU_SIG_SMALL_IMM, ++ QPU_SIG_LOAD_IMM, ++ QPU_SIG_BRANCH ++}; ++ ++enum qpu_mux { ++ /* hardware mux values */ ++ QPU_MUX_R0, ++ QPU_MUX_R1, ++ QPU_MUX_R2, ++ QPU_MUX_R3, ++ QPU_MUX_R4, ++ QPU_MUX_R5, ++ QPU_MUX_A, ++ QPU_MUX_B, ++ ++ /* non-hardware mux values */ ++ QPU_MUX_IMM, ++}; ++ ++enum qpu_cond { ++ QPU_COND_NEVER, ++ QPU_COND_ALWAYS, ++ QPU_COND_ZS, ++ QPU_COND_ZC, ++ QPU_COND_NS, ++ QPU_COND_NC, ++ QPU_COND_CS, ++ QPU_COND_CC, ++}; ++ ++enum qpu_pack_mul { ++ QPU_PACK_MUL_NOP, ++ /* replicated to each 8 bits of the 32-bit dst. */ ++ QPU_PACK_MUL_8888 = 3, ++ QPU_PACK_MUL_8A, ++ QPU_PACK_MUL_8B, ++ QPU_PACK_MUL_8C, ++ QPU_PACK_MUL_8D, ++}; ++ ++enum qpu_pack_a { ++ QPU_PACK_A_NOP, ++ /* convert to 16 bit float if float input, or to int16. */ ++ QPU_PACK_A_16A, ++ QPU_PACK_A_16B, ++ /* replicated to each 8 bits of the 32-bit dst. */ ++ QPU_PACK_A_8888, ++ /* Convert to 8-bit unsigned int. */ ++ QPU_PACK_A_8A, ++ QPU_PACK_A_8B, ++ QPU_PACK_A_8C, ++ QPU_PACK_A_8D, ++ ++ /* Saturating variants of the previous instructions. */ ++ QPU_PACK_A_32_SAT, /* int-only */ ++ QPU_PACK_A_16A_SAT, /* int or float */ ++ QPU_PACK_A_16B_SAT, ++ QPU_PACK_A_8888_SAT, ++ QPU_PACK_A_8A_SAT, ++ QPU_PACK_A_8B_SAT, ++ QPU_PACK_A_8C_SAT, ++ QPU_PACK_A_8D_SAT, ++}; ++ ++enum qpu_unpack_r4 { ++ QPU_UNPACK_R4_NOP, ++ QPU_UNPACK_R4_F16A_TO_F32, ++ QPU_UNPACK_R4_F16B_TO_F32, ++ QPU_UNPACK_R4_8D_REP, ++ QPU_UNPACK_R4_8A, ++ QPU_UNPACK_R4_8B, ++ QPU_UNPACK_R4_8C, ++ QPU_UNPACK_R4_8D, ++}; ++ ++#define QPU_MASK(high, low) \ ++ ((((uint64_t)1 << ((high) - (low) + 1)) - 1) << (low)) ++ ++#define QPU_GET_FIELD(word, field) \ ++ ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT)) ++ ++#define QPU_SIG_SHIFT 60 ++#define QPU_SIG_MASK QPU_MASK(63, 60) ++ ++#define QPU_UNPACK_SHIFT 57 ++#define QPU_UNPACK_MASK QPU_MASK(59, 57) ++ ++/** ++ * If set, the pack field means PACK_MUL or R4 packing, instead of normal ++ * regfile a packing. ++ */ ++#define QPU_PM ((uint64_t)1 << 56) ++ ++#define QPU_PACK_SHIFT 52 ++#define QPU_PACK_MASK QPU_MASK(55, 52) ++ ++#define QPU_COND_ADD_SHIFT 49 ++#define QPU_COND_ADD_MASK QPU_MASK(51, 49) ++#define QPU_COND_MUL_SHIFT 46 ++#define QPU_COND_MUL_MASK QPU_MASK(48, 46) ++ ++#define QPU_SF ((uint64_t)1 << 45) ++ ++#define QPU_WADDR_ADD_SHIFT 38 ++#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38) ++#define QPU_WADDR_MUL_SHIFT 32 ++#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32) ++ ++#define QPU_OP_MUL_SHIFT 29 ++#define QPU_OP_MUL_MASK QPU_MASK(31, 29) ++ ++#define QPU_RADDR_A_SHIFT 18 ++#define QPU_RADDR_A_MASK QPU_MASK(23, 18) ++#define QPU_RADDR_B_SHIFT 12 ++#define QPU_RADDR_B_MASK QPU_MASK(17, 12) ++#define QPU_SMALL_IMM_SHIFT 12 ++#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12) ++ ++#define QPU_ADD_A_SHIFT 9 ++#define QPU_ADD_A_MASK QPU_MASK(11, 9) ++#define QPU_ADD_B_SHIFT 6 ++#define QPU_ADD_B_MASK QPU_MASK(8, 6) ++#define QPU_MUL_A_SHIFT 3 ++#define QPU_MUL_A_MASK QPU_MASK(5, 3) ++#define QPU_MUL_B_SHIFT 0 ++#define QPU_MUL_B_MASK QPU_MASK(2, 0) ++ ++#define QPU_WS ((uint64_t)1 << 44) ++ ++#define QPU_OP_ADD_SHIFT 24 ++#define QPU_OP_ADD_MASK QPU_MASK(28, 24) ++ ++#endif /* VC4_QPU_DEFINES_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +new file mode 100644 +index 0000000..4e52a0a +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -0,0 +1,570 @@ ++/* ++ * Copyright © 2014-2015 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. ++ */ ++ ++#ifndef VC4_REGS_H ++#define VC4_REGS_H ++ ++#include ++ ++#define VC4_MASK(high, low) ((u32)GENMASK(high, low)) ++/* Using the GNU statement expression extension */ ++#define VC4_SET_FIELD(value, field) \ ++ ({ \ ++ uint32_t fieldval = (value) << field##_SHIFT; \ ++ WARN_ON((fieldval & ~field##_MASK) != 0); \ ++ fieldval & field##_MASK; \ ++ }) ++ ++#define VC4_GET_FIELD(word, field) (((word) & field##_MASK) >> \ ++ field##_SHIFT) ++ ++#define V3D_IDENT0 0x00000 ++# define V3D_EXPECTED_IDENT0 \ ++ ((2 << 24) | \ ++ ('V' << 0) | \ ++ ('3' << 8) | \ ++ ('D' << 16)) ++ ++#define V3D_IDENT1 0x00004 ++/* Multiples of 1kb */ ++# define V3D_IDENT1_VPM_SIZE_MASK VC4_MASK(31, 28) ++# define V3D_IDENT1_VPM_SIZE_SHIFT 28 ++# define V3D_IDENT1_NSEM_MASK VC4_MASK(23, 16) ++# define V3D_IDENT1_NSEM_SHIFT 16 ++# define V3D_IDENT1_TUPS_MASK VC4_MASK(15, 12) ++# define V3D_IDENT1_TUPS_SHIFT 12 ++# define V3D_IDENT1_QUPS_MASK VC4_MASK(11, 8) ++# define V3D_IDENT1_QUPS_SHIFT 8 ++# define V3D_IDENT1_NSLC_MASK VC4_MASK(7, 4) ++# define V3D_IDENT1_NSLC_SHIFT 4 ++# define V3D_IDENT1_REV_MASK VC4_MASK(3, 0) ++# define V3D_IDENT1_REV_SHIFT 0 ++ ++#define V3D_IDENT2 0x00008 ++#define V3D_SCRATCH 0x00010 ++#define V3D_L2CACTL 0x00020 ++# define V3D_L2CACTL_L2CCLR BIT(2) ++# define V3D_L2CACTL_L2CDIS BIT(1) ++# define V3D_L2CACTL_L2CENA BIT(0) ++ ++#define V3D_SLCACTL 0x00024 ++# define V3D_SLCACTL_T1CC_MASK VC4_MASK(27, 24) ++# define V3D_SLCACTL_T1CC_SHIFT 24 ++# define V3D_SLCACTL_T0CC_MASK VC4_MASK(19, 16) ++# define V3D_SLCACTL_T0CC_SHIFT 16 ++# define V3D_SLCACTL_UCC_MASK VC4_MASK(11, 8) ++# define V3D_SLCACTL_UCC_SHIFT 8 ++# define V3D_SLCACTL_ICC_MASK VC4_MASK(3, 0) ++# define V3D_SLCACTL_ICC_SHIFT 0 ++ ++#define V3D_INTCTL 0x00030 ++#define V3D_INTENA 0x00034 ++#define V3D_INTDIS 0x00038 ++# define V3D_INT_SPILLUSE BIT(3) ++# define V3D_INT_OUTOMEM BIT(2) ++# define V3D_INT_FLDONE BIT(1) ++# define V3D_INT_FRDONE BIT(0) ++ ++#define V3D_CT0CS 0x00100 ++#define V3D_CT1CS 0x00104 ++#define V3D_CTNCS(n) (V3D_CT0CS + 4 * n) ++# define V3D_CTRSTA BIT(15) ++# define V3D_CTSEMA BIT(12) ++# define V3D_CTRTSD BIT(8) ++# define V3D_CTRUN BIT(5) ++# define V3D_CTSUBS BIT(4) ++# define V3D_CTERR BIT(3) ++# define V3D_CTMODE BIT(0) ++ ++#define V3D_CT0EA 0x00108 ++#define V3D_CT1EA 0x0010c ++#define V3D_CTNEA(n) (V3D_CT0EA + 4 * (n)) ++#define V3D_CT0CA 0x00110 ++#define V3D_CT1CA 0x00114 ++#define V3D_CTNCA(n) (V3D_CT0CA + 4 * (n)) ++#define V3D_CT00RA0 0x00118 ++#define V3D_CT01RA0 0x0011c ++#define V3D_CTNRA0(n) (V3D_CT00RA0 + 4 * (n)) ++#define V3D_CT0LC 0x00120 ++#define V3D_CT1LC 0x00124 ++#define V3D_CTNLC(n) (V3D_CT0LC + 4 * (n)) ++#define V3D_CT0PC 0x00128 ++#define V3D_CT1PC 0x0012c ++#define V3D_CTNPC(n) (V3D_CT0PC + 4 * (n)) ++ ++#define V3D_PCS 0x00130 ++# define V3D_BMOOM BIT(8) ++# define V3D_RMBUSY BIT(3) ++# define V3D_RMACTIVE BIT(2) ++# define V3D_BMBUSY BIT(1) ++# define V3D_BMACTIVE BIT(0) ++ ++#define V3D_BFC 0x00134 ++#define V3D_RFC 0x00138 ++#define V3D_BPCA 0x00300 ++#define V3D_BPCS 0x00304 ++#define V3D_BPOA 0x00308 ++#define V3D_BPOS 0x0030c ++#define V3D_BXCF 0x00310 ++#define V3D_SQRSV0 0x00410 ++#define V3D_SQRSV1 0x00414 ++#define V3D_SQCNTL 0x00418 ++#define V3D_SRQPC 0x00430 ++#define V3D_SRQUA 0x00434 ++#define V3D_SRQUL 0x00438 ++#define V3D_SRQCS 0x0043c ++#define V3D_VPACNTL 0x00500 ++#define V3D_VPMBASE 0x00504 ++#define V3D_PCTRC 0x00670 ++#define V3D_PCTRE 0x00674 ++#define V3D_PCTR0 0x00680 ++#define V3D_PCTRS0 0x00684 ++#define V3D_PCTR1 0x00688 ++#define V3D_PCTRS1 0x0068c ++#define V3D_PCTR2 0x00690 ++#define V3D_PCTRS2 0x00694 ++#define V3D_PCTR3 0x00698 ++#define V3D_PCTRS3 0x0069c ++#define V3D_PCTR4 0x006a0 ++#define V3D_PCTRS4 0x006a4 ++#define V3D_PCTR5 0x006a8 ++#define V3D_PCTRS5 0x006ac ++#define V3D_PCTR6 0x006b0 ++#define V3D_PCTRS6 0x006b4 ++#define V3D_PCTR7 0x006b8 ++#define V3D_PCTRS7 0x006bc ++#define V3D_PCTR8 0x006c0 ++#define V3D_PCTRS8 0x006c4 ++#define V3D_PCTR9 0x006c8 ++#define V3D_PCTRS9 0x006cc ++#define V3D_PCTR10 0x006d0 ++#define V3D_PCTRS10 0x006d4 ++#define V3D_PCTR11 0x006d8 ++#define V3D_PCTRS11 0x006dc ++#define V3D_PCTR12 0x006e0 ++#define V3D_PCTRS12 0x006e4 ++#define V3D_PCTR13 0x006e8 ++#define V3D_PCTRS13 0x006ec ++#define V3D_PCTR14 0x006f0 ++#define V3D_PCTRS14 0x006f4 ++#define V3D_PCTR15 0x006f8 ++#define V3D_PCTRS15 0x006fc ++#define V3D_DBGE 0x00f00 ++#define V3D_FDBGO 0x00f04 ++#define V3D_FDBGB 0x00f08 ++#define V3D_FDBGR 0x00f0c ++#define V3D_FDBGS 0x00f10 ++#define V3D_ERRSTAT 0x00f20 ++ ++#define PV_CONTROL 0x00 ++# define PV_CONTROL_FORMAT_MASK VC4_MASK(23, 21) ++# define PV_CONTROL_FORMAT_SHIFT 21 ++# define PV_CONTROL_FORMAT_24 0 ++# define PV_CONTROL_FORMAT_DSIV_16 1 ++# define PV_CONTROL_FORMAT_DSIC_16 2 ++# define PV_CONTROL_FORMAT_DSIV_18 3 ++# define PV_CONTROL_FORMAT_DSIV_24 4 ++ ++# define PV_CONTROL_FIFO_LEVEL_MASK VC4_MASK(20, 15) ++# define PV_CONTROL_FIFO_LEVEL_SHIFT 15 ++# define PV_CONTROL_CLR_AT_START BIT(14) ++# define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) ++# define PV_CONTROL_WAIT_HSTART BIT(12) ++# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 ++# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 ++# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) ++# define PV_CONTROL_CLK_SELECT_SHIFT 2 ++# define PV_CONTROL_FIFO_CLR BIT(1) ++# define PV_CONTROL_EN BIT(0) ++ ++#define PV_V_CONTROL 0x04 ++# define PV_VCONTROL_INTERLACE BIT(4) ++# define PV_VCONTROL_CONTINUOUS BIT(1) ++# define PV_VCONTROL_VIDEN BIT(0) ++ ++#define PV_VSYNCD 0x08 ++ ++#define PV_HORZA 0x0c ++# define PV_HORZA_HBP_MASK VC4_MASK(31, 16) ++# define PV_HORZA_HBP_SHIFT 16 ++# define PV_HORZA_HSYNC_MASK VC4_MASK(15, 0) ++# define PV_HORZA_HSYNC_SHIFT 0 ++ ++#define PV_HORZB 0x10 ++# define PV_HORZB_HFP_MASK VC4_MASK(31, 16) ++# define PV_HORZB_HFP_SHIFT 16 ++# define PV_HORZB_HACTIVE_MASK VC4_MASK(15, 0) ++# define PV_HORZB_HACTIVE_SHIFT 0 ++ ++#define PV_VERTA 0x14 ++# define PV_VERTA_VBP_MASK VC4_MASK(31, 16) ++# define PV_VERTA_VBP_SHIFT 16 ++# define PV_VERTA_VSYNC_MASK VC4_MASK(15, 0) ++# define PV_VERTA_VSYNC_SHIFT 0 ++ ++#define PV_VERTB 0x18 ++# define PV_VERTB_VFP_MASK VC4_MASK(31, 16) ++# define PV_VERTB_VFP_SHIFT 16 ++# define PV_VERTB_VACTIVE_MASK VC4_MASK(15, 0) ++# define PV_VERTB_VACTIVE_SHIFT 0 ++ ++#define PV_VERTA_EVEN 0x1c ++#define PV_VERTB_EVEN 0x20 ++ ++#define PV_INTEN 0x24 ++#define PV_INTSTAT 0x28 ++# define PV_INT_VID_IDLE BIT(9) ++# define PV_INT_VFP_END BIT(8) ++# define PV_INT_VFP_START BIT(7) ++# define PV_INT_VACT_START BIT(6) ++# define PV_INT_VBP_START BIT(5) ++# define PV_INT_VSYNC_START BIT(4) ++# define PV_INT_HFP_START BIT(3) ++# define PV_INT_HACT_START BIT(2) ++# define PV_INT_HBP_START BIT(1) ++# define PV_INT_HSYNC_START BIT(0) ++ ++#define PV_STAT 0x2c ++ ++#define PV_HACT_ACT 0x30 ++ ++#define SCALER_DISPCTRL 0x00000000 ++/* Global register for clock gating the HVS */ ++# define SCALER_DISPCTRL_ENABLE BIT(31) ++# define SCALER_DISPCTRL_DSP2EISLUR BIT(15) ++# define SCALER_DISPCTRL_DSP1EISLUR BIT(14) ++/* Enables Display 0 short line and underrun contribution to ++ * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are ++ * always enabled. ++ */ ++# define SCALER_DISPCTRL_DSP0EISLUR BIT(13) ++# define SCALER_DISPCTRL_DSP2EIEOLN BIT(12) ++# define SCALER_DISPCTRL_DSP2EIEOF BIT(11) ++# define SCALER_DISPCTRL_DSP1EIEOLN BIT(10) ++# define SCALER_DISPCTRL_DSP1EIEOF BIT(9) ++/* Enables Display 0 end-of-line-N contribution to ++ * SCALER_DISPSTAT_IRQDISP0 ++ */ ++# define SCALER_DISPCTRL_DSP0EIEOLN BIT(8) ++/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ ++# define SCALER_DISPCTRL_DSP0EIEOF BIT(7) ++ ++# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) ++# define SCALER_DISPCTRL_SLVWREIRQ BIT(5) ++# define SCALER_DISPCTRL_DMAEIRQ BIT(4) ++# define SCALER_DISPCTRL_DISP2EIRQ BIT(3) ++# define SCALER_DISPCTRL_DISP1EIRQ BIT(2) ++/* Enables interrupt generation on the enabled EOF/EOLN/EISLUR ++ * bits and short frames.. ++ */ ++# define SCALER_DISPCTRL_DISP0EIRQ BIT(1) ++/* Enables interrupt generation on scaler profiler interrupt. */ ++# define SCALER_DISPCTRL_SCLEIRQ BIT(0) ++ ++#define SCALER_DISPSTAT 0x00000004 ++# define SCALER_DISPSTAT_COBLOW2 BIT(29) ++# define SCALER_DISPSTAT_EOLN2 BIT(28) ++# define SCALER_DISPSTAT_ESFRAME2 BIT(27) ++# define SCALER_DISPSTAT_ESLINE2 BIT(26) ++# define SCALER_DISPSTAT_EUFLOW2 BIT(25) ++# define SCALER_DISPSTAT_EOF2 BIT(24) ++ ++# define SCALER_DISPSTAT_COBLOW1 BIT(21) ++# define SCALER_DISPSTAT_EOLN1 BIT(20) ++# define SCALER_DISPSTAT_ESFRAME1 BIT(19) ++# define SCALER_DISPSTAT_ESLINE1 BIT(18) ++# define SCALER_DISPSTAT_EUFLOW1 BIT(17) ++# define SCALER_DISPSTAT_EOF1 BIT(16) ++ ++# define SCALER_DISPSTAT_RESP_MASK VC4_MASK(15, 14) ++# define SCALER_DISPSTAT_RESP_SHIFT 14 ++# define SCALER_DISPSTAT_RESP_OKAY 0 ++# define SCALER_DISPSTAT_RESP_EXOKAY 1 ++# define SCALER_DISPSTAT_RESP_SLVERR 2 ++# define SCALER_DISPSTAT_RESP_DECERR 3 ++ ++# define SCALER_DISPSTAT_COBLOW0 BIT(13) ++/* Set when the DISPEOLN line is done compositing. */ ++# define SCALER_DISPSTAT_EOLN0 BIT(12) ++/* Set when VSTART is seen but there are still pixels in the current ++ * output line. ++ */ ++# define SCALER_DISPSTAT_ESFRAME0 BIT(11) ++/* Set when HSTART is seen but there are still pixels in the current ++ * output line. ++ */ ++# define SCALER_DISPSTAT_ESLINE0 BIT(10) ++/* Set when the the downstream tries to read from the display FIFO ++ * while it's empty. ++ */ ++# define SCALER_DISPSTAT_EUFLOW0 BIT(9) ++/* Set when the display mode changes from RUN to EOF */ ++# define SCALER_DISPSTAT_EOF0 BIT(8) ++ ++/* Set on AXI invalid DMA ID error. */ ++# define SCALER_DISPSTAT_DMA_ERROR BIT(7) ++/* Set on AXI slave read decode error */ ++# define SCALER_DISPSTAT_IRQSLVRD BIT(6) ++/* Set on AXI slave write decode error */ ++# define SCALER_DISPSTAT_IRQSLVWR BIT(5) ++/* Set when SCALER_DISPSTAT_DMA_ERROR is set, or ++ * SCALER_DISPSTAT_RESP_ERROR is not SCALER_DISPSTAT_RESP_OKAY. ++ */ ++# define SCALER_DISPSTAT_IRQDMA BIT(4) ++# define SCALER_DISPSTAT_IRQDISP2 BIT(3) ++# define SCALER_DISPSTAT_IRQDISP1 BIT(2) ++/* Set when any of the EOF/EOLN/ESFRAME/ESLINE bits are set and their ++ * corresponding interrupt bit is enabled in DISPCTRL. ++ */ ++# define SCALER_DISPSTAT_IRQDISP0 BIT(1) ++/* On read, the profiler interrupt. On write, clear *all* interrupt bits. */ ++# define SCALER_DISPSTAT_IRQSCL BIT(0) ++ ++#define SCALER_DISPID 0x00000008 ++#define SCALER_DISPECTRL 0x0000000c ++#define SCALER_DISPPROF 0x00000010 ++#define SCALER_DISPDITHER 0x00000014 ++#define SCALER_DISPEOLN 0x00000018 ++#define SCALER_DISPLIST0 0x00000020 ++#define SCALER_DISPLIST1 0x00000024 ++#define SCALER_DISPLIST2 0x00000028 ++#define SCALER_DISPLSTAT 0x0000002c ++#define SCALER_DISPLISTX(x) (SCALER_DISPLIST0 + \ ++ (x) * (SCALER_DISPLIST1 - \ ++ SCALER_DISPLIST0)) ++ ++#define SCALER_DISPLACT0 0x00000030 ++#define SCALER_DISPLACT1 0x00000034 ++#define SCALER_DISPLACT2 0x00000038 ++#define SCALER_DISPCTRL0 0x00000040 ++# define SCALER_DISPCTRLX_ENABLE BIT(31) ++# define SCALER_DISPCTRLX_RESET BIT(30) ++# define SCALER_DISPCTRLX_WIDTH_MASK VC4_MASK(23, 12) ++# define SCALER_DISPCTRLX_WIDTH_SHIFT 12 ++# define SCALER_DISPCTRLX_HEIGHT_MASK VC4_MASK(11, 0) ++# define SCALER_DISPCTRLX_HEIGHT_SHIFT 0 ++ ++#define SCALER_DISPBKGND0 0x00000044 ++#define SCALER_DISPSTAT0 0x00000048 ++#define SCALER_DISPBASE0 0x0000004c ++# define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30) ++# define SCALER_DISPSTATX_MODE_SHIFT 30 ++# define SCALER_DISPSTATX_MODE_DISABLED 0 ++# define SCALER_DISPSTATX_MODE_INIT 1 ++# define SCALER_DISPSTATX_MODE_RUN 2 ++# define SCALER_DISPSTATX_MODE_EOF 3 ++# define SCALER_DISPSTATX_FULL BIT(29) ++# define SCALER_DISPSTATX_EMPTY BIT(28) ++#define SCALER_DISPCTRL1 0x00000050 ++#define SCALER_DISPBKGND1 0x00000054 ++#define SCALER_DISPSTAT1 0x00000058 ++#define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \ ++ (x) * (SCALER_DISPSTAT1 - \ ++ SCALER_DISPSTAT0)) ++#define SCALER_DISPBASE1 0x0000005c ++#define SCALER_DISPCTRL2 0x00000060 ++#define SCALER_DISPCTRLX(x) (SCALER_DISPCTRL0 + \ ++ (x) * (SCALER_DISPCTRL1 - \ ++ SCALER_DISPCTRL0)) ++#define SCALER_DISPBKGND2 0x00000064 ++#define SCALER_DISPSTAT2 0x00000068 ++#define SCALER_DISPBASE2 0x0000006c ++#define SCALER_DISPALPHA2 0x00000070 ++#define SCALER_GAMADDR 0x00000078 ++#define SCALER_GAMDATA 0x000000e0 ++#define SCALER_DLIST_START 0x00002000 ++#define SCALER_DLIST_SIZE 0x00004000 ++ ++#define VC4_HDMI_CORE_REV 0x000 ++ ++#define VC4_HDMI_SW_RESET_CONTROL 0x004 ++# define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) ++# define VC4_HDMI_SW_RESET_HDMI BIT(0) ++ ++#define VC4_HDMI_HOTPLUG_INT 0x008 ++ ++#define VC4_HDMI_HOTPLUG 0x00c ++# define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) ++ ++#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 ++# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) ++ ++#define VC4_HDMI_HORZA 0x0c4 ++# define VC4_HDMI_HORZA_VPOS BIT(14) ++# define VC4_HDMI_HORZA_HPOS BIT(13) ++/* Horizontal active pixels (hdisplay). */ ++# define VC4_HDMI_HORZA_HAP_MASK VC4_MASK(12, 0) ++# define VC4_HDMI_HORZA_HAP_SHIFT 0 ++ ++#define VC4_HDMI_HORZB 0x0c8 ++/* Horizontal pack porch (htotal - hsync_end). */ ++# define VC4_HDMI_HORZB_HBP_MASK VC4_MASK(29, 20) ++# define VC4_HDMI_HORZB_HBP_SHIFT 20 ++/* Horizontal sync pulse (hsync_end - hsync_start). */ ++# define VC4_HDMI_HORZB_HSP_MASK VC4_MASK(19, 10) ++# define VC4_HDMI_HORZB_HSP_SHIFT 10 ++/* Horizontal front porch (hsync_start - hdisplay). */ ++# define VC4_HDMI_HORZB_HFP_MASK VC4_MASK(9, 0) ++# define VC4_HDMI_HORZB_HFP_SHIFT 0 ++ ++#define VC4_HDMI_FIFO_CTL 0x05c ++# define VC4_HDMI_FIFO_CTL_RECENTER_DONE BIT(14) ++# define VC4_HDMI_FIFO_CTL_USE_EMPTY BIT(13) ++# define VC4_HDMI_FIFO_CTL_ON_VB BIT(7) ++# define VC4_HDMI_FIFO_CTL_RECENTER BIT(6) ++# define VC4_HDMI_FIFO_CTL_FIFO_RESET BIT(5) ++# define VC4_HDMI_FIFO_CTL_USE_PLL_LOCK BIT(4) ++# define VC4_HDMI_FIFO_CTL_INV_CLK_XFR BIT(3) ++# define VC4_HDMI_FIFO_CTL_CAPTURE_PTR BIT(2) ++# define VC4_HDMI_FIFO_CTL_USE_FULL BIT(1) ++# define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N BIT(0) ++# define VC4_HDMI_FIFO_VALID_WRITE_MASK 0xefff ++ ++#define VC4_HDMI_SCHEDULER_CONTROL 0x0c0 ++# define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15) ++# define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5) ++# define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT BIT(3) ++# define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE BIT(1) ++# define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI BIT(0) ++ ++#define VC4_HDMI_VERTA0 0x0cc ++#define VC4_HDMI_VERTA1 0x0d4 ++/* Vertical sync pulse (vsync_end - vsync_start). */ ++# define VC4_HDMI_VERTA_VSP_MASK VC4_MASK(24, 20) ++# define VC4_HDMI_VERTA_VSP_SHIFT 20 ++/* Vertical front porch (vsync_start - vdisplay). */ ++# define VC4_HDMI_VERTA_VFP_MASK VC4_MASK(19, 13) ++# define VC4_HDMI_VERTA_VFP_SHIFT 13 ++/* Vertical active lines (vdisplay). */ ++# define VC4_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) ++# define VC4_HDMI_VERTA_VAL_SHIFT 0 ++ ++#define VC4_HDMI_VERTB0 0x0d0 ++#define VC4_HDMI_VERTB1 0x0d8 ++/* Vertical sync pulse offset (for interlaced) */ ++# define VC4_HDMI_VERTB_VSPO_MASK VC4_MASK(21, 9) ++# define VC4_HDMI_VERTB_VSPO_SHIFT 9 ++/* Vertical pack porch (vtotal - vsync_end). */ ++# define VC4_HDMI_VERTB_VBP_MASK VC4_MASK(8, 0) ++# define VC4_HDMI_VERTB_VBP_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 ++ ++#define VC4_HD_M_CTL 0x00c ++# define VC4_HD_M_SW_RST BIT(2) ++# define VC4_HD_M_ENABLE BIT(0) ++ ++#define VC4_HD_MAI_CTL 0x014 ++ ++#define VC4_HD_VID_CTL 0x038 ++# define VC4_HD_VID_CTL_ENABLE BIT(31) ++# define VC4_HD_VID_CTL_UNDERFLOW_ENABLE BIT(30) ++# define VC4_HD_VID_CTL_FRAME_COUNTER_RESET BIT(29) ++# define VC4_HD_VID_CTL_VSYNC_LOW BIT(28) ++# define VC4_HD_VID_CTL_HSYNC_LOW BIT(27) ++ ++#define VC4_HD_CSC_CTL 0x040 ++# define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) ++# define VC4_HD_CSC_CTL_ORDER_SHIFT 5 ++# define VC4_HD_CSC_CTL_ORDER_RGB 0 ++# define VC4_HD_CSC_CTL_ORDER_BGR 1 ++# define VC4_HD_CSC_CTL_ORDER_BRG 2 ++# define VC4_HD_CSC_CTL_ORDER_GRB 3 ++# define VC4_HD_CSC_CTL_ORDER_GBR 4 ++# define VC4_HD_CSC_CTL_ORDER_RBG 5 ++# define VC4_HD_CSC_CTL_PADMSB BIT(4) ++# define VC4_HD_CSC_CTL_MODE_MASK VC4_MASK(3, 2) ++# define VC4_HD_CSC_CTL_MODE_SHIFT 2 ++# define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 ++# define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 ++# define VC4_HD_CSC_CTL_MODE_CUSTOM 2 ++# define VC4_HD_CSC_CTL_RGB2YCC BIT(1) ++# define VC4_HD_CSC_CTL_ENABLE BIT(0) ++ ++#define VC4_HD_FRAME_COUNT 0x068 ++ ++/* HVS display list information. */ ++#define HVS_BOOTLOADER_DLIST_END 32 ++ ++enum hvs_pixel_format { ++ /* 8bpp */ ++ HVS_PIXEL_FORMAT_RGB332 = 0, ++ /* 16bpp */ ++ HVS_PIXEL_FORMAT_RGBA4444 = 1, ++ HVS_PIXEL_FORMAT_RGB555 = 2, ++ HVS_PIXEL_FORMAT_RGBA5551 = 3, ++ HVS_PIXEL_FORMAT_RGB565 = 4, ++ /* 24bpp */ ++ HVS_PIXEL_FORMAT_RGB888 = 5, ++ HVS_PIXEL_FORMAT_RGBA6666 = 6, ++ /* 32bpp */ ++ HVS_PIXEL_FORMAT_RGBA8888 = 7 ++}; ++ ++/* Note: the LSB is the rightmost character shown. Only valid for ++ * HVS_PIXEL_FORMAT_RGB8888, not RGB888. ++ */ ++#define HVS_PIXEL_ORDER_RGBA 0 ++#define HVS_PIXEL_ORDER_BGRA 1 ++#define HVS_PIXEL_ORDER_ARGB 2 ++#define HVS_PIXEL_ORDER_ABGR 3 ++ ++#define HVS_PIXEL_ORDER_XBRG 0 ++#define HVS_PIXEL_ORDER_XRBG 1 ++#define HVS_PIXEL_ORDER_XRGB 2 ++#define HVS_PIXEL_ORDER_XBGR 3 ++ ++#define HVS_PIXEL_ORDER_XYCBCR 0 ++#define HVS_PIXEL_ORDER_XYCRCB 1 ++#define HVS_PIXEL_ORDER_YXCBCR 2 ++#define HVS_PIXEL_ORDER_YXCRCB 3 ++ ++#define SCALER_CTL0_END BIT(31) ++#define SCALER_CTL0_VALID BIT(30) ++ ++#define SCALER_CTL0_SIZE_MASK VC4_MASK(29, 24) ++#define SCALER_CTL0_SIZE_SHIFT 24 ++ ++#define SCALER_CTL0_HFLIP BIT(16) ++#define SCALER_CTL0_VFLIP BIT(15) ++ ++#define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13) ++#define SCALER_CTL0_ORDER_SHIFT 13 ++ ++/* Set to indicate no scaling. */ ++#define SCALER_CTL0_UNITY BIT(4) ++ ++#define SCALER_CTL0_PIXEL_FORMAT_MASK VC4_MASK(3, 0) ++#define SCALER_CTL0_PIXEL_FORMAT_SHIFT 0 ++ ++#define SCALER_POS0_FIXED_ALPHA_MASK VC4_MASK(31, 24) ++#define SCALER_POS0_FIXED_ALPHA_SHIFT 24 ++ ++#define SCALER_POS0_START_Y_MASK VC4_MASK(23, 12) ++#define SCALER_POS0_START_Y_SHIFT 12 ++ ++#define SCALER_POS0_START_X_MASK VC4_MASK(11, 0) ++#define SCALER_POS0_START_X_SHIFT 0 ++ ++#define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30) ++#define SCALER_POS2_ALPHA_MODE_SHIFT 30 ++#define SCALER_POS2_ALPHA_MODE_PIPELINE 0 ++#define SCALER_POS2_ALPHA_MODE_FIXED 1 ++#define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 ++#define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 ++ ++#define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) ++#define SCALER_POS2_HEIGHT_SHIFT 16 ++ ++#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) ++#define SCALER_POS2_WIDTH_SHIFT 0 ++ ++#define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0) ++#define SCALER_SRC_PITCH_SHIFT 0 ++ ++#endif /* VC4_REGS_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +new file mode 100644 +index 0000000..8a2a312 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -0,0 +1,634 @@ ++/* ++ * Copyright © 2014-2015 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Render command list generation ++ * ++ * In the VC4 driver, render command list generation is performed by the ++ * kernel instead of userspace. We do this because validating a ++ * user-submitted command list is hard to get right and has high CPU overhead, ++ * while the number of valid configurations for render command lists is ++ * actually fairly low. ++ */ ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_packet.h" ++ ++struct vc4_rcl_setup { ++ struct drm_gem_cma_object *color_read; ++ struct drm_gem_cma_object *color_write; ++ struct drm_gem_cma_object *zs_read; ++ struct drm_gem_cma_object *zs_write; ++ struct drm_gem_cma_object *msaa_color_write; ++ struct drm_gem_cma_object *msaa_zs_write; ++ ++ struct drm_gem_cma_object *rcl; ++ u32 next_offset; ++}; ++ ++static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) ++{ ++ *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 1; ++} ++ ++static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val) ++{ ++ *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 2; ++} ++ ++static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val) ++{ ++ *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 4; ++} ++ ++/* ++ * Emits a no-op STORE_TILE_BUFFER_GENERAL. ++ * ++ * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of ++ * some sort before another load is triggered. ++ */ ++static void vc4_store_before_load(struct vc4_rcl_setup *setup) ++{ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, ++ VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE, ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER) | ++ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR | ++ VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR | ++ VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR); ++ rcl_u32(setup, 0); /* no address, since we're in None mode */ ++} ++ ++/* ++ * Calculates the physical address of the start of a tile in a RCL surface. ++ * ++ * Unlike the other load/store packets, ++ * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile ++ * coordinates packet, and instead just store to the address given. ++ */ ++static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *bo, ++ struct drm_vc4_submit_rcl_surface *surf, ++ uint8_t x, uint8_t y) ++{ ++ return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE * ++ (DIV_ROUND_UP(exec->args->width, 32) * y + x); ++} ++ ++/* ++ * Emits a PACKET_TILE_COORDINATES if one isn't already pending. ++ * ++ * The tile coordinates packet triggers a pending load if there is one, are ++ * used for clipping during rendering, and determine where loads/stores happen ++ * relative to their base address. ++ */ ++static void vc4_tile_coordinates(struct vc4_rcl_setup *setup, ++ uint32_t x, uint32_t y) ++{ ++ rcl_u8(setup, VC4_PACKET_TILE_COORDINATES); ++ rcl_u8(setup, x); ++ rcl_u8(setup, y); ++} ++ ++static void emit_tile(struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup, ++ uint8_t x, uint8_t y, bool first, bool last) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ ++ /* Note that the load doesn't actually occur until the ++ * tile coords packet is processed, and only one load ++ * may be outstanding at a time. ++ */ ++ if (setup->color_read) { ++ if (args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->color_read, ++ &args->color_read, x, y) | ++ VC4_LOADSTORE_FULL_RES_DISABLE_ZS); ++ } else { ++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->color_read.bits); ++ rcl_u32(setup, setup->color_read->paddr + ++ args->color_read.offset); ++ } ++ } ++ ++ if (setup->zs_read) { ++ if (args->zs_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->zs_read, ++ &args->zs_read, x, y) | ++ VC4_LOADSTORE_FULL_RES_DISABLE_COLOR); ++ } else { ++ if (setup->color_read) { ++ /* Exec previous load. */ ++ vc4_tile_coordinates(setup, x, y); ++ vc4_store_before_load(setup); ++ } ++ ++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->zs_read.bits); ++ rcl_u32(setup, setup->zs_read->paddr + ++ args->zs_read.offset); ++ } ++ } ++ ++ /* Clipping depends on tile coordinates having been ++ * emitted, so we always need one here. ++ */ ++ vc4_tile_coordinates(setup, x, y); ++ ++ /* Wait for the binner before jumping to the first ++ * tile's lists. ++ */ ++ if (first && has_bin) ++ rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE); ++ ++ if (has_bin) { ++ rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); ++ rcl_u32(setup, (exec->tile_bo->paddr + ++ exec->tile_alloc_offset + ++ (y * exec->bin_tiles_x + x) * 32)); ++ } ++ ++ if (setup->msaa_color_write) { ++ bool last_tile_write = (!setup->msaa_zs_write && ++ !setup->zs_write && ++ !setup->color_write); ++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS; ++ ++ if (!last_tile_write) ++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; ++ else if (last) ++ bits |= VC4_LOADSTORE_FULL_RES_EOF; ++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->msaa_color_write, ++ &args->msaa_color_write, x, y) | ++ bits); ++ } ++ ++ if (setup->msaa_zs_write) { ++ bool last_tile_write = (!setup->zs_write && ++ !setup->color_write); ++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR; ++ ++ if (setup->msaa_color_write) ++ vc4_tile_coordinates(setup, x, y); ++ if (!last_tile_write) ++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; ++ else if (last) ++ bits |= VC4_LOADSTORE_FULL_RES_EOF; ++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->msaa_zs_write, ++ &args->msaa_zs_write, x, y) | ++ bits); ++ } ++ ++ if (setup->zs_write) { ++ bool last_tile_write = !setup->color_write; ++ ++ if (setup->msaa_color_write || setup->msaa_zs_write) ++ vc4_tile_coordinates(setup, x, y); ++ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->zs_write.bits | ++ (last_tile_write ? ++ 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR)); ++ rcl_u32(setup, ++ (setup->zs_write->paddr + args->zs_write.offset) | ++ ((last && last_tile_write) ? ++ VC4_LOADSTORE_TILE_BUFFER_EOF : 0)); ++ } ++ ++ if (setup->color_write) { ++ if (setup->msaa_color_write || setup->msaa_zs_write || ++ setup->zs_write) { ++ vc4_tile_coordinates(setup, x, y); ++ } ++ ++ if (last) ++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF); ++ else ++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER); ++ } ++} ++ ++static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ uint8_t min_x_tile = args->min_x_tile; ++ uint8_t min_y_tile = args->min_y_tile; ++ uint8_t max_x_tile = args->max_x_tile; ++ uint8_t max_y_tile = args->max_y_tile; ++ uint8_t xtiles = max_x_tile - min_x_tile + 1; ++ uint8_t ytiles = max_y_tile - min_y_tile + 1; ++ uint8_t x, y; ++ uint32_t size, loop_body_size; ++ ++ size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE; ++ loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE; ++ ++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { ++ size += VC4_PACKET_CLEAR_COLORS_SIZE + ++ VC4_PACKET_TILE_COORDINATES_SIZE + ++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ } ++ ++ if (setup->color_read) { ++ if (args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; ++ } else { ++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; ++ } ++ } ++ if (setup->zs_read) { ++ if (args->zs_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; ++ } else { ++ if (setup->color_read && ++ !(args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) { ++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE; ++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ } ++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; ++ } ++ } ++ ++ if (has_bin) { ++ size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE; ++ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE; ++ } ++ ++ if (setup->msaa_color_write) ++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; ++ if (setup->msaa_zs_write) ++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; ++ ++ if (setup->zs_write) ++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ if (setup->color_write) ++ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE; ++ ++ /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */ ++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE * ++ ((setup->msaa_color_write != NULL) + ++ (setup->msaa_zs_write != NULL) + ++ (setup->color_write != NULL) + ++ (setup->zs_write != NULL) - 1); ++ ++ size += xtiles * ytiles * loop_body_size; ++ ++ setup->rcl = &vc4_bo_create(dev, size, true)->base; ++ if (!setup->rcl) ++ return -ENOMEM; ++ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, ++ &exec->unref_list); ++ ++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); ++ rcl_u32(setup, ++ (setup->color_write ? (setup->color_write->paddr + ++ args->color_write.offset) : ++ 0)); ++ rcl_u16(setup, args->width); ++ rcl_u16(setup, args->height); ++ rcl_u16(setup, args->color_write.bits); ++ ++ /* The tile buffer gets cleared when the previous tile is stored. If ++ * the clear values changed between frames, then the tile buffer has ++ * stale clear values in it, so we have to do a store in None mode (no ++ * writes) so that we trigger the tile buffer clear. ++ */ ++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { ++ rcl_u8(setup, VC4_PACKET_CLEAR_COLORS); ++ rcl_u32(setup, args->clear_color[0]); ++ rcl_u32(setup, args->clear_color[1]); ++ rcl_u32(setup, args->clear_z); ++ rcl_u8(setup, args->clear_s); ++ ++ vc4_tile_coordinates(setup, 0, 0); ++ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE); ++ rcl_u32(setup, 0); /* no address, since we're in None mode */ ++ } ++ ++ for (y = min_y_tile; y <= max_y_tile; y++) { ++ for (x = min_x_tile; x <= max_x_tile; x++) { ++ bool first = (x == min_x_tile && y == min_y_tile); ++ bool last = (x == max_x_tile && y == max_y_tile); ++ ++ emit_tile(exec, setup, x, y, first, last); ++ } ++ } ++ ++ BUG_ON(setup->next_offset != size); ++ exec->ct1ca = setup->rcl->paddr; ++ exec->ct1ea = setup->rcl->paddr + setup->next_offset; ++ ++ return 0; ++} ++ ++static int vc4_full_res_bounds_check(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32); ++ ++ if (surf->offset > obj->base.size) { ++ DRM_ERROR("surface offset %d > BO size %zd\n", ++ surf->offset, obj->base.size); ++ return -EINVAL; ++ } ++ ++ if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE < ++ render_tiles_stride * args->max_y_tile + args->max_x_tile) { ++ DRM_ERROR("MSAA tile %d, %d out of bounds " ++ "(bo size %zd, offset %d).\n", ++ args->max_x_tile, args->max_y_tile, ++ obj->base.size, ++ surf->offset); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ if (surf->flags != 0 || surf->bits != 0) { ++ DRM_ERROR("MSAA surface had nonzero flags/bits\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (surf->offset & 0xf) { ++ DRM_ERROR("MSAA write must be 16b aligned.\n"); ++ return -EINVAL; ++ } ++ ++ return vc4_full_res_bounds_check(exec, *obj, surf); ++} ++ ++static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ uint8_t tiling = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_TILING); ++ uint8_t buffer = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER); ++ uint8_t format = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_FORMAT); ++ int cpp; ++ int ret; ++ ++ if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ DRM_ERROR("Extra flags set\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ if (surf == &exec->args->zs_write) { ++ DRM_ERROR("general zs write may not be a full-res.\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->bits != 0) { ++ DRM_ERROR("load/store general bits set with " ++ "full res load/store.\n"); ++ return -EINVAL; ++ } ++ ++ ret = vc4_full_res_bounds_check(exec, *obj, surf); ++ if (!ret) ++ return ret; ++ ++ return 0; ++ } ++ ++ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK | ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK | ++ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) { ++ DRM_ERROR("Unknown bits in load/store: 0x%04x\n", ++ surf->bits); ++ return -EINVAL; ++ } ++ ++ if (tiling > VC4_TILING_FORMAT_LT) { ++ DRM_ERROR("Bad tiling format\n"); ++ return -EINVAL; ++ } ++ ++ if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) { ++ if (format != 0) { ++ DRM_ERROR("No color format should be set for ZS\n"); ++ return -EINVAL; ++ } ++ cpp = 4; ++ } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) { ++ switch (format) { ++ case VC4_LOADSTORE_TILE_BUFFER_BGR565: ++ case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER: ++ cpp = 2; ++ break; ++ case VC4_LOADSTORE_TILE_BUFFER_RGBA8888: ++ cpp = 4; ++ break; ++ default: ++ DRM_ERROR("Bad tile buffer format\n"); ++ return -EINVAL; ++ } ++ } else { ++ DRM_ERROR("Bad load/store buffer %d.\n", buffer); ++ return -EINVAL; ++ } ++ ++ if (surf->offset & 0xf) { ++ DRM_ERROR("load/store buffer must be 16b aligned.\n"); ++ return -EINVAL; ++ } ++ ++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, ++ exec->args->width, exec->args->height, cpp)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ uint8_t tiling = VC4_GET_FIELD(surf->bits, ++ VC4_RENDER_CONFIG_MEMORY_FORMAT); ++ uint8_t format = VC4_GET_FIELD(surf->bits, ++ VC4_RENDER_CONFIG_FORMAT); ++ int cpp; ++ ++ if (surf->flags != 0) { ++ DRM_ERROR("No flags supported on render config.\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK | ++ VC4_RENDER_CONFIG_FORMAT_MASK | ++ VC4_RENDER_CONFIG_MS_MODE_4X | ++ VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) { ++ DRM_ERROR("Unknown bits in render config: 0x%04x\n", ++ surf->bits); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (tiling > VC4_TILING_FORMAT_LT) { ++ DRM_ERROR("Bad tiling format\n"); ++ return -EINVAL; ++ } ++ ++ switch (format) { ++ case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED: ++ case VC4_RENDER_CONFIG_FORMAT_BGR565: ++ cpp = 2; ++ break; ++ case VC4_RENDER_CONFIG_FORMAT_RGBA8888: ++ cpp = 4; ++ break; ++ default: ++ DRM_ERROR("Bad tile buffer format\n"); ++ return -EINVAL; ++ } ++ ++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, ++ exec->args->width, exec->args->height, cpp)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct vc4_rcl_setup setup = {0}; ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ int ret; ++ ++ if (args->min_x_tile > args->max_x_tile || ++ args->min_y_tile > args->max_y_tile) { ++ DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n", ++ args->min_x_tile, args->min_y_tile, ++ args->max_x_tile, args->max_y_tile); ++ return -EINVAL; ++ } ++ ++ if (has_bin && ++ (args->max_x_tile > exec->bin_tiles_x || ++ args->max_y_tile > exec->bin_tiles_y)) { ++ DRM_ERROR("Render tiles (%d,%d) outside of bin config " ++ "(%d,%d)\n", ++ args->max_x_tile, args->max_y_tile, ++ exec->bin_tiles_x, exec->bin_tiles_y); ++ return -EINVAL; ++ } ++ ++ ret = vc4_rcl_render_config_surface_setup(exec, &setup, ++ &setup.color_write, ++ &args->color_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write, ++ &args->msaa_color_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write, ++ &args->msaa_zs_write); ++ if (ret) ++ return ret; ++ ++ /* We shouldn't even have the job submitted to us if there's no ++ * surface to write out. ++ */ ++ if (!setup.color_write && !setup.zs_write && ++ !setup.msaa_color_write && !setup.msaa_zs_write) { ++ DRM_ERROR("RCL requires color or Z/S write\n"); ++ return -EINVAL; ++ } ++ ++ return vc4_create_rcl_bo(dev, exec, &setup); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h +new file mode 100644 +index 0000000..ad7b1ea +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_trace.h +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) ++#define _VC4_TRACE_H_ ++ ++#include ++#include ++#include ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM vc4 ++#define TRACE_INCLUDE_FILE vc4_trace ++ ++TRACE_EVENT(vc4_wait_for_seqno_begin, ++ TP_PROTO(struct drm_device *dev, uint64_t seqno, uint64_t timeout), ++ TP_ARGS(dev, seqno, timeout), ++ ++ TP_STRUCT__entry( ++ __field(u32, dev) ++ __field(u64, seqno) ++ __field(u64, timeout) ++ ), ++ ++ TP_fast_assign( ++ __entry->dev = dev->primary->index; ++ __entry->seqno = seqno; ++ __entry->timeout = timeout; ++ ), ++ ++ TP_printk("dev=%u, seqno=%llu, timeout=%llu", ++ __entry->dev, __entry->seqno, __entry->timeout) ++); ++ ++TRACE_EVENT(vc4_wait_for_seqno_end, ++ TP_PROTO(struct drm_device *dev, uint64_t seqno), ++ TP_ARGS(dev, seqno), ++ ++ TP_STRUCT__entry( ++ __field(u32, dev) ++ __field(u64, seqno) ++ ), ++ ++ TP_fast_assign( ++ __entry->dev = dev->primary->index; ++ __entry->seqno = seqno; ++ ), ++ ++ TP_printk("dev=%u, seqno=%llu", ++ __entry->dev, __entry->seqno) ++); ++ ++#endif /* _VC4_TRACE_H_ */ ++ ++/* This part must be outside protection */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#include +diff --git a/drivers/gpu/drm/vc4/vc4_trace_points.c b/drivers/gpu/drm/vc4/vc4_trace_points.c +new file mode 100644 +index 0000000..e6278f2 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_trace_points.c +@@ -0,0 +1,14 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#include "vc4_drv.h" ++ ++#ifndef __CHECKER__ ++#define CREATE_TRACE_POINTS ++#include "vc4_trace.h" ++#endif +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +new file mode 100644 +index 0000000..4d103f7f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -0,0 +1,270 @@ ++/* ++ * Copyright (c) 2014 The Linux Foundation. All rights reserved. ++ * Copyright (C) 2013 Red Hat ++ * Author: Rob Clark ++ * ++ * 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 . ++ */ ++ ++#include "linux/component.h" ++#include "soc/bcm2835/raspberrypi-firmware.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#ifdef CONFIG_DEBUG_FS ++#define REGDEF(reg) { reg, #reg } ++static const struct { ++ uint32_t reg; ++ const char *name; ++} vc4_reg_defs[] = { ++ REGDEF(V3D_IDENT0), ++ REGDEF(V3D_IDENT1), ++ REGDEF(V3D_IDENT2), ++ REGDEF(V3D_SCRATCH), ++ REGDEF(V3D_L2CACTL), ++ REGDEF(V3D_SLCACTL), ++ REGDEF(V3D_INTCTL), ++ REGDEF(V3D_INTENA), ++ REGDEF(V3D_INTDIS), ++ REGDEF(V3D_CT0CS), ++ REGDEF(V3D_CT1CS), ++ REGDEF(V3D_CT0EA), ++ REGDEF(V3D_CT1EA), ++ REGDEF(V3D_CT0CA), ++ REGDEF(V3D_CT1CA), ++ REGDEF(V3D_CT00RA0), ++ REGDEF(V3D_CT01RA0), ++ REGDEF(V3D_CT0LC), ++ REGDEF(V3D_CT1LC), ++ REGDEF(V3D_CT0PC), ++ REGDEF(V3D_CT1PC), ++ REGDEF(V3D_PCS), ++ REGDEF(V3D_BFC), ++ REGDEF(V3D_RFC), ++ REGDEF(V3D_BPCA), ++ REGDEF(V3D_BPCS), ++ REGDEF(V3D_BPOA), ++ REGDEF(V3D_BPOS), ++ REGDEF(V3D_BXCF), ++ REGDEF(V3D_SQRSV0), ++ REGDEF(V3D_SQRSV1), ++ REGDEF(V3D_SQCNTL), ++ REGDEF(V3D_SRQPC), ++ REGDEF(V3D_SRQUA), ++ REGDEF(V3D_SRQUL), ++ REGDEF(V3D_SRQCS), ++ REGDEF(V3D_VPACNTL), ++ REGDEF(V3D_VPMBASE), ++ REGDEF(V3D_PCTRC), ++ REGDEF(V3D_PCTRE), ++ REGDEF(V3D_PCTR0), ++ REGDEF(V3D_PCTRS0), ++ REGDEF(V3D_PCTR1), ++ REGDEF(V3D_PCTRS1), ++ REGDEF(V3D_PCTR2), ++ REGDEF(V3D_PCTRS2), ++ REGDEF(V3D_PCTR3), ++ REGDEF(V3D_PCTRS3), ++ REGDEF(V3D_PCTR4), ++ REGDEF(V3D_PCTRS4), ++ REGDEF(V3D_PCTR5), ++ REGDEF(V3D_PCTRS5), ++ REGDEF(V3D_PCTR6), ++ REGDEF(V3D_PCTRS6), ++ REGDEF(V3D_PCTR7), ++ REGDEF(V3D_PCTRS7), ++ REGDEF(V3D_PCTR8), ++ REGDEF(V3D_PCTRS8), ++ REGDEF(V3D_PCTR9), ++ REGDEF(V3D_PCTRS9), ++ REGDEF(V3D_PCTR10), ++ REGDEF(V3D_PCTRS10), ++ REGDEF(V3D_PCTR11), ++ REGDEF(V3D_PCTRS11), ++ REGDEF(V3D_PCTR12), ++ REGDEF(V3D_PCTRS12), ++ REGDEF(V3D_PCTR13), ++ REGDEF(V3D_PCTRS13), ++ REGDEF(V3D_PCTR14), ++ REGDEF(V3D_PCTRS14), ++ REGDEF(V3D_PCTR15), ++ REGDEF(V3D_PCTRS15), ++ REGDEF(V3D_DBGE), ++ REGDEF(V3D_FDBGO), ++ REGDEF(V3D_FDBGB), ++ REGDEF(V3D_FDBGR), ++ REGDEF(V3D_FDBGS), ++ REGDEF(V3D_ERRSTAT), ++}; ++ ++int vc4_v3d_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ vc4_reg_defs[i].name, vc4_reg_defs[i].reg, ++ V3D_READ(vc4_reg_defs[i].reg)); ++ } ++ ++ return 0; ++} ++ ++int vc4_v3d_debugfs_ident(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); ++ uint32_t ident1 = V3D_READ(V3D_IDENT1); ++ uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC); ++ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS); ++ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS); ++ ++ seq_printf(m, "Revision: %d\n", ++ VC4_GET_FIELD(ident1, V3D_IDENT1_REV)); ++ seq_printf(m, "Slices: %d\n", nslc); ++ seq_printf(m, "TMUs: %d\n", nslc * tups); ++ seq_printf(m, "QPUs: %d\n", nslc * qups); ++ seq_printf(m, "Semaphores: %d\n", ++ VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM)); ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++/* ++ * Asks the firmware to turn on power to the V3D engine. ++ * ++ * This may be doable with just the clocks interface, though this ++ * packet does some other register setup from the firmware, too. ++ */ ++int ++vc4_v3d_set_power(struct vc4_dev *vc4, bool on) ++{ ++ u32 packet = on; ++ ++ return rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_SET_ENABLE_QPU, ++ &packet, sizeof(packet)); ++} ++ ++static void vc4_v3d_init_hw(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Take all the memory that would have been reserved for user ++ * QPU programs, since we don't have an interface for running ++ * them, anyway. ++ */ ++ V3D_WRITE(V3D_VPMBASE, 0); ++} ++ ++static int vc4_v3d_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_v3d *v3d = NULL; ++ int ret; ++ ++ v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); ++ if (!v3d) ++ return -ENOMEM; ++ ++ v3d->pdev = pdev; ++ ++ v3d->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(v3d->regs)) ++ return PTR_ERR(v3d->regs); ++ ++ vc4->v3d = v3d; ++ ++ ret = vc4_v3d_set_power(vc4, true); ++ if (ret) ++ return ret; ++ ++ if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { ++ DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", ++ V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); ++ return -EINVAL; ++ } ++ ++ /* Reset the binner overflow address/size at setup, to be sure ++ * we don't reuse an old one. ++ */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ vc4_v3d_init_hw(drm); ++ ++ ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); ++ if (ret) { ++ DRM_ERROR("Failed to install IRQ handler\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void vc4_v3d_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); ++ ++ drm_irq_uninstall(drm); ++ ++ /* Disable the binner's overflow memory address, so the next ++ * driver probe (if any) doesn't try to reuse our old ++ * allocation. ++ */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ vc4_v3d_set_power(vc4, false); ++ ++ vc4->v3d = NULL; ++} ++ ++static const struct component_ops vc4_v3d_ops = { ++ .bind = vc4_v3d_bind, ++ .unbind = vc4_v3d_unbind, ++}; ++ ++static int vc4_v3d_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_v3d_ops); ++} ++ ++static int vc4_v3d_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_v3d_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_v3d_dt_match[] = { ++ { .compatible = "brcm,vc4-v3d" }, ++ {} ++}; ++ ++struct platform_driver vc4_v3d_driver = { ++ .probe = vc4_v3d_dev_probe, ++ .remove = vc4_v3d_dev_remove, ++ .driver = { ++ .name = "vc4_v3d", ++ .of_match_table = vc4_v3d_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +new file mode 100644 +index 0000000..0fb5b99 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -0,0 +1,900 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++/** ++ * Command list validator for VC4. ++ * ++ * The VC4 has no IOMMU between it and system memory. So, a user with ++ * access to execute command lists could escalate privilege by ++ * overwriting system memory (drawing to it as a framebuffer) or ++ * reading system memory it shouldn't (reading it as a texture, or ++ * uniform data, or vertex data). ++ * ++ * This validates command lists to ensure that all accesses are within ++ * the bounds of the GEM objects referenced. It explicitly whitelists ++ * packets, and looks at the offsets in any address fields to make ++ * sure they're constrained within the BOs they reference. ++ * ++ * Note that because of the validation that's happening anyway, this ++ * is where GEM relocation processing happens. ++ */ ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_packet.h" ++ ++#define VALIDATE_ARGS \ ++ struct vc4_exec_info *exec, \ ++ void *validated, \ ++ void *untrusted ++ ++/** Return the width in pixels of a 64-byte microtile. */ ++static uint32_t ++utile_width(int cpp) ++{ ++ switch (cpp) { ++ case 1: ++ case 2: ++ return 8; ++ case 4: ++ return 4; ++ case 8: ++ return 2; ++ default: ++ DRM_ERROR("unknown cpp: %d\n", cpp); ++ return 1; ++ } ++} ++ ++/** Return the height in pixels of a 64-byte microtile. */ ++static uint32_t ++utile_height(int cpp) ++{ ++ switch (cpp) { ++ case 1: ++ return 8; ++ case 2: ++ case 4: ++ case 8: ++ return 4; ++ default: ++ DRM_ERROR("unknown cpp: %d\n", cpp); ++ return 1; ++ } ++} ++ ++/** ++ * The texture unit decides what tiling format a particular miplevel is using ++ * this function, so we lay out our miptrees accordingly. ++ */ ++static bool ++size_is_lt(uint32_t width, uint32_t height, int cpp) ++{ ++ return (width <= 4 * utile_width(cpp) || ++ height <= 4 * utile_height(cpp)); ++} ++ ++struct drm_gem_cma_object * ++vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) ++{ ++ struct drm_gem_cma_object *obj; ++ struct vc4_bo *bo; ++ ++ if (hindex >= exec->bo_count) { ++ DRM_ERROR("BO index %d greater than BO count %d\n", ++ hindex, exec->bo_count); ++ return NULL; ++ } ++ obj = exec->bo[hindex]; ++ bo = to_vc4_bo(&obj->base); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("Trying to use shader BO as something other than " ++ "a shader\n"); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++static struct drm_gem_cma_object * ++vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index) ++{ ++ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]); ++} ++ ++static bool ++validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos) ++{ ++ /* Note that the untrusted pointer passed to these functions is ++ * incremented past the packet byte. ++ */ ++ return (untrusted - 1 == exec->bin_u + pos); ++} ++ ++static uint32_t ++gl_shader_rec_size(uint32_t pointer_bits) ++{ ++ uint32_t attribute_count = pointer_bits & 7; ++ bool extended = pointer_bits & 8; ++ ++ if (attribute_count == 0) ++ attribute_count = 8; ++ ++ if (extended) ++ return 100 + attribute_count * 4; ++ else ++ return 36 + attribute_count * 8; ++} ++ ++bool ++vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo, ++ uint32_t offset, uint8_t tiling_format, ++ uint32_t width, uint32_t height, uint8_t cpp) ++{ ++ uint32_t aligned_width, aligned_height, stride, size; ++ uint32_t utile_w = utile_width(cpp); ++ uint32_t utile_h = utile_height(cpp); ++ ++ /* The shaded vertex format stores signed 12.4 fixed point ++ * (-2048,2047) offsets from the viewport center, so we should ++ * never have a render target larger than 4096. The texture ++ * unit can only sample from 2048x2048, so it's even more ++ * restricted. This lets us avoid worrying about overflow in ++ * our math. ++ */ ++ if (width > 4096 || height > 4096) { ++ DRM_ERROR("Surface dimesions (%d,%d) too large", width, height); ++ return false; ++ } ++ ++ switch (tiling_format) { ++ case VC4_TILING_FORMAT_LINEAR: ++ aligned_width = round_up(width, utile_w); ++ aligned_height = height; ++ break; ++ case VC4_TILING_FORMAT_T: ++ aligned_width = round_up(width, utile_w * 8); ++ aligned_height = round_up(height, utile_h * 8); ++ break; ++ case VC4_TILING_FORMAT_LT: ++ aligned_width = round_up(width, utile_w); ++ aligned_height = round_up(height, utile_h); ++ break; ++ default: ++ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format); ++ return false; ++ } ++ ++ stride = aligned_width * cpp; ++ size = stride * aligned_height; ++ ++ if (size + offset < size || ++ size + offset > fbo->base.size) { ++ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n", ++ width, height, ++ aligned_width, aligned_height, ++ size, offset, fbo->base.size); ++ return false; ++ } ++ ++ return true; ++} ++ ++static int ++validate_flush(VALIDATE_ARGS) ++{ ++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) { ++ DRM_ERROR("Bin CL must end with VC4_PACKET_FLUSH\n"); ++ return -EINVAL; ++ } ++ exec->found_flush = true; ++ ++ return 0; ++} ++ ++static int ++validate_start_tile_binning(VALIDATE_ARGS) ++{ ++ if (exec->found_start_tile_binning_packet) { ++ DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n"); ++ return -EINVAL; ++ } ++ exec->found_start_tile_binning_packet = true; ++ ++ if (!exec->found_tile_binning_mode_config_packet) { ++ DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++validate_increment_semaphore(VALIDATE_ARGS) ++{ ++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) { ++ DRM_ERROR("Bin CL must end with " ++ "VC4_PACKET_INCREMENT_SEMAPHORE\n"); ++ return -EINVAL; ++ } ++ exec->found_increment_semaphore_packet = true; ++ ++ return 0; ++} ++ ++static int ++validate_indexed_prim_list(VALIDATE_ARGS) ++{ ++ struct drm_gem_cma_object *ib; ++ uint32_t length = *(uint32_t *)(untrusted + 1); ++ uint32_t offset = *(uint32_t *)(untrusted + 5); ++ uint32_t max_index = *(uint32_t *)(untrusted + 9); ++ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1; ++ struct vc4_shader_state *shader_state; ++ ++ /* Check overflow condition */ ++ if (exec->shader_state_count == 0) { ++ DRM_ERROR("shader state must precede primitives\n"); ++ return -EINVAL; ++ } ++ shader_state = &exec->shader_state[exec->shader_state_count - 1]; ++ ++ if (max_index > shader_state->max_index) ++ shader_state->max_index = max_index; ++ ++ ib = vc4_use_handle(exec, 0); ++ if (!ib) ++ return -EINVAL; ++ ++ if (offset > ib->base.size || ++ (ib->base.size - offset) / index_size < length) { ++ DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n", ++ offset, length, index_size, ib->base.size); ++ return -EINVAL; ++ } ++ ++ *(uint32_t *)(validated + 5) = ib->paddr + offset; ++ ++ return 0; ++} ++ ++static int ++validate_gl_array_primitive(VALIDATE_ARGS) ++{ ++ uint32_t length = *(uint32_t *)(untrusted + 1); ++ uint32_t base_index = *(uint32_t *)(untrusted + 5); ++ uint32_t max_index; ++ struct vc4_shader_state *shader_state; ++ ++ /* Check overflow condition */ ++ if (exec->shader_state_count == 0) { ++ DRM_ERROR("shader state must precede primitives\n"); ++ return -EINVAL; ++ } ++ shader_state = &exec->shader_state[exec->shader_state_count - 1]; ++ ++ if (length + base_index < length) { ++ DRM_ERROR("primitive vertex count overflow\n"); ++ return -EINVAL; ++ } ++ max_index = length + base_index - 1; ++ ++ if (max_index > shader_state->max_index) ++ shader_state->max_index = max_index; ++ ++ return 0; ++} ++ ++static int ++validate_gl_shader_state(VALIDATE_ARGS) ++{ ++ uint32_t i = exec->shader_state_count++; ++ ++ if (i >= exec->shader_state_size) { ++ DRM_ERROR("More requests for shader states than declared\n"); ++ return -EINVAL; ++ } ++ ++ exec->shader_state[i].addr = *(uint32_t *)untrusted; ++ exec->shader_state[i].max_index = 0; ++ ++ if (exec->shader_state[i].addr & ~0xf) { ++ DRM_ERROR("high bits set in GL shader rec reference\n"); ++ return -EINVAL; ++ } ++ ++ *(uint32_t *)validated = (exec->shader_rec_p + ++ exec->shader_state[i].addr); ++ ++ exec->shader_rec_p += ++ roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16); ++ ++ return 0; ++} ++ ++static int ++validate_tile_binning_config(VALIDATE_ARGS) ++{ ++ struct drm_device *dev = exec->exec_bo->base.dev; ++ struct vc4_bo *tile_bo; ++ uint8_t flags; ++ uint32_t tile_state_size, tile_alloc_size; ++ uint32_t tile_count; ++ ++ if (exec->found_tile_binning_mode_config_packet) { ++ DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); ++ return -EINVAL; ++ } ++ exec->found_tile_binning_mode_config_packet = true; ++ ++ exec->bin_tiles_x = *(uint8_t *)(untrusted + 12); ++ exec->bin_tiles_y = *(uint8_t *)(untrusted + 13); ++ tile_count = exec->bin_tiles_x * exec->bin_tiles_y; ++ flags = *(uint8_t *)(untrusted + 14); ++ ++ if (exec->bin_tiles_x == 0 || ++ exec->bin_tiles_y == 0) { ++ DRM_ERROR("Tile binning config of %dx%d too small\n", ++ exec->bin_tiles_x, exec->bin_tiles_y); ++ return -EINVAL; ++ } ++ ++ if (flags & (VC4_BIN_CONFIG_DB_NON_MS | ++ VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) { ++ DRM_ERROR("unsupported binning config flags 0x%02x\n", flags); ++ return -EINVAL; ++ } ++ ++ /* The tile state data array is 48 bytes per tile, and we put it at ++ * the start of a BO containing both it and the tile alloc. ++ */ ++ tile_state_size = 48 * tile_count; ++ ++ /* Since the tile alloc array will follow us, align. */ ++ exec->tile_alloc_offset = roundup(tile_state_size, 4096); ++ ++ *(uint8_t *)(validated + 14) = ++ ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | ++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) | ++ VC4_BIN_CONFIG_AUTO_INIT_TSDA | ++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32, ++ VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) | ++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, ++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); ++ ++ /* Initial block size. */ ++ tile_alloc_size = 32 * tile_count; ++ ++ /* ++ * The initial allocation gets rounded to the next 256 bytes before ++ * the hardware starts fulfilling further allocations. ++ */ ++ tile_alloc_size = roundup(tile_alloc_size, 256); ++ ++ /* Add space for the extra allocations. This is what gets used first, ++ * before overflow memory. It must have at least 4096 bytes, but we ++ * want to avoid overflow memory usage if possible. ++ */ ++ tile_alloc_size += 1024 * 1024; ++ ++ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, ++ true); ++ exec->tile_bo = &tile_bo->base; ++ if (!exec->tile_bo) ++ return -ENOMEM; ++ list_add_tail(&tile_bo->unref_head, &exec->unref_list); ++ ++ /* tile alloc address. */ ++ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr + ++ exec->tile_alloc_offset); ++ /* tile alloc size. */ ++ *(uint32_t *)(validated + 4) = tile_alloc_size; ++ /* tile state address. */ ++ *(uint32_t *)(validated + 8) = exec->tile_bo->paddr; ++ ++ return 0; ++} ++ ++static int ++validate_gem_handles(VALIDATE_ARGS) ++{ ++ memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index)); ++ return 0; ++} ++ ++#define VC4_DEFINE_PACKET(packet, func) \ ++ [packet] = { packet ## _SIZE, #packet, func } ++ ++static const struct cmd_info { ++ uint16_t len; ++ const char *name; ++ int (*func)(struct vc4_exec_info *exec, void *validated, ++ void *untrusted); ++} cmd_info[] = { ++ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, ++ validate_start_tile_binning), ++ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, ++ validate_increment_semaphore), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, ++ validate_indexed_prim_list), ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, ++ validate_gl_array_primitive), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL), ++ /* Note: The docs say this was also 105, but it was 106 in the ++ * initial userland code drop. ++ */ ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, ++ validate_tile_binning_config), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles), ++}; ++ ++int ++vc4_validate_bin_cl(struct drm_device *dev, ++ void *validated, ++ void *unvalidated, ++ struct vc4_exec_info *exec) ++{ ++ uint32_t len = exec->args->bin_cl_size; ++ uint32_t dst_offset = 0; ++ uint32_t src_offset = 0; ++ ++ while (src_offset < len) { ++ void *dst_pkt = validated + dst_offset; ++ void *src_pkt = unvalidated + src_offset; ++ u8 cmd = *(uint8_t *)src_pkt; ++ const struct cmd_info *info; ++ ++ if (cmd >= ARRAY_SIZE(cmd_info)) { ++ DRM_ERROR("0x%08x: packet %d out of bounds\n", ++ src_offset, cmd); ++ return -EINVAL; ++ } ++ ++ info = &cmd_info[cmd]; ++ if (!info->name) { ++ DRM_ERROR("0x%08x: packet %d invalid\n", ++ src_offset, cmd); ++ return -EINVAL; ++ } ++ ++ if (src_offset + info->len > len) { ++ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x " ++ "exceeds bounds (0x%08x)\n", ++ src_offset, cmd, info->name, info->len, ++ src_offset + len); ++ return -EINVAL; ++ } ++ ++ if (cmd != VC4_PACKET_GEM_HANDLES) ++ memcpy(dst_pkt, src_pkt, info->len); ++ ++ if (info->func && info->func(exec, ++ dst_pkt + 1, ++ src_pkt + 1)) { ++ DRM_ERROR("0x%08x: packet %d (%s) failed to validate\n", ++ src_offset, cmd, info->name); ++ return -EINVAL; ++ } ++ ++ src_offset += info->len; ++ /* GEM handle loading doesn't produce HW packets. */ ++ if (cmd != VC4_PACKET_GEM_HANDLES) ++ dst_offset += info->len; ++ ++ /* When the CL hits halt, it'll stop reading anything else. */ ++ if (cmd == VC4_PACKET_HALT) ++ break; ++ } ++ ++ exec->ct0ea = exec->ct0ca + dst_offset; ++ ++ if (!exec->found_start_tile_binning_packet) { ++ DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n"); ++ return -EINVAL; ++ } ++ ++ /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The ++ * semaphore is used to trigger the render CL to start up, and the ++ * FLUSH is what caps the bin lists with ++ * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main ++ * render CL when they get called to) and actually triggers the queued ++ * semaphore increment. ++ */ ++ if (!exec->found_increment_semaphore_packet || !exec->found_flush) { ++ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + " ++ "VC4_PACKET_FLUSH\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static bool ++reloc_tex(struct vc4_exec_info *exec, ++ void *uniform_data_u, ++ struct vc4_texture_sample_info *sample, ++ uint32_t texture_handle_index) ++ ++{ ++ struct drm_gem_cma_object *tex; ++ uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); ++ uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]); ++ uint32_t p2 = (sample->p_offset[2] != ~0 ? ++ *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0); ++ uint32_t p3 = (sample->p_offset[3] != ~0 ? ++ *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0); ++ uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0]; ++ uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK; ++ uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS); ++ uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH); ++ uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT); ++ uint32_t cpp, tiling_format, utile_w, utile_h; ++ uint32_t i; ++ uint32_t cube_map_stride = 0; ++ enum vc4_texture_data_type type; ++ ++ tex = vc4_use_bo(exec, texture_handle_index); ++ if (!tex) ++ return false; ++ ++ if (sample->is_direct) { ++ uint32_t remaining_size = tex->base.size - p0; ++ ++ if (p0 > tex->base.size - 4) { ++ DRM_ERROR("UBO offset greater than UBO size\n"); ++ goto fail; ++ } ++ if (p1 > remaining_size - 4) { ++ DRM_ERROR("UBO clamp would allow reads " ++ "outside of UBO\n"); ++ goto fail; ++ } ++ *validated_p0 = tex->paddr + p0; ++ return true; ++ } ++ ++ if (width == 0) ++ width = 2048; ++ if (height == 0) ++ height = 2048; ++ ++ if (p0 & VC4_TEX_P0_CMMODE_MASK) { ++ if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) == ++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) ++ cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK; ++ if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) == ++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) { ++ if (cube_map_stride) { ++ DRM_ERROR("Cube map stride set twice\n"); ++ goto fail; ++ } ++ ++ cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK; ++ } ++ if (!cube_map_stride) { ++ DRM_ERROR("Cube map stride not set\n"); ++ goto fail; ++ } ++ } ++ ++ type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) | ++ (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4)); ++ ++ switch (type) { ++ case VC4_TEXTURE_TYPE_RGBA8888: ++ case VC4_TEXTURE_TYPE_RGBX8888: ++ case VC4_TEXTURE_TYPE_RGBA32R: ++ cpp = 4; ++ break; ++ case VC4_TEXTURE_TYPE_RGBA4444: ++ case VC4_TEXTURE_TYPE_RGBA5551: ++ case VC4_TEXTURE_TYPE_RGB565: ++ case VC4_TEXTURE_TYPE_LUMALPHA: ++ case VC4_TEXTURE_TYPE_S16F: ++ case VC4_TEXTURE_TYPE_S16: ++ cpp = 2; ++ break; ++ case VC4_TEXTURE_TYPE_LUMINANCE: ++ case VC4_TEXTURE_TYPE_ALPHA: ++ case VC4_TEXTURE_TYPE_S8: ++ cpp = 1; ++ break; ++ case VC4_TEXTURE_TYPE_ETC1: ++ case VC4_TEXTURE_TYPE_BW1: ++ case VC4_TEXTURE_TYPE_A4: ++ case VC4_TEXTURE_TYPE_A1: ++ case VC4_TEXTURE_TYPE_RGBA64: ++ case VC4_TEXTURE_TYPE_YUV422R: ++ default: ++ DRM_ERROR("Texture format %d unsupported\n", type); ++ goto fail; ++ } ++ utile_w = utile_width(cpp); ++ utile_h = utile_height(cpp); ++ ++ if (type == VC4_TEXTURE_TYPE_RGBA32R) { ++ tiling_format = VC4_TILING_FORMAT_LINEAR; ++ } else { ++ if (size_is_lt(width, height, cpp)) ++ tiling_format = VC4_TILING_FORMAT_LT; ++ else ++ tiling_format = VC4_TILING_FORMAT_T; ++ } ++ ++ if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5, ++ tiling_format, width, height, cpp)) { ++ goto fail; ++ } ++ ++ /* The mipmap levels are stored before the base of the texture. Make ++ * sure there is actually space in the BO. ++ */ ++ for (i = 1; i <= miplevels; i++) { ++ uint32_t level_width = max(width >> i, 1u); ++ uint32_t level_height = max(height >> i, 1u); ++ uint32_t aligned_width, aligned_height; ++ uint32_t level_size; ++ ++ /* Once the levels get small enough, they drop from T to LT. */ ++ if (tiling_format == VC4_TILING_FORMAT_T && ++ size_is_lt(level_width, level_height, cpp)) { ++ tiling_format = VC4_TILING_FORMAT_LT; ++ } ++ ++ switch (tiling_format) { ++ case VC4_TILING_FORMAT_T: ++ aligned_width = round_up(level_width, utile_w * 8); ++ aligned_height = round_up(level_height, utile_h * 8); ++ break; ++ case VC4_TILING_FORMAT_LT: ++ aligned_width = round_up(level_width, utile_w); ++ aligned_height = round_up(level_height, utile_h); ++ break; ++ default: ++ aligned_width = round_up(level_width, utile_w); ++ aligned_height = level_height; ++ break; ++ } ++ ++ level_size = aligned_width * cpp * aligned_height; ++ ++ if (offset < level_size) { ++ DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db " ++ "overflowed buffer bounds (offset %d)\n", ++ i, level_width, level_height, ++ aligned_width, aligned_height, ++ level_size, offset); ++ goto fail; ++ } ++ ++ offset -= level_size; ++ } ++ ++ *validated_p0 = tex->paddr + p0; ++ ++ return true; ++ fail: ++ DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0); ++ DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1); ++ DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2); ++ DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3); ++ return false; ++} ++ ++static int ++validate_gl_shader_rec(struct drm_device *dev, ++ struct vc4_exec_info *exec, ++ struct vc4_shader_state *state) ++{ ++ uint32_t *src_handles; ++ void *pkt_u, *pkt_v; ++ static const uint32_t shader_reloc_offsets[] = { ++ 4, /* fs */ ++ 16, /* vs */ ++ 28, /* cs */ ++ }; ++ uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); ++ struct drm_gem_cma_object *bo[shader_reloc_count + 8]; ++ uint32_t nr_attributes, nr_relocs, packet_size; ++ int i; ++ ++ nr_attributes = state->addr & 0x7; ++ if (nr_attributes == 0) ++ nr_attributes = 8; ++ packet_size = gl_shader_rec_size(state->addr); ++ ++ nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes; ++ if (nr_relocs * 4 > exec->shader_rec_size) { ++ DRM_ERROR("overflowed shader recs reading %d handles " ++ "from %d bytes left\n", ++ nr_relocs, exec->shader_rec_size); ++ return -EINVAL; ++ } ++ src_handles = exec->shader_rec_u; ++ exec->shader_rec_u += nr_relocs * 4; ++ exec->shader_rec_size -= nr_relocs * 4; ++ ++ if (packet_size > exec->shader_rec_size) { ++ DRM_ERROR("overflowed shader recs copying %db packet " ++ "from %d bytes left\n", ++ packet_size, exec->shader_rec_size); ++ return -EINVAL; ++ } ++ pkt_u = exec->shader_rec_u; ++ pkt_v = exec->shader_rec_v; ++ memcpy(pkt_v, pkt_u, packet_size); ++ exec->shader_rec_u += packet_size; ++ /* Shader recs have to be aligned to 16 bytes (due to the attribute ++ * flags being in the low bytes), so round the next validated shader ++ * rec address up. This should be safe, since we've got so many ++ * relocations in a shader rec packet. ++ */ ++ BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4); ++ 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]); ++ return -EINVAL; ++ } ++ ++ bo[i] = exec->bo[src_handles[i]]; ++ if (!bo[i]) ++ return -EINVAL; ++ } ++ for (i = shader_reloc_count; i < nr_relocs; i++) { ++ bo[i] = vc4_use_bo(exec, src_handles[i]); ++ if (!bo[i]) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < shader_reloc_count; i++) { ++ struct vc4_validated_shader_info *validated_shader; ++ uint32_t o = shader_reloc_offsets[i]; ++ uint32_t src_offset = *(uint32_t *)(pkt_u + o); ++ uint32_t *texture_handles_u; ++ void *uniform_data_u; ++ uint32_t tex; ++ ++ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset; ++ ++ if (src_offset != 0) { ++ DRM_ERROR("Shaders must be at offset 0 of " ++ "the BO.\n"); ++ return -EINVAL; ++ } ++ ++ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader; ++ if (!validated_shader) ++ return -EINVAL; ++ ++ if (validated_shader->uniforms_src_size > ++ exec->uniforms_size) { ++ DRM_ERROR("Uniforms src buffer overflow\n"); ++ return -EINVAL; ++ } ++ ++ texture_handles_u = exec->uniforms_u; ++ uniform_data_u = (texture_handles_u + ++ validated_shader->num_texture_samples); ++ ++ memcpy(exec->uniforms_v, uniform_data_u, ++ validated_shader->uniforms_size); ++ ++ for (tex = 0; ++ tex < validated_shader->num_texture_samples; ++ tex++) { ++ if (!reloc_tex(exec, ++ uniform_data_u, ++ &validated_shader->texture_samples[tex], ++ texture_handles_u[tex])) { ++ return -EINVAL; ++ } ++ } ++ ++ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p; ++ ++ exec->uniforms_u += validated_shader->uniforms_src_size; ++ exec->uniforms_v += validated_shader->uniforms_size; ++ exec->uniforms_p += validated_shader->uniforms_size; ++ } ++ ++ for (i = 0; i < nr_attributes; i++) { ++ struct drm_gem_cma_object *vbo = ++ bo[ARRAY_SIZE(shader_reloc_offsets) + i]; ++ uint32_t o = 36 + i * 8; ++ uint32_t offset = *(uint32_t *)(pkt_u + o + 0); ++ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1; ++ uint32_t stride = *(uint8_t *)(pkt_u + o + 5); ++ uint32_t max_index; ++ ++ if (state->addr & 0x8) ++ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; ++ ++ if (vbo->base.size < offset || ++ vbo->base.size - offset < attr_size) { ++ DRM_ERROR("BO offset overflow (%d + %d > %d)\n", ++ offset, attr_size, vbo->base.size); ++ return -EINVAL; ++ } ++ ++ if (stride != 0) { ++ max_index = ((vbo->base.size - offset - attr_size) / ++ stride); ++ if (state->max_index > max_index) { ++ DRM_ERROR("primitives use index %d out of " ++ "supplied %d\n", ++ state->max_index, max_index); ++ return -EINVAL; ++ } ++ } ++ ++ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset; ++ } ++ ++ return 0; ++} ++ ++int ++vc4_validate_shader_recs(struct drm_device *dev, ++ struct vc4_exec_info *exec) ++{ ++ uint32_t i; ++ int ret = 0; ++ ++ for (i = 0; i < exec->shader_state_count; i++) { ++ ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +new file mode 100644 +index 0000000..f67124b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -0,0 +1,513 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Shader validator for VC4. ++ * ++ * The VC4 has no IOMMU between it and system memory, so a user with ++ * access to execute shaders could escalate privilege by overwriting ++ * system memory (using the VPM write address register in the ++ * general-purpose DMA mode) or reading system memory it shouldn't ++ * (reading it as a texture, or uniform data, or vertex data). ++ * ++ * This walks over a shader BO, ensuring that its accesses are ++ * appropriately bounded, and recording how many texture accesses are ++ * made and where so that we can do relocations for them in the ++ * uniform stream. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_qpu_defines.h" ++ ++struct vc4_shader_validation_state { ++ struct vc4_texture_sample_info tmu_setup[2]; ++ int tmu_write_count[2]; ++ ++ /* For registers that were last written to by a MIN instruction with ++ * one argument being a uniform, the address of the uniform. ++ * Otherwise, ~0. ++ * ++ * This is used for the validation of direct address memory reads. ++ */ ++ uint32_t live_min_clamp_offsets[32 + 32 + 4]; ++ bool live_max_clamp_regs[32 + 32 + 4]; ++}; ++ ++static uint32_t ++waddr_to_live_reg_index(uint32_t waddr, bool is_b) ++{ ++ if (waddr < 32) { ++ if (is_b) ++ return 32 + waddr; ++ else ++ return waddr; ++ } else if (waddr <= QPU_W_ACC3) { ++ return 64 + waddr - QPU_W_ACC0; ++ } else { ++ return ~0; ++ } ++} ++ ++static uint32_t ++raddr_add_a_to_live_reg_index(uint64_t inst) ++{ ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ ++ if (add_a == QPU_MUX_A) ++ return raddr_a; ++ else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) ++ return 32 + raddr_b; ++ else if (add_a <= QPU_MUX_R3) ++ return 64 + add_a; ++ else ++ return ~0; ++} ++ ++static bool ++is_tmu_submit(uint32_t waddr) ++{ ++ return (waddr == QPU_W_TMU0_S || ++ waddr == QPU_W_TMU1_S); ++} ++ ++static bool ++is_tmu_write(uint32_t waddr) ++{ ++ return (waddr >= QPU_W_TMU0_S && ++ waddr <= QPU_W_TMU1_B); ++} ++ ++static bool ++record_texture_sample(struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ int tmu) ++{ ++ uint32_t s = validated_shader->num_texture_samples; ++ int i; ++ struct vc4_texture_sample_info *temp_samples; ++ ++ temp_samples = krealloc(validated_shader->texture_samples, ++ (s + 1) * sizeof(*temp_samples), ++ GFP_KERNEL); ++ if (!temp_samples) ++ return false; ++ ++ memcpy(&temp_samples[s], ++ &validation_state->tmu_setup[tmu], ++ sizeof(*temp_samples)); ++ ++ validated_shader->num_texture_samples = s + 1; ++ validated_shader->texture_samples = temp_samples; ++ ++ for (i = 0; i < 4; i++) ++ validation_state->tmu_setup[tmu].p_offset[i] = ~0; ++ ++ return true; ++} ++ ++static bool ++check_tmu_write(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ bool is_mul) ++{ ++ uint32_t waddr = (is_mul ? ++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) : ++ QPU_GET_FIELD(inst, QPU_WADDR_ADD)); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ int tmu = waddr > QPU_W_TMU0_B; ++ bool submit = is_tmu_submit(waddr); ++ bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0; ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ if (is_direct) { ++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B); ++ uint32_t clamp_reg, clamp_offset; ++ ++ if (sig == QPU_SIG_SMALL_IMM) { ++ DRM_ERROR("direct TMU read used small immediate\n"); ++ return false; ++ } ++ ++ /* Make sure that this texture load is an add of the base ++ * address of the UBO to a clamped offset within the UBO. ++ */ ++ if (is_mul || ++ QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) { ++ DRM_ERROR("direct TMU load wasn't an add\n"); ++ return false; ++ } ++ ++ /* We assert that the the clamped address is the first ++ * argument, and the UBO base address is the second argument. ++ * This is arbitrary, but simpler than supporting flipping the ++ * two either way. ++ */ ++ clamp_reg = raddr_add_a_to_live_reg_index(inst); ++ if (clamp_reg == ~0) { ++ DRM_ERROR("direct TMU load wasn't clamped\n"); ++ return false; ++ } ++ ++ clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg]; ++ if (clamp_offset == ~0) { ++ DRM_ERROR("direct TMU load wasn't clamped\n"); ++ return false; ++ } ++ ++ /* Store the clamp value's offset in p1 (see reloc_tex() in ++ * vc4_validate.c). ++ */ ++ validation_state->tmu_setup[tmu].p_offset[1] = ++ clamp_offset; ++ ++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) && ++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) { ++ DRM_ERROR("direct TMU load didn't add to a uniform\n"); ++ return false; ++ } ++ ++ validation_state->tmu_setup[tmu].is_direct = true; ++ } else { ++ if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM && ++ raddr_b == QPU_R_UNIF)) { ++ DRM_ERROR("uniform read in the same instruction as " ++ "texture setup.\n"); ++ return false; ++ } ++ } ++ ++ if (validation_state->tmu_write_count[tmu] >= 4) { ++ DRM_ERROR("TMU%d got too many parameters before dispatch\n", ++ tmu); ++ return false; ++ } ++ validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] = ++ validated_shader->uniforms_size; ++ validation_state->tmu_write_count[tmu]++; ++ /* Since direct uses a RADDR uniform reference, it will get counted in ++ * check_instruction_reads() ++ */ ++ if (!is_direct) ++ validated_shader->uniforms_size += 4; ++ ++ if (submit) { ++ if (!record_texture_sample(validated_shader, ++ validation_state, tmu)) { ++ return false; ++ } ++ ++ validation_state->tmu_write_count[tmu] = 0; ++ } ++ ++ return true; ++} ++ ++static bool ++check_reg_write(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ bool is_mul) ++{ ++ uint32_t waddr = (is_mul ? ++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) : ++ QPU_GET_FIELD(inst, QPU_WADDR_ADD)); ++ ++ switch (waddr) { ++ case QPU_W_UNIFORMS_ADDRESS: ++ /* XXX: We'll probably need to support this for reladdr, but ++ * it's definitely a security-related one. ++ */ ++ DRM_ERROR("uniforms address load unsupported\n"); ++ return false; ++ ++ case QPU_W_TLB_COLOR_MS: ++ case QPU_W_TLB_COLOR_ALL: ++ case QPU_W_TLB_Z: ++ /* These only interact with the tile buffer, not main memory, ++ * so they're safe. ++ */ ++ return true; ++ ++ case QPU_W_TMU0_S: ++ case QPU_W_TMU0_T: ++ case QPU_W_TMU0_R: ++ case QPU_W_TMU0_B: ++ case QPU_W_TMU1_S: ++ case QPU_W_TMU1_T: ++ case QPU_W_TMU1_R: ++ case QPU_W_TMU1_B: ++ return check_tmu_write(inst, validated_shader, validation_state, ++ is_mul); ++ ++ case QPU_W_HOST_INT: ++ case QPU_W_TMU_NOSWAP: ++ case QPU_W_TLB_ALPHA_MASK: ++ case QPU_W_MUTEX_RELEASE: ++ /* XXX: I haven't thought about these, so don't support them ++ * for now. ++ */ ++ DRM_ERROR("Unsupported waddr %d\n", waddr); ++ return false; ++ ++ case QPU_W_VPM_ADDR: ++ DRM_ERROR("General VPM DMA unsupported\n"); ++ return false; ++ ++ case QPU_W_VPM: ++ case QPU_W_VPMVCD_SETUP: ++ /* We allow VPM setup in general, even including VPM DMA ++ * configuration setup, because the (unsafe) DMA can only be ++ * triggered by QPU_W_VPM_ADDR writes. ++ */ ++ return true; ++ ++ case QPU_W_TLB_STENCIL_SETUP: ++ return true; ++ } ++ ++ return true; ++} ++ ++static void ++track_live_clamps(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state) ++{ ++ uint32_t op_add = QPU_GET_FIELD(inst, QPU_OP_ADD); ++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); ++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); ++ uint32_t cond_add = QPU_GET_FIELD(inst, QPU_COND_ADD); ++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A); ++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ bool ws = inst & QPU_WS; ++ uint32_t lri_add_a, lri_add, lri_mul; ++ bool add_a_is_min_0; ++ ++ /* Check whether OP_ADD's A argumennt comes from a live MAX(x, 0), ++ * before we clear previous live state. ++ */ ++ lri_add_a = raddr_add_a_to_live_reg_index(inst); ++ add_a_is_min_0 = (lri_add_a != ~0 && ++ validation_state->live_max_clamp_regs[lri_add_a]); ++ ++ /* Clear live state for registers written by our instruction. */ ++ lri_add = waddr_to_live_reg_index(waddr_add, ws); ++ lri_mul = waddr_to_live_reg_index(waddr_mul, !ws); ++ if (lri_mul != ~0) { ++ validation_state->live_max_clamp_regs[lri_mul] = false; ++ validation_state->live_min_clamp_offsets[lri_mul] = ~0; ++ } ++ if (lri_add != ~0) { ++ validation_state->live_max_clamp_regs[lri_add] = false; ++ validation_state->live_min_clamp_offsets[lri_add] = ~0; ++ } else { ++ /* Nothing further to do for live tracking, since only ADDs ++ * generate new live clamp registers. ++ */ ++ return; ++ } ++ ++ /* Now, handle remaining live clamp tracking for the ADD operation. */ ++ ++ if (cond_add != QPU_COND_ALWAYS) ++ return; ++ ++ if (op_add == QPU_A_MAX) { ++ /* Track live clamps of a value to a minimum of 0 (in either ++ * arg). ++ */ ++ if (sig != QPU_SIG_SMALL_IMM || raddr_b != 0 || ++ (add_a != QPU_MUX_B && add_b != QPU_MUX_B)) { ++ return; ++ } ++ ++ validation_state->live_max_clamp_regs[lri_add] = true; ++ } else if (op_add == QPU_A_MIN) { ++ /* Track live clamps of a value clamped to a minimum of 0 and ++ * a maximum of some uniform's offset. ++ */ ++ if (!add_a_is_min_0) ++ return; ++ ++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) && ++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF && ++ sig != QPU_SIG_SMALL_IMM)) { ++ return; ++ } ++ ++ validation_state->live_min_clamp_offsets[lri_add] = ++ validated_shader->uniforms_size; ++ } ++} ++ ++static bool ++check_instruction_writes(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state) ++{ ++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); ++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); ++ bool ok; ++ ++ if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) { ++ DRM_ERROR("ADD and MUL both set up textures\n"); ++ return false; ++ } ++ ++ ok = (check_reg_write(inst, validated_shader, validation_state, ++ false) && ++ check_reg_write(inst, validated_shader, validation_state, ++ true)); ++ ++ track_live_clamps(inst, validated_shader, validation_state); ++ ++ return ok; ++} ++ ++static bool ++check_instruction_reads(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader) ++{ ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ if (raddr_a == QPU_R_UNIF || ++ (raddr_b == QPU_R_UNIF && sig != QPU_SIG_SMALL_IMM)) { ++ /* This can't overflow the uint32_t, because we're reading 8 ++ * bytes of instruction to increment by 4 here, so we'd ++ * already be OOM. ++ */ ++ validated_shader->uniforms_size += 4; ++ } ++ ++ return true; ++} ++ ++struct vc4_validated_shader_info * ++vc4_validate_shader(struct drm_gem_cma_object *shader_obj) ++{ ++ bool found_shader_end = false; ++ int shader_end_ip = 0; ++ uint32_t ip, max_ip; ++ uint64_t *shader; ++ struct vc4_validated_shader_info *validated_shader; ++ struct vc4_shader_validation_state validation_state; ++ int i; ++ ++ memset(&validation_state, 0, sizeof(validation_state)); ++ ++ for (i = 0; i < 8; i++) ++ validation_state.tmu_setup[i / 4].p_offset[i % 4] = ~0; ++ for (i = 0; i < ARRAY_SIZE(validation_state.live_min_clamp_offsets); i++) ++ validation_state.live_min_clamp_offsets[i] = ~0; ++ ++ shader = shader_obj->vaddr; ++ max_ip = shader_obj->base.size / sizeof(uint64_t); ++ ++ validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL); ++ if (!validated_shader) ++ return NULL; ++ ++ for (ip = 0; ip < max_ip; ip++) { ++ uint64_t inst = shader[ip]; ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ switch (sig) { ++ case QPU_SIG_NONE: ++ case QPU_SIG_WAIT_FOR_SCOREBOARD: ++ case QPU_SIG_SCOREBOARD_UNLOCK: ++ case QPU_SIG_COLOR_LOAD: ++ case QPU_SIG_LOAD_TMU0: ++ case QPU_SIG_LOAD_TMU1: ++ case QPU_SIG_PROG_END: ++ case QPU_SIG_SMALL_IMM: ++ if (!check_instruction_writes(inst, validated_shader, ++ &validation_state)) { ++ DRM_ERROR("Bad write at ip %d\n", ip); ++ goto fail; ++ } ++ ++ if (!check_instruction_reads(inst, validated_shader)) ++ goto fail; ++ ++ if (sig == QPU_SIG_PROG_END) { ++ found_shader_end = true; ++ shader_end_ip = ip; ++ } ++ ++ break; ++ ++ case QPU_SIG_LOAD_IMM: ++ if (!check_instruction_writes(inst, validated_shader, ++ &validation_state)) { ++ DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip); ++ goto fail; ++ } ++ break; ++ ++ default: ++ DRM_ERROR("Unsupported QPU signal %d at " ++ "instruction %d\n", sig, ip); ++ goto fail; ++ } ++ ++ /* 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 (ip == max_ip) { ++ DRM_ERROR("shader failed to terminate before " ++ "shader BO end at %zd\n", ++ shader_obj->base.size); ++ goto fail; ++ } ++ ++ /* Again, no chance of integer overflow here because the worst case ++ * scenario is 8 bytes of uniforms plus handles per 8-byte ++ * instruction. ++ */ ++ validated_shader->uniforms_src_size = ++ (validated_shader->uniforms_size + ++ 4 * validated_shader->num_texture_samples); ++ ++ return validated_shader; ++ ++fail: ++ if (validated_shader) { ++ kfree(validated_shader->texture_samples); ++ kfree(validated_shader); ++ } ++ return NULL; ++} +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +new file mode 100644 +index 0000000..eeb37e3 +--- /dev/null ++++ b/include/uapi/drm/vc4_drm.h +@@ -0,0 +1,279 @@ ++/* ++ * Copyright © 2014-2015 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef _UAPI_VC4_DRM_H_ ++#define _UAPI_VC4_DRM_H_ ++ ++#include "drm.h" ++ ++#define DRM_VC4_SUBMIT_CL 0x00 ++#define DRM_VC4_WAIT_SEQNO 0x01 ++#define DRM_VC4_WAIT_BO 0x02 ++#define DRM_VC4_CREATE_BO 0x03 ++#define DRM_VC4_MMAP_BO 0x04 ++#define DRM_VC4_CREATE_SHADER_BO 0x05 ++#define DRM_VC4_GET_HANG_STATE 0x06 ++ ++#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) ++#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) ++#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo) ++#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo) ++#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo) ++#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo) ++#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state) ++ ++struct drm_vc4_submit_rcl_surface { ++ __u32 hindex; /* Handle index, or ~0 if not present. */ ++ __u32 offset; /* Offset to start of buffer. */ ++ /* ++ * Bits for either render config (color_write) or load/store packet. ++ * Bits should all be 0 for MSAA load/stores. ++ */ ++ __u16 bits; ++ ++#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0) ++ __u16 flags; ++}; ++ ++/** ++ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D ++ * engine. ++ * ++ * Drivers typically use GPU BOs to store batchbuffers / command lists and ++ * their associated state. However, because the VC4 lacks an MMU, we have to ++ * do validation of memory accesses by the GPU commands. If we were to store ++ * our commands in BOs, we'd need to do uncached readback from them to do the ++ * validation process, which is too expensive. Instead, userspace accumulates ++ * commands and associated state in plain memory, then the kernel copies the ++ * data to its own address space, and then validates and stores it in a GPU ++ * BO. ++ */ ++struct drm_vc4_submit_cl { ++ /* Pointer to the binner command list. ++ * ++ * This is the first set of commands executed, which runs the ++ * coordinate shader to determine where primitives land on the screen, ++ * then writes out the state updates and draw calls necessary per tile ++ * to the tile allocation BO. ++ */ ++ __u64 bin_cl; ++ ++ /* Pointer to the shader records. ++ * ++ * Shader records are the structures read by the hardware that contain ++ * pointers to uniforms, shaders, and vertex attributes. The ++ * reference to the shader record has enough information to determine ++ * how many pointers are necessary (fixed number for shaders/uniforms, ++ * and an attribute count), so those BO indices into bo_handles are ++ * just stored as __u32s before each shader record passed in. ++ */ ++ __u64 shader_rec; ++ ++ /* Pointer to uniform data and texture handles for the textures ++ * referenced by the shader. ++ * ++ * For each shader state record, there is a set of uniform data in the ++ * order referenced by the record (FS, VS, then CS). Each set of ++ * uniform data has a __u32 index into bo_handles per texture ++ * sample operation, in the order the QPU_W_TMUn_S writes appear in ++ * the program. Following the texture BO handle indices is the actual ++ * uniform data. ++ * ++ * The individual uniform state blocks don't have sizes passed in, ++ * because the kernel has to determine the sizes anyway during shader ++ * code validation. ++ */ ++ __u64 uniforms; ++ __u64 bo_handles; ++ ++ /* Size in bytes of the binner command list. */ ++ __u32 bin_cl_size; ++ /* Size in bytes of the set of shader records. */ ++ __u32 shader_rec_size; ++ /* Number of shader records. ++ * ++ * This could just be computed from the contents of shader_records and ++ * the address bits of references to them from the bin CL, but it ++ * keeps the kernel from having to resize some allocations it makes. ++ */ ++ __u32 shader_rec_count; ++ /* Size in bytes of the uniform state. */ ++ __u32 uniforms_size; ++ ++ /* Number of BO handles passed in (size is that times 4). */ ++ __u32 bo_handle_count; ++ ++ /* RCL setup: */ ++ __u16 width; ++ __u16 height; ++ __u8 min_x_tile; ++ __u8 min_y_tile; ++ __u8 max_x_tile; ++ __u8 max_y_tile; ++ struct drm_vc4_submit_rcl_surface color_read; ++ struct drm_vc4_submit_rcl_surface color_write; ++ struct drm_vc4_submit_rcl_surface zs_read; ++ struct drm_vc4_submit_rcl_surface zs_write; ++ struct drm_vc4_submit_rcl_surface msaa_color_write; ++ struct drm_vc4_submit_rcl_surface msaa_zs_write; ++ __u32 clear_color[2]; ++ __u32 clear_z; ++ __u8 clear_s; ++ ++ __u32 pad:24; ++ ++#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0) ++ __u32 flags; ++ ++ /* Returned value of the seqno of this render job (for the ++ * wait ioctl). ++ */ ++ __u64 seqno; ++}; ++ ++/** ++ * struct drm_vc4_wait_seqno - ioctl argument for waiting for ++ * DRM_VC4_SUBMIT_CL completion using its returned seqno. ++ * ++ * timeout_ns is the timeout in nanoseconds, where "0" means "don't ++ * block, just return the status." ++ */ ++struct drm_vc4_wait_seqno { ++ __u64 seqno; ++ __u64 timeout_ns; ++}; ++ ++/** ++ * struct drm_vc4_wait_bo - ioctl argument for waiting for ++ * completion of the last DRM_VC4_SUBMIT_CL on a BO. ++ * ++ * This is useful for cases where multiple processes might be ++ * rendering to a BO and you want to wait for all rendering to be ++ * completed. ++ */ ++struct drm_vc4_wait_bo { ++ __u32 handle; ++ __u32 pad; ++ __u64 timeout_ns; ++}; ++ ++/** ++ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_vc4_create_bo { ++ __u32 size; ++ __u32 flags; ++ /** Returned GEM handle for the BO. */ ++ __u32 handle; ++ __u32 pad; ++}; ++ ++/** ++ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs. ++ * ++ * This doesn't actually perform an mmap. Instead, it returns the ++ * offset you need to use in an mmap on the DRM device node. This ++ * means that tools like valgrind end up knowing about the mapped ++ * memory. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_vc4_mmap_bo { ++ /** Handle for the object being mapped. */ ++ __u32 handle; ++ __u32 flags; ++ /** offset into the drm node to use for subsequent mmap call. */ ++ __u64 offset; ++}; ++ ++/** ++ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4 ++ * shader BOs. ++ * ++ * Since allowing a shader to be overwritten while it's also being ++ * executed from would allow privlege escalation, shaders must be ++ * created using this ioctl, and they can't be mmapped later. ++ */ ++struct drm_vc4_create_shader_bo { ++ /* Size of the data argument. */ ++ __u32 size; ++ /* Flags, currently must be 0. */ ++ __u32 flags; ++ ++ /* Pointer to the data. */ ++ __u64 data; ++ ++ /** Returned GEM handle for the BO. */ ++ __u32 handle; ++ /* Pad, must be 0. */ ++ __u32 pad; ++}; ++ ++struct drm_vc4_get_hang_state_bo { ++ __u32 handle; ++ __u32 paddr; ++ __u32 size; ++ __u32 pad; ++}; ++ ++/** ++ * struct drm_vc4_hang_state - ioctl argument for collecting state ++ * from a GPU hang for analysis. ++*/ ++struct drm_vc4_get_hang_state { ++ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */ ++ __u64 bo; ++ /** ++ * On input, the size of the bo array. Output is the number ++ * of bos to be returned. ++ */ ++ __u32 bo_count; ++ ++ __u32 start_bin, start_render; ++ ++ __u32 ct0ca, ct0ea; ++ __u32 ct1ca, ct1ea; ++ __u32 ct0cs, ct1cs; ++ __u32 ct0ra0, ct1ra0; ++ ++ __u32 bpca, bpcs; ++ __u32 bpoa, bpos; ++ ++ __u32 vpmbase; ++ ++ __u32 dbge; ++ __u32 fdbgo; ++ __u32 fdbgb; ++ __u32 fdbgr; ++ __u32 fdbgs; ++ __u32 errstat; ++ ++ /* Pad that we may save more registers into in the future. */ ++ __u32 pad[16]; ++}; ++ ++#endif /* _UAPI_VC4_DRM_H_ */ + +From d3449ad0cd9603d192fbcb70ac395844e43ec1a1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 20 Oct 2015 15:56:56 +0100 +Subject: [PATCH 244/278] Add vc4-kms-v3d overlay + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 88 ++++++++++++++++++++++ + 2 files changed, 89 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 1a60e9c..75692d0 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -59,6 +59,7 @@ dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += spi-dma-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += vc4-kms-v3d-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +new file mode 100644 +index 0000000..32043e0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -0,0 +1,88 @@ ++/* ++ * vc4-kms-v3d-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "dt-bindings/clock/bcm2835.h" ++#include "dt-bindings/gpio/gpio.h" ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&i2c2>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&cprman>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&fb>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&soc>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pixelvalve@7e206000 { ++ compatible = "brcm,bcm2835-pixelvalve0"; ++ reg = <0x7e206000 0x100>; ++ interrupts = <2 13>; /* pwa0 */ ++ }; ++ ++ pixelvalve@7e207000 { ++ compatible = "brcm,bcm2835-pixelvalve1"; ++ reg = <0x7e207000 0x100>; ++ interrupts = <2 14>; /* pwa1 */ ++ }; ++ ++ hvs@7e400000 { ++ compatible = "brcm,bcm2835-hvs"; ++ reg = <0x7e400000 0x6000>; ++ interrupts = <2 1>; ++ }; ++ ++ pixelvalve@7e807000 { ++ compatible = "brcm,bcm2835-pixelvalve2"; ++ reg = <0x7e807000 0x100>; ++ interrupts = <2 10>; /* pixelvalve */ ++ }; ++ ++ hdmi@7e902000 { ++ compatible = "brcm,bcm2835-hdmi"; ++ reg = <0x7e902000 0x600>, ++ <0x7e808000 0x100>; ++ interrupts = <2 8>, <2 9>; ++ ddc = <&i2c2>; ++ hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>; ++ clocks = <&cprman BCM2835_PLLH_PIX>, ++ <&cprman BCM2835_CLOCK_HSM>; ++ clock-names = "pixel", "hdmi"; ++ }; ++ ++ v3d@7ec00000 { ++ compatible = "brcm,vc4-v3d"; ++ reg = <0x7ec00000 0x1000>; ++ interrupts = <1 10>; ++ }; ++ ++ gpu@7e4c0000 { ++ compatible = "brcm,bcm2835-vc4"; ++ }; ++ }; ++ }; ++}; + +From 3ce28fac1cba8e3d5663cb2c0915fc6852a2cb90 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 2 Nov 2015 17:07:33 +0000 +Subject: [PATCH 245/278] drm/vc4: Enable VC4 modules, and increase CMA size + with overlay + +If using the overlay, be careful not to boot to GUI or run startx, +or the Pi will almost hang, reporting stalls in kernel threads. +--- + arch/arm/boot/dts/overlays/README | 8 ++++++++ + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 7 +++++++ + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 4 files changed, 19 insertions(+) + diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 3276312..42a5876 100644 +index cb7c359..e651bf3 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -178,7 +178,7 @@ Load: dtoverlay=at86rf233,= - Params: interrupt GPIO used for INT (default 23) - reset GPIO used for Reset (default 24) - sleep GPIO used for Sleep (default 25) -- speed SPI bus speed in Hz (default 750000) -+ speed SPI bus speed in Hz (default 6000000) - trim Fine tuning of the internal capacitance - arrays (0=+0pF, 15=+4.5pF, default 15) +@@ -691,6 +691,14 @@ Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) + rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + ++Name: vc4-kms-v3d ++Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or ++ booting to GUI while this overlay is in use will cause interesting ++ lockups. ++Load: dtoverlay=vc4-kms-v3d ++Params: ++ ++ + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board + This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds +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 32043e0..419b53d 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -85,4 +85,11 @@ + }; + }; + }; ++ ++ fragment@4 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "cma=0x4000000"; ++ }; ++ }; + }; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 5a61222..d61f42a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -805,6 +805,8 @@ CONFIG_VIDEO_TW9903=m + CONFIG_VIDEO_TW9906=m + CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m ++CONFIG_DRM=m ++CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + CONFIG_FB_UDL=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 20a26f0..ccdde92 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -798,6 +798,8 @@ CONFIG_VIDEO_TW9903=m + CONFIG_VIDEO_TW9906=m + CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m ++CONFIG_DRM=m ++CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + CONFIG_FB_UDL=m + +From 65229f88bc73d44dea5d0325f5960d03e60d358d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 5 Nov 2015 11:05:09 +0000 +Subject: [PATCH 246/278] drm/vc4: Increase CMA size to 256M aligned to 256M + boundary + +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 419b53d..cf5d5c9 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -89,7 +89,7 @@ + fragment@4 { + target-path = "/chosen"; + __overlay__ { +- bootargs = "cma=0x4000000"; ++ bootargs = "cma=256M@512M"; + }; + }; + }; + +From 9475887297d3e6af66295695fa0db73884cfb8a1 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 8 Dec 2015 14:02:27 -0800 +Subject: [PATCH 247/278] drm/vc4: Use "hpd-gpios" for HDMI GPIO, like what + landed upstream. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 cf5d5c9..da37483 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -68,7 +68,7 @@ + <0x7e808000 0x100>; + interrupts = <2 8>, <2 9>; + ddc = <&i2c2>; +- hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>; ++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + clocks = <&cprman BCM2835_PLLH_PIX>, + <&cprman BCM2835_CLOCK_HSM>; + clock-names = "pixel", "hdmi"; + +From e3d395a16a2f957002049a2e7f4d8fabc08d5227 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 20 Jan 2016 17:50:09 +0000 +Subject: [PATCH 248/278] smsx95xx: Add option to disable the crimes against + truesize fix + +It may improve iperf numbers on Pi 1, but may generate dmesg warnings and possibly cause network issues +See issue 1248. +--- + drivers/net/usb/smsc95xx.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + mode change 100755 => 100644 drivers/net/usb/smsc95xx.c + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +old mode 100755 +new mode 100644 +index 08a8a8c..f664c1b +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -75,6 +75,10 @@ static bool turbo_mode = false; + module_param(turbo_mode, bool, 0644); + MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + ++static bool truesize_mode = false; ++module_param(truesize_mode, bool, 0644); ++MODULE_PARM_DESC(truesize_mode, "Report larger truesize value"); ++ + static char *macaddr = ":"; + module_param(macaddr, charp, 0); + MODULE_PARM_DESC(macaddr, "MAC address"); +@@ -1841,6 +1845,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(skb); + skb_trim(skb, skb->len - 4); /* remove fcs */ ++ if (truesize_mode) ++ skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } +@@ -1858,6 +1864,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(ax_skb); + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ++ if (truesize_mode) ++ ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + +From dd141ddde242e1dbeeca78cf97cf3d33d34c324b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 25 Jan 2016 09:12:06 +0000 +Subject: [PATCH 249/278] BCM270X_DT: Add sdio_overclock parameter to sdio + overlay + +The sdio_overclock parameter is like the overclock_50 parameter, i.e. +it sets an alternate frequency (in MHz) to use when the MMC framework +requests 50MHz, except that it applies to the SDIO bus. + +Be aware that the actual frequencies achievable are limited to even integer +divisions of 250MHz, and that the driver will round up to include fractions +(e.g. 62 will include 62.5) but then round down to the nearest frequency. +In other words, the chosen frequency is the highest possible that is less than +the parameter value + 1. In practise this means that 62 is the only sensible +value. + +Examples: + 250MHz/4 = 62.5MHz (sdio_overclock=62) + 250MHz/2 = 125MHz (sdio_overclock=125) # Too fast +--- + arch/arm/boot/dts/overlays/README | 9 ++++++--- + arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index e651bf3..0cf7997 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -53,8 +53,8 @@ have its contents deleted (or commented out). + Using Overlays + ============== + +-Overlays are loaded using the "dtoverlay" directive. As an example, consider the +-popular lirc-rpi module, the Linux Infrared Remote Control driver. In the ++Overlays are loaded using the "dtoverlay" directive. As an example, consider ++the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the + pre-DT world this would be loaded from /etc/modules, with an explicit + "modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled, + this becomes a line in config.txt: +@@ -600,9 +600,12 @@ Name: sdio + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, + and enables SDIO via GPIOs 22-27. + Load: dtoverlay=sdio,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework + requests 50MHz + ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz ++ + force_pio Disable DMA support (default off) + + pio_limit Number of blocks above which to use DMA +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 7935e7a..398bd81 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -12,6 +12,7 @@ + pinctrl-0 = <&sdio_pins>; + non-removable; + bus-width = <4>; ++ brcm,overclock-50 = <0>; + status = "okay"; + }; + }; +@@ -30,5 +31,6 @@ + __overrides__ { + poll_once = <&sdio_mmc>,"non-removable?"; + bus_width = <&sdio_mmc>,"bus-width:0"; ++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0"; + }; + }; + +From ee5ff3eac369b112886261a909b4306dea898b14 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 11 Dec 2015 19:45:03 -0800 +Subject: [PATCH 250/278] drm: Use the driver's gem_object_free function from + CMA helpers. + +VC4 wraps the CMA objects in its own structures, so it needs to do its +own teardown (waiting for GPU to finish, updating bo_stats tracking). +The other CMA drivers are using drm_gem_cma_free_object as their +gem_free_object, so this should be a no-op for them. + +Signed-off-by: Eric Anholt +(cherry picked from commit a8812101ce0faa865c1b75e461d5f05d8a43b9e3) +--- + drivers/gpu/drm/drm_fb_cma_helper.c | 6 +++--- + drivers/gpu/drm/drm_gem_cma_helper.c | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c +index 5c1aca4..99b5673 100644 +--- a/drivers/gpu/drm/drm_fb_cma_helper.c ++++ b/drivers/gpu/drm/drm_fb_cma_helper.c +@@ -279,7 +279,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, + if (!fbi) { + dev_err(dev->dev, "Failed to allocate framebuffer info.\n"); + ret = -ENOMEM; +- goto err_drm_gem_cma_free_object; ++ goto err_gem_free_object; + } + + fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1); +@@ -322,8 +322,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, + drm_fb_cma_destroy(fb); + err_framebuffer_release: + framebuffer_release(fbi); +-err_drm_gem_cma_free_object: +- drm_gem_cma_free_object(&obj->base); ++err_gem_free_object: ++ dev->driver->gem_free_object(&obj->base); + return ret; + } + +diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c +index a2f13aa..27cc420 100644 +--- a/drivers/gpu/drm/drm_gem_cma_helper.c ++++ b/drivers/gpu/drm/drm_gem_cma_helper.c +@@ -121,7 +121,7 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, + return cma_obj; + + error: +- drm_gem_cma_free_object(&cma_obj->base); ++ drm->driver->gem_free_object(&cma_obj->base); + return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(drm_gem_cma_create); +@@ -171,7 +171,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv, + return cma_obj; + + err_handle_create: +- drm_gem_cma_free_object(gem_obj); ++ drm->driver->gem_free_object(gem_obj); + + return ERR_PTR(ret); + } + +From d94f206f5e395d8d4dbbbce658985b221c8795f5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 22 Jan 2016 13:06:39 -0800 +Subject: [PATCH 251/278] drm/vc4: Add a debugfs node for tracking execution + state. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_gem.c | 14 ++++++++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index d76ad10..a99aa86 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -17,6 +17,7 @@ + + static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, ++ {"gem_exec", vc4_gem_exec_debugfs, 0}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, + {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 03e037e..d3850e8 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -403,6 +403,7 @@ void vc4_job_handle_completed(struct vc4_dev *vc4); + int vc4_queue_seqno_cb(struct drm_device *dev, + struct vc4_seqno_cb *cb, uint64_t seqno, + void (*func)(struct vc4_seqno_cb *cb)); ++int vc4_gem_exec_debugfs(struct seq_file *m, void *arg); + + /* vc4_hdmi.c */ + extern struct platform_driver vc4_hdmi_driver; +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 39f29e7..1243f4e 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -31,6 +31,20 @@ + #include "vc4_regs.h" + #include "vc4_trace.h" + ++#ifdef CONFIG_DEBUG_FS ++int vc4_gem_exec_debugfs(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); ++ ++ seq_printf(m, "Emitted seqno: 0x%016llx\n", vc4->emit_seqno); ++ seq_printf(m, "Finished seqno: 0x%016llx\n", vc4->finished_seqno); ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ + static void + vc4_queue_hangcheck(struct drm_device *dev) + { + +From 69680d2967d46ba507b468e662630bb54e25126a Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:03:33 -0800 +Subject: [PATCH 252/278] drm/vc4: Include vc4_drm.h in uapi in downstream + build. + +Signed-off-by: Eric Anholt +--- + include/uapi/drm/Kbuild | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild +index 2d9a25d..8cb3dbb 100644 +--- a/include/uapi/drm/Kbuild ++++ b/include/uapi/drm/Kbuild +@@ -14,6 +14,7 @@ header-y += radeon_drm.h + header-y += savage_drm.h + header-y += sis_drm.h + header-y += tegra_drm.h ++header-y += vc4_drm.h + header-y += via_drm.h + header-y += vmwgfx_drm.h + header-y += msm_drm.h + +From fd03f679dd87b612d2d018c3426da9359987d0c0 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:05:00 -0800 +Subject: [PATCH 253/278] drm/vc4: Validate that WAIT_BO padding is cleared. + +This is ABI future-proofing if we ever want to extend the pad to mean +something. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 1243f4e..849d374 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -761,6 +761,9 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data, + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + ++ if (args->pad != 0) ++ return -EINVAL; ++ + gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (!gem_obj) { + DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); + +From 6f43eea3834c75fabfe868b03d3154fd73c12d5d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:52:41 -0800 +Subject: [PATCH 254/278] drm/vc4: Fix the clear color for the first tile + rendered. + +Apparently in hardware (as opposed to simulation), the clear colors +need to be uploaded before the render config, otherwise they won't +take effect. Fixes igt's vc4_wait_bo/used-bo-* subtests. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_render_cl.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index 8a2a312..dea97f4 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -321,15 +321,6 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, + &exec->unref_list); + +- rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); +- rcl_u32(setup, +- (setup->color_write ? (setup->color_write->paddr + +- args->color_write.offset) : +- 0)); +- rcl_u16(setup, args->width); +- rcl_u16(setup, args->height); +- rcl_u16(setup, args->color_write.bits); +- + /* The tile buffer gets cleared when the previous tile is stored. If + * the clear values changed between frames, then the tile buffer has + * stale clear values in it, so we have to do a store in None mode (no +@@ -349,6 +340,15 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + rcl_u32(setup, 0); /* no address, since we're in None mode */ + } + ++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); ++ rcl_u32(setup, ++ (setup->color_write ? (setup->color_write->paddr + ++ args->color_write.offset) : ++ 0)); ++ rcl_u16(setup, args->width); ++ rcl_u16(setup, args->height); ++ rcl_u16(setup, args->color_write.bits); ++ + for (y = min_y_tile; y <= max_y_tile; y++) { + for (x = min_x_tile; x <= max_x_tile; x++) { + bool first = (x == min_x_tile && y == min_y_tile); + +From 2e5c374e7d27cb403f6de594bc8358dfb35755be Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:13:12 -0800 +Subject: [PATCH 255/278] drm/vc4: Return an ERR_PTR from BO creation instead + of NULL. + +Fixes igt vc4_create_bo/create-bo-0 by returning -EINVAL from the +ioctl instead of -ENOMEM. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_bo.c | 23 +++++++++++++---------- + drivers/gpu/drm/vc4/vc4_gem.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_irq.c | 2 +- + drivers/gpu/drm/vc4/vc4_render_cl.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_validate.c | 4 ++-- + 5 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 6247ff8..8477579 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -213,10 +213,10 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, + size_t size = roundup(unaligned_size, PAGE_SIZE); + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_gem_cma_object *cma_obj; +- int pass; ++ int pass, ret; + + if (size == 0) +- return NULL; ++ return ERR_PTR(-EINVAL); + + /* First, try to get a vc4_bo from the kernel BO cache. */ + if (from_cache) { +@@ -247,14 +247,17 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, + * unreferenced BOs to the cache, and then + * free the cache. + */ +- vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true); ++ ret = vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, ++ true); ++ if (ret) ++ return ERR_PTR(ret); + vc4_job_handle_completed(vc4); + vc4_bo_cache_purge(dev); + break; + case 3: + DRM_ERROR("Failed to allocate from CMA:\n"); + vc4_bo_stats_dump(vc4); +- return NULL; ++ return ERR_PTR(-ENOMEM); + } + } + +@@ -276,8 +279,8 @@ int vc4_dumb_create(struct drm_file *file_priv, + args->size = args->pitch * args->height; + + bo = vc4_bo_create(dev, args->size, false); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_unreference_unlocked(&bo->base.base); +@@ -460,8 +463,8 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data, + * get zeroed, and that might leak data between users. + */ + bo = vc4_bo_create(dev, args->size, false); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_unreference_unlocked(&bo->base.base); +@@ -513,8 +516,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, + } + + bo = vc4_bo_create(dev, args->size, true); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = copy_from_user(bo->base.vaddr, + (void __user *)(uintptr_t)args->data, +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 849d374..f8c003a 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -593,9 +593,9 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) + } + + bo = vc4_bo_create(dev, exec_size, true); +- if (!bo) { ++ if (IS_ERR(bo)) { + DRM_ERROR("Couldn't allocate BO for binning\n"); +- ret = PTR_ERR(exec->exec_bo); ++ ret = PTR_ERR(bo); + goto fail; + } + exec->exec_bo = &bo->base; +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +index b68060e..78a2135 100644 +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -57,7 +57,7 @@ vc4_overflow_mem_work(struct work_struct *work) + struct vc4_bo *bo; + + bo = vc4_bo_create(dev, 256 * 1024, true); +- if (!bo) { ++ if (IS_ERR(bo)) { + DRM_ERROR("Couldn't allocate binner overflow mem\n"); + return; + } +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index dea97f4..0f12418 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -316,8 +316,8 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + size += xtiles * ytiles * loop_body_size; + + setup->rcl = &vc4_bo_create(dev, size, true)->base; +- if (!setup->rcl) +- return -ENOMEM; ++ if (IS_ERR(setup->rcl)) ++ return PTR_ERR(setup->rcl); + list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, + &exec->unref_list); + +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 0fb5b99..8396960 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -401,8 +401,8 @@ validate_tile_binning_config(VALIDATE_ARGS) + tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, + true); + exec->tile_bo = &tile_bo->base; +- if (!exec->tile_bo) +- return -ENOMEM; ++ if (IS_ERR(exec->tile_bo)) ++ return PTR_ERR(exec->tile_bo); + list_add_tail(&tile_bo->unref_head, &exec->unref_list); + + /* tile alloc address. */ + +From 39bbb00a1740b4d54f587a25ba82bada1ae98ba5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:32:41 -0800 +Subject: [PATCH 256/278] drm/vc4: Fix -ERESTARTSYS error return from BO waits. + +This caused the wait ioctls to claim that waiting had completed when +we actually got interrupted by a signal before it was done. Fixes +broken rendering throttling that produced serious lag in X window +dragging. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index f8c003a..dc3044d 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -352,12 +352,10 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, + finish_wait(&vc4->job_wait_queue, &wait); + trace_vc4_wait_for_seqno_end(dev, seqno); + +- if (ret && ret != -ERESTARTSYS) { ++ if (ret && ret != -ERESTARTSYS) + DRM_ERROR("timeout waiting for render thread idle\n"); +- return ret; +- } + +- return 0; ++ return ret; + } + + static void + +From fde284c88f2260e63cfcb5c053d3eaced109d363 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:33:50 -0800 +Subject: [PATCH 257/278] drm/vc4: Drop error message on seqno wait timeouts. + +These ioctls end up getting exposed to userspace, and having normal +user requests print DRM errors is obviously wrong. The message was +originally to give us some idea of what happened when a hang occurred, +but we have a DRM_INFO from reset for that. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index dc3044d..a6fa63f 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -352,9 +352,6 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, + finish_wait(&vc4->job_wait_queue, &wait); + trace_vc4_wait_for_seqno_end(dev, seqno); + +- if (ret && ret != -ERESTARTSYS) +- DRM_ERROR("timeout waiting for render thread idle\n"); +- + return ret; + } + + +From 1b1c474d92849d740d67ad30514df3ae198ede58 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 1 Feb 2016 11:44:47 +0000 +Subject: [PATCH 258/278] Revert "bcm270x_dt: Use the sdhost MMC controller by + default" + +This reverts commit aad4e7c34665e3f2fd4e7cb613aeca231e09ac5c. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 11 ++---- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 11 ++---- + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 14 ++------ + arch/arm/boot/dts/bcm2708_common.dtsi | 13 ------- + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 11 ++---- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 22 +----------- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 49 +++++++++++++++++++++------ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 1 + + 8 files changed, 48 insertions(+), 84 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index bb8c075..d41d31c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 8030401..684852f 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 91ec483c..713e5a2 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,12 +1,5 @@ + /include/ "bcm2708.dtsi" + +-&gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +-}; +- + &leds { + act_led: act { + label = "led0"; +@@ -15,12 +8,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; +- non-removable; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 0425419..924edc8 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,7 +14,6 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; +- sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -127,18 +126,6 @@ + status = "disabled"; + }; + +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,pio-limit = <1>; +- status = "disabled"; +- }; +- + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 747f859..a8e8b7c 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 00a22be..4579ff2 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,29 +6,9 @@ + + fragment@0 { + target = <&mmc>; ++ + frag0: __overlay__ { +- pinctrl-names = "default"; +- pinctrl-0 = <&mmc_pins>; +- bus-width = <4>; + brcm,overclock-50 = <0>; +- status = "okay"; +- }; +- }; +- +- fragment@1 { +- target = <&gpio>; +- __overlay__ { +- mmc_pins: mmc_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <7>; /* alt3 */ +- }; +- }; +- }; +- +- fragment@2 { +- target = <&sdhost>; +- __overlay__ { +- status = "disabled"; + }; + }; + +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 85f0725..2da14a4 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -5,25 +5,52 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&mmc>; ++ target = <&soc>; + __overlay__ { +- status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,delay-after-stop = <0>; ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; ++ }; + }; + }; + + fragment@1 { +- target = <&sdhost>; +- frag1: __overlay__ { +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; ++ target = <&gpio>; ++ __overlay__ { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&mmc>; ++ __overlay__ { ++ /* Find a way to disable the other driver */ ++ compatible = ""; ++ status = "disabled"; + }; + }; + + __overrides__ { +- overclock_50 = <&frag1>,"brcm,overclock-50:0"; +- force_pio = <&frag1>,"brcm,force-pio?"; +- pio_limit = <&frag1>,"brcm,pio-limit:0"; +- debug = <&frag1>,"brcm,debug?"; ++ overclock_50 = <&sdhost>,"brcm,overclock-50:0"; ++ force_pio = <&sdhost>,"brcm,force-pio?"; ++ pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ debug = <&sdhost>,"brcm,debug?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 398bd81..d6a812d 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -8,6 +8,7 @@ + fragment@3 { + target = <&mmc>; + sdio_mmc: __overlay__ { ++ compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; + +From 9552fbc94e0ed0a52c9cb5249c1642a9eb2e9810 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 8 Feb 2016 09:51:08 +0000 +Subject: [PATCH 259/278] BCM270X_DT: Adjust overlay README formatting + +--- + arch/arm/boot/dts/overlays/README | 396 +++++++++++++++++++------------------- + 1 file changed, 198 insertions(+), 198 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 0cf7997..734be606 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -83,58 +83,58 @@ Name: + Info: Configures the base Raspberry Pi hardware + Load: + Params: +- audio Set to "on" to enable the onboard ALSA audio +- interface (default "off") ++ audio Set to "on" to enable the onboard ALSA audio ++ interface (default "off") + +- i2c_arm Set to "on" to enable the ARM's i2c interface +- (default "off") ++ i2c_arm Set to "on" to enable the ARM's i2c interface ++ (default "off") + +- i2c_vc Set to "on" to enable the i2c interface +- usually reserved for the VideoCore processor +- (default "off") ++ i2c_vc Set to "on" to enable the i2c interface ++ usually reserved for the VideoCore processor ++ (default "off") + +- i2c An alias for i2c_arm ++ i2c An alias for i2c_arm + +- i2c_arm_baudrate Set the baudrate of the ARM's i2c interface +- (default "100000") ++ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface ++ (default "100000") + +- i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface +- (default "100000") ++ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface ++ (default "100000") + +- i2c_baudrate An alias for i2c_arm_baudrate ++ i2c_baudrate An alias for i2c_arm_baudrate + +- i2s Set to "on" to enable the i2s interface +- (default "off") ++ i2s Set to "on" to enable the i2s interface ++ (default "off") + +- spi Set to "on" to enable the spi interfaces +- (default "off") ++ spi Set to "on" to enable the spi interfaces ++ (default "off") + +- random Set to "on" to enable the hardware random +- number generator (default "on") ++ random Set to "on" to enable the hardware random ++ number generator (default "on") + +- uart0 Set to "off" to disable uart0 (default "on") ++ uart0 Set to "off" to disable uart0 (default "on") + +- watchdog Set to "on" to enable the hardware watchdog +- (default "off") ++ watchdog Set to "on" to enable the hardware watchdog ++ (default "off") + +- act_led_trigger Choose which activity the LED tracks. +- Use "heartbeat" for a nice load indicator. +- (default "mmc") ++ act_led_trigger Choose which activity the LED tracks. ++ Use "heartbeat" for a nice load indicator. ++ (default "mmc") + +- act_led_activelow Set to "on" to invert the sense of the LED +- (default "off") ++ act_led_activelow Set to "on" to invert the sense of the LED ++ (default "off") + +- act_led_gpio Set which GPIO to use for the activity LED +- (in case you want to connect it to an external +- device) +- (default "16" on a non-Plus board, "47" on a +- Plus or Pi 2) ++ act_led_gpio Set which GPIO to use for the activity LED ++ (in case you want to connect it to an external ++ device) ++ (default "16" on a non-Plus board, "47" on a ++ Plus or Pi 2) + + pwr_led_trigger + pwr_led_activelow + pwr_led_gpio +- As for act_led_*, but using the PWR LED. +- Not available on Model A/B boards. ++ As for act_led_*, but using the PWR LED. ++ Not available on Model A/B boards. + + N.B. It is recommended to only enable those interfaces that are needed. + Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc +@@ -149,19 +149,19 @@ Params: + Name: ads7846 + Info: ADS7846 Touch controller + Load: dtoverlay=ads7846,= +-Params: cs SPI bus Chip Select (default 1) +- speed SPI bus speed (default 2MHz, max 3.25MHz) +- penirq GPIO used for PENIRQ. REQUIRED +- penirq_pull Set GPIO pull (default 0=none, 2=pullup) +- swapxy Swap x and y axis +- xmin Minimum value on the X axis (default 0) +- ymin Minimum value on the Y axis (default 0) +- xmax Maximum value on the X axis (default 4095) +- ymax Maximum value on the Y axis (default 4095) +- pmin Minimum reported pressure value (default 0) +- pmax Maximum reported pressure value (default 65535) +- xohms Touchpanel sensitivity (X-plate resistance) +- (default 400) ++Params: cs SPI bus Chip Select (default 1) ++ speed SPI bus speed (default 2MHz, max 3.25MHz) ++ penirq GPIO used for PENIRQ. REQUIRED ++ penirq_pull Set GPIO pull (default 0=none, 2=pullup) ++ swapxy Swap x and y axis ++ xmin Minimum value on the X axis (default 0) ++ ymin Minimum value on the Y axis (default 0) ++ xmax Maximum value on the X axis (default 4095) ++ ymax Maximum value on the Y axis (default 4095) ++ pmin Minimum reported pressure value (default 0) ++ pmax Maximum reported pressure value (default 65535) ++ xohms Touchpanel sensitivity (X-plate resistance) ++ (default 400) + + penirq is required and usually xohms (60-100) has to be set as well. + Apart from that, pmax (255) and swapxy are also common. +@@ -175,12 +175,12 @@ Name: at86rf233 + Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, + connected to spi0.0 + Load: dtoverlay=at86rf233,= +-Params: interrupt GPIO used for INT (default 23) +- reset GPIO used for Reset (default 24) +- sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 6000000) +- trim Fine tuning of the internal capacitance +- arrays (0=+0pF, 15=+4.5pF, default 15) ++Params: interrupt GPIO used for INT (default 23) ++ reset GPIO used for Reset (default 24) ++ sleep GPIO used for Sleep (default 25) ++ speed SPI bus speed in Hz (default 6000000) ++ trim Fine tuning of the internal capacitance ++ arrays (0=+0pF, 15=+4.5pF, default 15) + + + Name: bmp085_i2c-sensor +@@ -194,8 +194,8 @@ Name: dht11 + Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors + Also sometimes found with the part number(s) AM230x. + Load: dtoverlay=dht11,= +-Params: gpiopin GPIO connected to the sensor's DATA output. +- (default 4) ++Params: gpiopin GPIO connected to the sensor's DATA output. ++ (default 4) + + + [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ] +@@ -204,9 +204,9 @@ Params: gpiopin GPIO connected to the sensor's DATA output. + Name: enc28j60 + Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI) + Load: dtoverlay=enc28j60,= +-Params: int_pin GPIO used for INT (default 25) ++Params: int_pin GPIO used for INT (default 25) + +- speed SPI bus speed (default 12000000) ++ speed SPI bus speed (default 12000000) + + + Name: gpio-ir +@@ -216,26 +216,26 @@ Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core- + not required! The key mapping and other decoding parameters can be + configured by "ir-keytable" tool. + Load: dtoverlay=gpio-ir,= +-Params: gpio_pin Input pin number. Default is 18. ++Params: gpio_pin Input pin number. Default is 18. + +- gpio_pull Desired pull-up/down state (off, down, up) +- Default is "down". ++ gpio_pull Desired pull-up/down state (off, down, up) ++ Default is "down". + +- rc-map-name Default rc keymap (can also be changed by +- ir-keytable), defaults to "rc-rc6-mce" ++ rc-map-name Default rc keymap (can also be changed by ++ ir-keytable), defaults to "rc-rc6-mce" + + + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot + Load: dtoverlay=gpio-poweroff,= +-Params: gpiopin GPIO for signalling (default 26) ++Params: gpiopin GPIO for signalling (default 26) + +- active_low Set if the power control device requires a +- high->low transition to trigger a power-down. +- Note that this will require the support of a +- custom dt-blob.bin to prevent a power-down +- during the boot process, and that a reboot +- will also cause the pin to go low. ++ active_low Set if the power control device requires a ++ high->low transition to trigger a power-down. ++ Note that this will require the support of a ++ custom dt-blob.bin to prevent a power-down ++ during the boot process, and that a reboot ++ will also cause the pin to go low. + + + Name: hifiberry-amp +@@ -266,65 +266,65 @@ Name: hy28a + Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics + Default values match Texy's display shield + Load: dtoverlay=hy28a,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + +- resetgpio GPIO used to reset controller ++ resetgpio GPIO used to reset controller + +- ledgpio GPIO used to control backlight ++ ledgpio GPIO used to control backlight + + + Name: hy28b + Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics + Default values match Texy's display shield + Load: dtoverlay=hy28b,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + +- resetgpio GPIO used to reset controller ++ resetgpio GPIO used to reset controller + +- ledgpio GPIO used to control backlight ++ ledgpio GPIO used to control backlight + + + Name: i2c-gpio + Info: Adds support for software i2c controller on gpio pins + Load: dtoverlay=i2c-gpio,= +-Params: i2c_gpio_sda GPIO used for I2C data (default "23") ++Params: i2c_gpio_sda GPIO used for I2C data (default "23") + +- i2c_gpio_scl GPIO used for I2C clock (default "24") ++ i2c_gpio_scl GPIO used for I2C clock (default "24") + +- i2c_gpio_delay_us Clock delay in microseconds +- (default "2" = ~100kHz) ++ i2c_gpio_delay_us Clock delay in microseconds ++ (default "2" = ~100kHz) + + + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices + Load: dtoverlay=i2c-rtc,= +-Params: ds1307 Select the DS1307 device ++Params: ds1307 Select the DS1307 device + +- ds3231 Select the DS3231 device ++ ds3231 Select the DS3231 device + +- mcp7941x Select the MCP7941x device ++ mcp7941x Select the MCP7941x device + +- pcf2127 Select the PCF2127 device ++ pcf2127 Select the PCF2127 device + +- pcf8523 Select the PCF8523 device ++ pcf8523 Select the PCF8523 device + +- pcf8563 Select the PCF8563 device ++ pcf8563 Select the PCF8563 device + + + Name: i2s-mmap +@@ -349,70 +349,70 @@ Name: lirc-rpi + Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi) + Consult the module documentation for more details. + Load: dtoverlay=lirc-rpi,= +-Params: gpio_out_pin GPIO for output (default "17") ++Params: gpio_out_pin GPIO for output (default "17") + +- gpio_in_pin GPIO for input (default "18") ++ gpio_in_pin GPIO for input (default "18") + +- gpio_in_pull Pull up/down/off on the input pin +- (default "down") ++ gpio_in_pull Pull up/down/off on the input pin ++ (default "down") + +- sense Override the IR receive auto-detection logic: +- "0" = force active-high +- "1" = force active-low +- "-1" = use auto-detection +- (default "-1") ++ sense Override the IR receive auto-detection logic: ++ "0" = force active-high ++ "1" = force active-low ++ "-1" = use auto-detection ++ (default "-1") + +- softcarrier Turn the software carrier "on" or "off" +- (default "on") ++ softcarrier Turn the software carrier "on" or "off" ++ (default "on") + +- invert "on" = invert the output pin (default "off") ++ invert "on" = invert the output pin (default "off") + +- debug "on" = enable additional debug messages +- (default "off") ++ debug "on" = enable additional debug messages ++ (default "off") + + + Name: mcp2515-can0 + Info: Configures the MCP2515 CAN controller on spi0.0 + Load: dtoverlay=mcp2515-can0,= +-Params: oscillator Clock frequency for the CAN controller (Hz) ++Params: oscillator Clock frequency for the CAN controller (Hz) + +- spimaxfrequency Maximum SPI frequence (Hz) ++ spimaxfrequency Maximum SPI frequence (Hz) + +- interrupt GPIO for interrupt signal ++ interrupt GPIO for interrupt signal + + + Name: mcp2515-can1 + Info: Configures the MCP2515 CAN controller on spi0.1 + Load: dtoverlay=mcp2515-can1,= +-Params: oscillator Clock frequency for the CAN controller (Hz) ++Params: oscillator Clock frequency for the CAN controller (Hz) + +- spimaxfrequency Maximum SPI frequence (Hz) ++ spimaxfrequency Maximum SPI frequence (Hz) + +- interrupt GPIO for interrupt signal ++ interrupt GPIO for interrupt signal + + + Name: mmc + Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock + Load: dtoverlay=mmc,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework +- requests 50MHz +- force_pio Disable DMA support ++Params: overclock_50 Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ force_pio Disable DMA support + + + Name: mz61581 + Info: MZ61581 display by Tontec + Load: dtoverlay=mz61581,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- txbuflen Transmit buffer length (default 32768) ++ txbuflen Transmit buffer length (default 32768) + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ] +@@ -427,69 +427,69 @@ Params: speed Display SPI bus speed + Name: piscreen + Info: PiScreen display by OzzMaker.com + Load: dtoverlay=piscreen,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com + Load: dtoverlay=piscreen2r,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: pitft28-capacitive + Info: Adafruit PiTFT 2.8" capacitive touch screen + Load: dtoverlay=pitft28-capacitive,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- touch-sizex Touchscreen size x (default 240) ++ touch-sizex Touchscreen size x (default 240) + +- touch-sizey Touchscreen size y (default 320) ++ touch-sizey Touchscreen size y (default 320) + +- touch-invx Touchscreen inverted x axis ++ touch-invx Touchscreen inverted x axis + +- touch-invy Touchscreen inverted y axis ++ touch-invy Touchscreen inverted y axis + +- touch-swapxy Touchscreen swapped x y axis ++ touch-swapxy Touchscreen swapped x y axis + + + Name: pitft28-resistive + Info: Adafruit PiTFT 2.8" resistive touch screen + Load: dtoverlay=pitft28-resistive,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + + + Name: pps-gpio + Info: Configures the pps-gpio (pulse-per-second time signal via GPIO). + Load: dtoverlay=pps-gpio,= +-Params: gpiopin Input GPIO (default "18") ++Params: gpiopin Input GPIO (default "18") + + + Name: pwm +@@ -503,12 +503,12 @@ Info: Configures a single PWM channel + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clock must have been enabled and configured ++ 4) Currently the clockmust have been enabled and configured + by other means. + Load: dtoverlay=pwm,= +-Params: pin Output pin (default 18) - see table +- func Pin function (default 2 = Alt5) - see above +- clock PWM clock frequency (informational) ++Params: pin Output pin (default 18) - see table ++ func Pin function (default 2 = Alt5) - see above ++ clock PWM clock frequency (informational) + + + Name: pwm-2chan +@@ -522,14 +522,14 @@ Info: Configures both PWM channels + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clock must have been enabled and configured ++ 4) Currently the clockmust have been enabled and configured + by other means. + Load: dtoverlay=pwm-2chan,= +-Params: pin Output pin (default 18) - see table +- pin2 Output pin for other channel (default 19) +- func Pin function (default 2 = Alt5) - see above +- func2 Function for pin2 (default 2 = Alt5) +- clock PWM clock frequency (informational) ++Params: pin Output pin (default 18) - see table ++ pin2 Output pin for other channel (default 19) ++ func Pin function (default 2 = Alt5) - see above ++ func2 Function for pin2 (default 2 = Alt5) ++ clock PWM clock frequency (informational) + + + Name: raspidac3 +@@ -553,15 +553,15 @@ Params: + Name: rpi-display + Info: RPi-Display - 2.8" Touch Display by Watterott + Load: dtoverlay=rpi-display,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: rpi-ft5406 +@@ -585,38 +585,38 @@ Params: + Name: sdhost + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock + Load: dtoverlay=sdhost,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework +- requests 50MHz ++Params: overclock_50 Clock (in MHz) to use when the MMC framework ++ requests 50MHz + +- force_pio Disable DMA support (default off) ++ force_pio Disable DMA support (default off) + +- pio_limit Number of blocks above which to use DMA +- (default 1) ++ pio_limit Number of blocks above which to use DMA ++ (default 1) + +- debug Enable debug output (default off) ++ debug Enable debug output (default off) + + + Name: sdio + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, + and enables SDIO via GPIOs 22-27. + Load: dtoverlay=sdio,= +-Params: overclock_50 SD Clock (in MHz) to use when the MMC framework +- requests 50MHz ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework ++ requests 50MHz + +- sdio_overclock SDIO Clock (in MHz) to use when the MMC +- framework requests 50MHz ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz + +- force_pio Disable DMA support (default off) ++ force_pio Disable DMA support (default off) + +- pio_limit Number of blocks above which to use DMA +- (default 1) ++ pio_limit Number of blocks above which to use DMA ++ (default 1) + +- debug Enable debug output (default off) ++ debug Enable debug output (default off) + +- poll_once Disable SDIO-device polling every second +- (default on: polling once at boot-time) ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) + +- bus_width Set the SDIO host bus width (default 4 bits) ++ bus_width Set the SDIO host bus width (default 4 bits) + + + Name: smi +@@ -659,25 +659,25 @@ Name: tinylcd35 + Info: 3.5" Color TFT Display by www.tinylcd.com + Options: Touch, RTC, keypad + Load: dtoverlay=tinylcd35,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- touch Enable touch panel ++ touch Enable touch panel + +- touchgpio Touch controller IRQ GPIO ++ touchgpio Touch controller IRQ GPIO + +- xohms Touchpanel: Resistance of X-plate in ohms ++ xohms Touchpanel: Resistance of X-plate in ohms + +- rtc-pcf PCF8563 Real Time Clock ++ rtc-pcf PCF8563 Real Time Clock + +- rtc-ds DS1307 Real Time Clock ++ rtc-ds DS1307 Real Time Clock + +- keypad Enable keypad ++ keypad Enable keypad + + Examples: + Display with touchpanel, PCF8563 RTC and keypad: +@@ -689,9 +689,9 @@ Params: speed Display SPI bus speed + Name: uart1 + Info: Enable uart1 in place of uart0 + Load: dtoverlay=uart1,= +-Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) ++Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) + +- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) ++ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + + + Name: vc4-kms-v3d +@@ -704,7 +704,7 @@ Params: + + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board +- This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds ++ This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds + after the kernel has started. + Load: dtoverlay=vga666 + Params: +@@ -714,22 +714,22 @@ Name: w1-gpio + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *don't* need a GPIO to drive an external pullup. + Load: dtoverlay=w1-gpio,= +-Params: gpiopin GPIO for I/O (default "4") ++Params: gpiopin GPIO for I/O (default "4") + +- pullup Non-zero, "on", or "y" to enable the parasitic +- power (2-wire, power-on-data) feature ++ pullup Non-zero, "on", or "y" to enable the parasitic ++ power (2-wire, power-on-data) feature + + + Name: w1-gpio-pullup + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *do* need a GPIO to drive an external pullup. + Load: dtoverlay=w1-gpio-pullup,= +-Params: gpiopin GPIO for I/O (default "4") ++Params: gpiopin GPIO for I/O (default "4") + +- pullup Non-zero, "on", or "y" to enable the parasitic +- power (2-wire, power-on-data) feature ++ pullup Non-zero, "on", or "y" to enable the parasitic ++ power (2-wire, power-on-data) feature + +- extpullup GPIO for external pullup (default "5") ++ extpullup GPIO for external pullup (default "5") + + + Troubleshooting + +From 1cd0ef61452ad01f02a39060df4aaba98a8b6845 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 8 Feb 2016 12:53:44 +0000 +Subject: [PATCH 260/278] FIXUP: Overlay README - Restore spaces deleted in + error + +--- + arch/arm/boot/dts/overlays/README | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 734be606..b657512 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -503,7 +503,7 @@ Info: Configures a single PWM channel + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clockmust have been enabled and configured ++ 4) Currently the clock must have been enabled and configured + by other means. + Load: dtoverlay=pwm,= + Params: pin Output pin (default 18) - see table +@@ -522,7 +522,7 @@ Info: Configures both PWM channels + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clockmust have been enabled and configured ++ 4) Currently the clock must have been enabled and configured + by other means. + Load: dtoverlay=pwm-2chan,= + Params: pin Output pin (default 18) - see table +@@ -704,7 +704,7 @@ Params: + + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board +- This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds ++ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds + after the kernel has started. + Load: dtoverlay=vga666 + Params: + +From 17e9af6feddde2b08a224868a099307a577c4cde Mon Sep 17 00:00:00 2001 +From: Digital Dreamtime +Date: Thu, 4 Feb 2016 14:14:44 +0000 +Subject: [PATCH 261/278] Allow up to 24dB digital gain to be applied when + using IQAudIO DAC+ + +24db_digital_gain DT param can be used to specify that PCM512x +codec "Digital" volume control should not be limited to 0dB gain, +and if specified will allow the full 24dB gain. +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++++++++-- + .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 6 +++++- + sound/soc/bcm/iqaudio-dac.c | 22 +++++++++++++++------- + 3 files changed, 35 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index b657512..7f1ef9b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -341,8 +341,21 @@ Params: + + Name: iqaudio-dacplus + Info: Configures the IQaudio DAC+ audio card +-Load: dtoverlay=iqaudio-dacplus +-Params: ++Load: dtoverlay=iqaudio-dacplus,= ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ Digital volume control. Enable with ++ "dtoverlay=iqaudio-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: lirc-rpi +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +index 735d8ab..e0aaf8f 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +@@ -7,7 +7,7 @@ + + fragment@0 { + target = <&sound>; +- __overlay__ { ++ frag0: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; + i2s-controller = <&i2s>; + status = "okay"; +@@ -36,4 +36,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?"; ++ }; + }; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index a38e874..5ade006 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -23,15 +23,20 @@ + #include + #include + ++static bool digital_gain_0db_limit = true; ++ + static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) + { +- int ret; +- struct snd_soc_card *card = rtd->card; +- struct snd_soc_codec *codec = rtd->codec; +- +- ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); +- if (ret < 0) +- dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ if (digital_gain_0db_limit) ++ { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } + + return 0; + } +@@ -95,6 +100,9 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) + dai->platform_name = NULL; + dai->platform_of_node = i2s_node; + } ++ ++ digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node, ++ "iqaudio,24db_digital_gain"); + } + + ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); + +From e1e2fab9e43a933c6efc8d28350064d2cba1a010 Mon Sep 17 00:00:00 2001 +From: Digital Dreamtime +Date: Thu, 4 Feb 2016 20:04:00 +0000 +Subject: [PATCH 262/278] Limit PCM512x "Digital" gain to 0dB by default with + HiFiBerry DAC+ + +24db_digital_gain DT param can be used to specify that PCM512x +codec "Digital" volume control should not be limited to 0dB gain, +and if specified will allow the full 24dB gain. +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++++++++-- + .../arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 6 +++++- + sound/soc/bcm/hifiberry_dacplus.c | 15 +++++++++++++++ + 3 files changed, 35 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 7f1ef9b..3f7a25d 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -252,8 +252,21 @@ Params: + + Name: hifiberry-dacplus + Info: Configures the HifiBerry DAC+ audio card +-Load: dtoverlay=hifiberry-dacplus +-Params: ++Load: dtoverlay=hifiberry-dacplus,= ++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: hifiberry-digi +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +index f923a48..42a0194 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -17,7 +17,7 @@ + + fragment@1 { + target = <&sound>; +- __overlay__ { ++ frag1: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; + i2s-controller = <&i2s>; + status = "okay"; +@@ -47,4 +47,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag1>,"hifiberry,24db_digital_gain?"; ++ }; + }; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index a6b651c..50b66a1 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -48,6 +48,7 @@ struct pcm512x_priv { + #define CLK_48EN_RATE 24576000UL + + static bool snd_rpi_hifiberry_is_dacpro; ++static bool digital_gain_0db_limit = true; + + static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec, + int clk_id) +@@ -167,6 +168,17 @@ static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd) + snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); + snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + ++ if (digital_gain_0db_limit) ++ { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ + return 0; + } + +@@ -299,6 +311,9 @@ static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev) + dai->platform_name = NULL; + dai->platform_of_node = i2s_node; + } ++ ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "hifiberry,24db_digital_gain"); + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus); + +From 0361429f25d77226e1e254f67bc06cd2537fa094 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 9 Feb 2016 09:52:13 +0000 +Subject: [PATCH 263/278] pinctrl-bcm2835: Fix cut-and-paste error in "pull" + parsing + +The DT bindings for pinctrl-bcm2835 allow both the function and pull +to contain either one entry or one per pin. However, an error in the +DT parsing can cause failures if the number of pulls differs from the +number of functions. +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +index 61ef002..5821f46 100644 +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -818,7 +818,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + } + if (num_pulls) { + err = of_property_read_u32_index(np, "brcm,pull", +- (num_funcs > 1) ? i : 0, &pull); ++ (num_pulls > 1) ? i : 0, &pull); + if (err) + goto out; + err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin, + +From 699dc6932548e83d9a52bed5e8bf17233cc14d30 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 11 Feb 2016 15:25:17 +0000 +Subject: [PATCH 264/278] bcm2835-sdhost: Major revision + +This is a significant revision of the bcm2835-sdhost driver. It +improves on the original in a number of ways: + +1) Through the use of CMD23 for reads it appears to avoid problems + reading some sectors on certain high speed cards. +2) Better atomicity to prevent crashes. +3) Higher performance. +4) Activity logging included, for easier diagnosis in the event + of a problem. +--- + drivers/mmc/host/bcm2835-sdhost.c | 1263 ++++++++++++++++++++----------------- + 1 file changed, 696 insertions(+), 567 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 44d61c3..84d120f 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -2,7 +2,7 @@ + * BCM2835 SD host driver. + * + * Author: Phil Elwell +- * Copyright 2015 ++ * Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd. + * + * Based on + * mmc-bcm2835.c by Gellert Weisz +@@ -24,12 +24,13 @@ + * along with this program. If not, see . + */ + +-#define SAFE_READ_THRESHOLD 4 +-#define SAFE_WRITE_THRESHOLD 4 +-#define ALLOW_DMA 1 +-#define ALLOW_CMD23 0 +-#define ALLOW_FAST 1 +-#define USE_BLOCK_IRQ 1 ++#define FIFO_READ_THRESHOLD 4 ++#define FIFO_WRITE_THRESHOLD 4 ++#define ALLOW_CMD23_READ 1 ++#define ALLOW_CMD23_WRITE 0 ++#define ENABLE_LOG 1 ++#define SDDATA_FIFO_PIO_BURST 8 ++#define CMD_DALLY_US 1 + + #include + #include +@@ -48,6 +49,7 @@ + #include + #include + #include ++#include + + #define DRIVER_NAME "sdhost-bcm2835" + +@@ -110,6 +112,28 @@ + #define SDEDM_READ_THRESHOLD_SHIFT 14 + #define SDEDM_THRESHOLD_MASK 0x1f + ++#define SDEDM_FSM_MASK 0xf ++#define SDEDM_FSM_IDENTMODE 0x0 ++#define SDEDM_FSM_DATAMODE 0x1 ++#define SDEDM_FSM_READDATA 0x2 ++#define SDEDM_FSM_WRITEDATA 0x3 ++#define SDEDM_FSM_READWAIT 0x4 ++#define SDEDM_FSM_READCRC 0x5 ++#define SDEDM_FSM_WRITECRC 0x6 ++#define SDEDM_FSM_WRITEWAIT1 0x7 ++#define SDEDM_FSM_POWERDOWN 0x8 ++#define SDEDM_FSM_POWERUP 0x9 ++#define SDEDM_FSM_WRITESTART1 0xa ++#define SDEDM_FSM_WRITESTART2 0xb ++#define SDEDM_FSM_GENPULSES 0xc ++#define SDEDM_FSM_WRITEWAIT2 0xd ++#define SDEDM_FSM_STARTPOWDOWN 0xf ++ ++#define SDDATA_FIFO_WORDS 16 ++ ++#define USE_CMD23_FLAGS ((ALLOW_CMD23_READ * MMC_DATA_READ) | \ ++ (ALLOW_CMD23_WRITE * MMC_DATA_WRITE)) ++ + #define MHZ 1000000 + + #ifndef BCM2708_PERI_BASE +@@ -138,15 +162,17 @@ struct bcm2835_host { + + struct tasklet_struct finish_tasklet; /* Tasklet structures */ + +- struct timer_list timer; /* Timer for timeouts */ ++ struct work_struct cmd_wait_wq; /* Workqueue function */ + +- struct timer_list pio_timer; /* PIO error detection timer */ ++ struct timer_list timer; /* Timer for timeouts */ + + struct sg_mapping_iter sg_miter; /* SG state for PIO */ + unsigned int blocks; /* remaining PIO blocks */ + + int irq; /* Device IRQ */ + ++ u32 cmd_quick_poll_retries; ++ u32 ns_per_fifo_word; + + /* cached registers */ + u32 hcfg; +@@ -161,16 +187,21 @@ struct bcm2835_host { + + unsigned int use_busy:1; /* Wait for busy interrupt */ + +- unsigned int debug:1; /* Enable debug output */ ++ unsigned int use_sbc:1; /* Send CMD23 */ + +- u32 thread_isr; ++ unsigned int debug:1; /* Enable debug output */ + + /*DMA part*/ + struct dma_chan *dma_chan_rx; /* DMA channel for reads */ + struct dma_chan *dma_chan_tx; /* DMA channel for writes */ ++ struct dma_chan *dma_chan; /* Channel in used */ ++ struct dma_async_tx_descriptor *dma_desc; ++ u32 dma_dir; ++ u32 drain_words; ++ struct page *drain_page; ++ u32 drain_offset; + + bool allow_dma; +- bool have_dma; + bool use_dma; + /*end of DMA part*/ + +@@ -182,6 +213,96 @@ struct bcm2835_host { + u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */ + }; + ++#if ENABLE_LOG ++ ++struct log_entry_struct { ++ char event[4]; ++ u32 timestamp; ++ u32 param1; ++ u32 param2; ++}; ++ ++typedef struct log_entry_struct LOG_ENTRY_T; ++ ++LOG_ENTRY_T *sdhost_log_buf; ++dma_addr_t sdhost_log_addr; ++static u32 sdhost_log_idx; ++static spinlock_t log_lock; ++static void __iomem *timer_base; ++ ++#define LOG_ENTRIES (256*1) ++#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES) ++ ++static void log_init(void) ++{ ++ spin_lock_init(&log_lock); ++ sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr, ++ GFP_KERNEL); ++ if (sdhost_log_buf) { ++ pr_err("sdhost: log_buf @ %p (%x)\n", ++ sdhost_log_buf, sdhost_log_addr); ++ timer_base = ioremap_nocache(BCM2708_PERI_BASE + 0x3000, SZ_4K); ++ if (!timer_base) ++ pr_err("sdhost: failed to remap timer\n"); ++ } ++ else ++ pr_err("sdhost: failed to allocate log buf\n"); ++} ++ ++static void log_event_impl(const char *event, u32 param1, u32 param2) ++{ ++ if (sdhost_log_buf) { ++ LOG_ENTRY_T *entry; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&log_lock, flags); ++ ++ entry = sdhost_log_buf + sdhost_log_idx; ++ memcpy(entry->event, event, 4); ++ entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) + ++ (smp_processor_id()<<30); ++ entry->param1 = param1; ++ entry->param2 = param2; ++ sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES; ++ ++ spin_unlock_irqrestore(&log_lock, flags); ++ } ++} ++ ++static void log_dump(void) ++{ ++ if (sdhost_log_buf) { ++ LOG_ENTRY_T *entry; ++ unsigned long flags; ++ int idx; ++ ++ spin_lock_irqsave(&log_lock, flags); ++ ++ idx = sdhost_log_idx; ++ do { ++ entry = sdhost_log_buf + idx; ++ if (entry->event[0] != '\0') ++ pr_err("[%08x] %.4s %x %x\n", ++ entry->timestamp, ++ entry->event, ++ entry->param1, ++ entry->param2); ++ idx = (idx + 1) % LOG_ENTRIES; ++ } while (idx != sdhost_log_idx); ++ ++ spin_unlock_irqrestore(&log_lock, flags); ++ } ++} ++ ++#define log_event(event, param1, param2) log_event_impl(event, param1, param2) ++ ++#else ++ ++#define log_init() (void)0 ++#define log_event(event, param1, param2) (void)0 ++#define log_dump() (void)0 ++ ++#endif + + static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg) + { +@@ -203,7 +324,7 @@ static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host, + const char *label) + { + if (cmd) +- pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n", ++ pr_err("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n", + mmc_hostname(host->mmc), + (cmd == host->cmd) ? '>' : ' ', + label, cmd->opcode, cmd->arg, cmd->flags, +@@ -213,77 +334,81 @@ static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host, + + static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host) + { +- bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc"); +- bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd"); +- if (host->mrq->data) +- pr_err("%s: data blocks %x blksz %x - err %d\n", +- mmc_hostname(host->mmc), +- host->mrq->data->blocks, +- host->mrq->data->blksz, +- host->mrq->data->error); +- bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop"); ++ if (host->mrq) ++ { ++ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc"); ++ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd"); ++ if (host->mrq->data) ++ pr_err("%s: data blocks %x blksz %x - err %d\n", ++ mmc_hostname(host->mmc), ++ host->mrq->data->blocks, ++ host->mrq->data->blksz, ++ host->mrq->data->error); ++ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop"); ++ } + +- pr_info("%s: =========== REGISTER DUMP ===========\n", ++ pr_err("%s: =========== REGISTER DUMP ===========\n", + mmc_hostname(host->mmc)); + +- pr_info("%s: SDCMD 0x%08x\n", ++ pr_err("%s: SDCMD 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDCMD)); +- pr_info("%s: SDARG 0x%08x\n", ++ pr_err("%s: SDARG 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDARG)); +- pr_info("%s: SDTOUT 0x%08x\n", ++ pr_err("%s: SDTOUT 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDTOUT)); +- pr_info("%s: SDCDIV 0x%08x\n", ++ pr_err("%s: SDCDIV 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDCDIV)); +- pr_info("%s: SDRSP0 0x%08x\n", ++ pr_err("%s: SDRSP0 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP0)); +- pr_info("%s: SDRSP1 0x%08x\n", ++ pr_err("%s: SDRSP1 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP1)); +- pr_info("%s: SDRSP2 0x%08x\n", ++ pr_err("%s: SDRSP2 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP2)); +- pr_info("%s: SDRSP3 0x%08x\n", ++ pr_err("%s: SDRSP3 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP3)); +- pr_info("%s: SDHSTS 0x%08x\n", ++ pr_err("%s: SDHSTS 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHSTS)); +- pr_info("%s: SDVDD 0x%08x\n", ++ pr_err("%s: SDVDD 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDVDD)); +- pr_info("%s: SDEDM 0x%08x\n", ++ pr_err("%s: SDEDM 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDEDM)); +- pr_info("%s: SDHCFG 0x%08x\n", ++ pr_err("%s: SDHCFG 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHCFG)); +- pr_info("%s: SDHBCT 0x%08x\n", ++ pr_err("%s: SDHBCT 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHBCT)); +- pr_info("%s: SDHBLC 0x%08x\n", ++ pr_err("%s: SDHBLC 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHBLC)); + +- pr_info("%s: ===========================================\n", ++ pr_err("%s: ===========================================\n", + mmc_hostname(host->mmc)); + } + +- + static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on) + { + bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD); + } + +- + static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host) + { + u32 temp; + ++ if (host->debug) ++ pr_info("%s: reset\n", mmc_hostname(host->mmc)); ++ + bcm2835_sdhost_set_power(host, false); + + bcm2835_sdhost_write(host, 0, SDCMD); +@@ -299,8 +424,8 @@ static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host) + temp = bcm2835_sdhost_read(host, SDEDM); + temp &= ~((SDEDM_THRESHOLD_MASK<debug) +- pr_info("%s: reset\n", mmc_hostname(mmc)); + spin_lock_irqsave(&host->lock, flags); ++ log_event("RST<", 0, 0); + + bcm2835_sdhost_reset_internal(host); + +@@ -343,82 +466,48 @@ static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft) + } + } + +-static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host) ++static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host) + { +- bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1); +- +- if (!write_complete) { +- /* Request an IRQ for the last block */ +- host->hcfg |= SDHCFG_BLOCK_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) { +- /* The write has now completed. Disable the interrupt +- and clear the status flag */ +- host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS); +- write_complete = true; +- } +- } ++ int timediff; ++ u32 alternate_idle; ++ u32 edm; + +- return write_complete; +-} ++ alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ? ++ SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1; + +-static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host) +-{ +- int timediff; +-#ifdef DEBUG +- static struct timeval start_time; +- static int max_stall_time = 0; +- static int total_stall_time = 0; +- struct timeval before, after; ++ edm = bcm2835_sdhost_read(host, SDEDM); + +- do_gettimeofday(&before); +- if (max_stall_time == 0) +- start_time = before; +-#endif ++ log_event("WTC<", edm, 0); + + timediff = 0; + + while (1) { +- u32 edm = bcm2835_sdhost_read(host, SDEDM); +- if ((edm & 0xf) == 1) ++ u32 fsm = edm & SDEDM_FSM_MASK; ++ if ((fsm == SDEDM_FSM_IDENTMODE) || ++ (fsm == SDEDM_FSM_DATAMODE)) + break; +- timediff++; +- if (timediff > 5000000) { +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + +- (after.tv_usec - before.tv_usec); ++ if (fsm == alternate_idle) { ++ bcm2835_sdhost_write(host, ++ edm | SDEDM_FORCE_DATA_MODE, ++ SDEDM); ++ break; ++ } + +- pr_err(" wait_write_complete - still waiting after %dus\n", +- timediff); +-#else +- pr_err(" wait_write_complete - still waiting after %d retries\n", ++ timediff++; ++ if (timediff == 100000) { ++ pr_err("%s: wait_transfer_complete - still waiting after %d retries\n", ++ mmc_hostname(host->mmc), + timediff); +-#endif ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- host->data->error = -ETIMEDOUT; ++ host->mrq->data->error = -ETIMEDOUT; ++ log_event("WTC!", edm, 0); + return; + } ++ cpu_relax(); ++ edm = bcm2835_sdhost_read(host, SDEDM); + } +- +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec); +- +- total_stall_time += timediff; +- if (timediff > max_stall_time) +- max_stall_time = timediff; +- +- if ((after.tv_sec - start_time.tv_sec) > 10) { +- pr_debug(" wait_write_complete - max wait %dus, total %dus\n", +- max_stall_time, total_stall_time); +- start_time = after; +- max_stall_time = 0; +- total_stall_time = 0; +- } +-#endif ++ log_event("WTC>", edm, 0); + } + + static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); +@@ -426,65 +515,44 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); + static void bcm2835_sdhost_dma_complete(void *param) + { + struct bcm2835_host *host = param; +- struct dma_chan *dma_chan; ++ struct mmc_data *data = host->data; + unsigned long flags; +- u32 dir_data; + + spin_lock_irqsave(&host->lock, flags); ++ log_event("DMA<", (u32)host->data, bcm2835_sdhost_read(host, SDHSTS)); ++ log_event("DMA ", bcm2835_sdhost_read(host, SDCMD), ++ bcm2835_sdhost_read(host, SDEDM)); + +- if (host->data) { +- bool write_complete; +- if (USE_BLOCK_IRQ) +- write_complete = bcm2835_sdhost_is_write_complete(host); +- else { +- bcm2835_sdhost_wait_write_complete(host); +- write_complete = true; +- } +- pr_debug("dma_complete() - write_complete=%d\n", +- write_complete); +- +- if (write_complete || (host->data->flags & MMC_DATA_READ)) +- { +- if (write_complete) { +- dma_chan = host->dma_chan_tx; +- dir_data = DMA_TO_DEVICE; +- } else { +- dma_chan = host->dma_chan_rx; +- dir_data = DMA_FROM_DEVICE; +- } ++ if (host->dma_chan) { ++ dma_unmap_sg(host->dma_chan->device->dev, ++ data->sg, data->sg_len, ++ host->dma_dir); + +- dma_unmap_sg(dma_chan->device->dev, +- host->data->sg, host->data->sg_len, +- dir_data); +- +- bcm2835_sdhost_finish_data(host); +- } ++ host->dma_chan = NULL; + } + +- spin_unlock_irqrestore(&host->lock, flags); +-} ++ if (host->drain_words) { ++ void *page; ++ u32 *buf; + +-static bool data_transfer_wait(struct bcm2835_host *host) +-{ +- unsigned long timeout = 1000000; +- while (timeout) +- { +- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); +- if (sdhsts & SDHSTS_DATA_FLAG) { +- bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS); +- break; ++ page = kmap_atomic(host->drain_page); ++ buf = page + host->drain_offset; ++ ++ while (host->drain_words) { ++ u32 edm = bcm2835_sdhost_read(host, SDEDM); ++ if ((edm >> 4) & 0x1f) ++ *(buf++) = bcm2835_sdhost_read(host, ++ SDDATA); ++ host->drain_words--; + } +- timeout--; +- } +- if (timeout == 0) { +- pr_err("%s: Data %s timeout\n", +- mmc_hostname(host->mmc), +- (host->data->flags & MMC_DATA_READ) ? "read" : "write"); +- bcm2835_sdhost_dumpregs(host); +- host->data->error = -ETIMEDOUT; +- return false; ++ ++ kunmap_atomic(page); + } +- return true; ++ ++ bcm2835_sdhost_finish_data(host); ++ ++ log_event("DMA>", (u32)host->data, 0); ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) +@@ -492,32 +560,83 @@ static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) + unsigned long flags; + size_t blksize, len; + u32 *buf; ++ unsigned long wait_max; + + blksize = host->data->blksz; + ++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout); ++ + local_irq_save(flags); + + while (blksize) { +- if (!sg_miter_next(&host->sg_miter)) +- BUG(); ++ int copy_words; ++ u32 hsts = 0; ++ ++ if (!sg_miter_next(&host->sg_miter)) { ++ host->data->error = -EINVAL; ++ break; ++ } + + len = min(host->sg_miter.length, blksize); +- BUG_ON(len % 4); ++ if (len % 4) { ++ host->data->error = -EINVAL; ++ break; ++ } + + blksize -= len; + host->sg_miter.consumed = len; + + buf = (u32 *)host->sg_miter.addr; + +- while (len) { +- if (!data_transfer_wait(host)) +- break; ++ copy_words = len/4; ++ ++ while (copy_words) { ++ int burst_words, words; ++ u32 edm; ++ ++ burst_words = SDDATA_FIFO_PIO_BURST; ++ if (burst_words > copy_words) ++ burst_words = copy_words; ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ words = ((edm >> 4) & 0x1f); ++ ++ if (words < burst_words) { ++ int fsm_state = (edm & SDEDM_FSM_MASK); ++ if ((fsm_state != SDEDM_FSM_READDATA) && ++ (fsm_state != SDEDM_FSM_READWAIT) && ++ (fsm_state != SDEDM_FSM_READCRC)) { ++ hsts = bcm2835_sdhost_read(host, ++ SDHSTS); ++ pr_err("%s: fsm %x, hsts %x\n", ++ mmc_hostname(host->mmc), ++ fsm_state, hsts); ++ if (hsts & SDHSTS_ERROR_MASK) ++ break; ++ } ++ ++ if (time_after(jiffies, wait_max)) { ++ pr_err("%s: PIO read timeout - EDM %x\n", ++ mmc_hostname(host->mmc), ++ edm); ++ hsts = SDHSTS_REW_TIME_OUT; ++ break; ++ } ++ ndelay((burst_words - words) * ++ host->ns_per_fifo_word); ++ continue; ++ } else if (words > copy_words) { ++ words = copy_words; ++ } + +- *(buf++) = bcm2835_sdhost_read(host, SDDATA); +- len -= 4; ++ copy_words -= words; ++ ++ while (words) { ++ *(buf++) = bcm2835_sdhost_read(host, SDDATA); ++ words--; ++ } + } + +- if (host->data->error) ++ if (hsts & SDHSTS_ERROR_MASK) + break; + } + +@@ -531,32 +650,83 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) + unsigned long flags; + size_t blksize, len; + u32 *buf; ++ unsigned long wait_max; + + blksize = host->data->blksz; + ++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout); ++ + local_irq_save(flags); + + while (blksize) { +- if (!sg_miter_next(&host->sg_miter)) +- BUG(); ++ int copy_words; ++ u32 hsts = 0; ++ ++ if (!sg_miter_next(&host->sg_miter)) { ++ host->data->error = -EINVAL; ++ break; ++ } + + len = min(host->sg_miter.length, blksize); +- BUG_ON(len % 4); ++ if (len % 4) { ++ host->data->error = -EINVAL; ++ break; ++ } + + blksize -= len; + host->sg_miter.consumed = len; + +- buf = host->sg_miter.addr; ++ buf = (u32 *)host->sg_miter.addr; + +- while (len) { +- if (!data_transfer_wait(host)) +- break; ++ copy_words = len/4; ++ ++ while (copy_words) { ++ int burst_words, words; ++ u32 edm; ++ ++ burst_words = SDDATA_FIFO_PIO_BURST; ++ if (burst_words > copy_words) ++ burst_words = copy_words; ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f); ++ ++ if (words < burst_words) { ++ int fsm_state = (edm & SDEDM_FSM_MASK); ++ if ((fsm_state != SDEDM_FSM_WRITEDATA) && ++ (fsm_state != SDEDM_FSM_WRITESTART1) && ++ (fsm_state != SDEDM_FSM_WRITESTART2)) { ++ hsts = bcm2835_sdhost_read(host, ++ SDHSTS); ++ pr_err("%s: fsm %x, hsts %x\n", ++ mmc_hostname(host->mmc), ++ fsm_state, hsts); ++ if (hsts & SDHSTS_ERROR_MASK) ++ break; ++ } + +- bcm2835_sdhost_write(host, *(buf++), SDDATA); +- len -= 4; ++ if (time_after(jiffies, wait_max)) { ++ pr_err("%s: PIO write timeout - EDM %x\n", ++ mmc_hostname(host->mmc), ++ edm); ++ hsts = SDHSTS_REW_TIME_OUT; ++ break; ++ } ++ ndelay((burst_words - words) * ++ host->ns_per_fifo_word); ++ continue; ++ } else if (words > copy_words) { ++ words = copy_words; ++ } ++ ++ copy_words -= words; ++ ++ while (words) { ++ bcm2835_sdhost_write(host, *(buf++), SDDATA); ++ words--; ++ } + } + +- if (host->data->error) ++ if (hsts & SDHSTS_ERROR_MASK) + break; + } + +@@ -565,12 +735,12 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) + local_irq_restore(flags); + } + +- + static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) + { + u32 sdhsts; + bool is_read; + BUG_ON(!host->data); ++ log_event("XFP<", (u32)host->data, host->blocks); + + is_read = (host->data->flags & MMC_DATA_READ) != 0; + if (is_read) +@@ -594,28 +764,21 @@ static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) + is_read ? "read" : "write", + sdhsts); + host->data->error = -ETIMEDOUT; +- } else if (!is_read && !host->data->error) { +- /* Start a timer in case a transfer error occurs because +- there is no error interrupt */ +- mod_timer(&host->pio_timer, jiffies + host->pio_timeout); + } ++ log_event("XFP>", (u32)host->data, host->blocks); + } + +- +-static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) ++static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host, ++ struct mmc_data *data) + { +- u32 len, dir_data, dir_slave; ++ int len, dir_data, dir_slave; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *dma_chan; + +- pr_debug("bcm2835_sdhost_transfer_dma()\n"); +- +- WARN_ON(!host->data); ++ log_event("PRD<", (u32)data, 0); ++ pr_debug("bcm2835_sdhost_prepare_dma()\n"); + +- if (!host->data) +- return; +- +- if (host->data->flags & MMC_DATA_READ) { ++ if (data->flags & MMC_DATA_READ) { + dma_chan = host->dma_chan_rx; + dir_data = DMA_FROM_DEVICE; + dir_slave = DMA_DEV_TO_MEM; +@@ -624,35 +787,71 @@ static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) + dir_data = DMA_TO_DEVICE; + dir_slave = DMA_MEM_TO_DEV; + } ++ log_event("PRD1", (u32)dma_chan, 0); + + BUG_ON(!dma_chan->device); + BUG_ON(!dma_chan->device->dev); +- BUG_ON(!host->data->sg); ++ BUG_ON(!data->sg); ++ ++ /* The block doesn't manage the FIFO DREQs properly for multi-block ++ transfers, so don't attempt to DMA the final few words. ++ Unfortunately this requires the final sg entry to be trimmed. ++ N.B. This code demands that the overspill is contained in ++ a single sg entry. ++ */ ++ ++ host->drain_words = 0; ++ if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) { ++ struct scatterlist *sg; ++ u32 len; ++ int i; ++ ++ len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4, ++ (u32)data->blocks * data->blksz); ++ ++ for_each_sg(data->sg, sg, data->sg_len, i) { ++ if (sg_is_last(sg)) { ++ BUG_ON(sg->length < len); ++ sg->length -= len; ++ host->drain_page = (struct page *)sg->page_link; ++ host->drain_offset = sg->offset + sg->length; ++ } ++ } ++ host->drain_words = len/4; ++ } ++ ++ len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len, ++ dir_data); + +- len = dma_map_sg(dma_chan->device->dev, host->data->sg, +- host->data->sg_len, dir_data); +- if (len > 0) { +- desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg, ++ log_event("PRD2", len, 0); ++ if (len > 0) ++ desc = dmaengine_prep_slave_sg(dma_chan, data->sg, + len, dir_slave, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +- } else { +- dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); +- } ++ log_event("PRD3", (u32)desc, 0); ++ + if (desc) { + desc->callback = bcm2835_sdhost_dma_complete; + desc->callback_param = host; +- dmaengine_submit(desc); +- dma_async_issue_pending(dma_chan); ++ host->dma_desc = desc; ++ host->dma_chan = dma_chan; ++ host->dma_dir = dir_data; + } +- ++ log_event("PDM>", (u32)data, 0); + } + ++static void bcm2835_sdhost_start_dma(struct bcm2835_host *host) ++{ ++ log_event("SDMA", (u32)host->data, (u32)host->dma_chan); ++ dmaengine_submit(host->dma_desc); ++ dma_async_issue_pending(host->dma_chan); ++} + + static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) + { + u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | + SDHCFG_BUSY_IRPT_EN; +- if (host->use_dma) ++ if (host->dma_desc) + host->hcfg = (host->hcfg & ~all_irqs) | + SDHCFG_BUSY_IRPT_EN; + else +@@ -663,13 +862,13 @@ static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + } + +- + static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd) + { + struct mmc_data *data = cmd->data; + + WARN_ON(host->data); + ++ host->data = data; + if (!data) + return; + +@@ -678,20 +877,19 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > 65535); + +- host->data = data; + host->data_complete = 0; + host->flush_fifo = 0; + host->data->bytes_xfered = 0; + +- host->use_dma = host->have_dma && (data->blocks > host->pio_limit); +- if (!host->use_dma) { ++ ++ if (!host->dma_desc) { ++ /* Use PIO */ + int flags; + +- flags = SG_MITER_ATOMIC; + if (data->flags & MMC_DATA_READ) +- flags |= SG_MITER_TO_SG; ++ flags = SG_MITER_TO_SG; + else +- flags |= SG_MITER_FROM_SG; ++ flags = SG_MITER_FROM_SG; + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); + host->blocks = data->blocks; + } +@@ -699,19 +897,20 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + bcm2835_sdhost_set_transfer_irqs(host); + + bcm2835_sdhost_write(host, data->blksz, SDHBCT); +- bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC); ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); + + BUG_ON(!host->data); + } + +- +-void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd) ++bool bcm2835_sdhost_send_command(struct bcm2835_host *host, ++ struct mmc_command *cmd) + { + u32 sdcmd, sdhsts; + unsigned long timeout; + int delay; + + WARN_ON(host->cmd); ++ log_event("CMD<", cmd->opcode, cmd->arg); + + if (cmd->data) + pr_debug("%s: send_command %d 0x%x " +@@ -734,9 +933,9 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + pr_err("%s: previous command never completed.\n", + mmc_hostname(host->mmc)); + bcm2835_sdhost_dumpregs(host); +- cmd->error = -EIO; ++ cmd->error = -EILSEQ; + tasklet_schedule(&host->finish_tasklet); +- return; ++ return false; + } + timeout--; + udelay(10); +@@ -764,23 +963,24 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + if (sdhsts & SDHSTS_ERROR_MASK) + bcm2835_sdhost_write(host, sdhsts, SDHSTS); + +- bcm2835_sdhost_prepare_data(host, cmd); +- +- bcm2835_sdhost_write(host, cmd->arg, SDARG); +- + if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { + pr_err("%s: unsupported response type!\n", + mmc_hostname(host->mmc)); + cmd->error = -EINVAL; + tasklet_schedule(&host->finish_tasklet); +- return; ++ return false; + } + ++ bcm2835_sdhost_prepare_data(host, cmd); ++ ++ bcm2835_sdhost_write(host, cmd->arg, SDARG); ++ + sdcmd = cmd->opcode & SDCMD_CMD_MASK; + +- if (!(cmd->flags & MMC_RSP_PRESENT)) ++ host->use_busy = 0; ++ if (!(cmd->flags & MMC_RSP_PRESENT)) { + sdcmd |= SDCMD_NO_RESPONSE; +- else { ++ } else { + if (cmd->flags & MMC_RSP_136) + sdcmd |= SDCMD_LONG_RESPONSE; + if (cmd->flags & MMC_RSP_BUSY) { +@@ -790,6 +990,7 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + } + + if (cmd->data) { ++ log_event("CMDD", cmd->data->blocks, cmd->data->blksz); + if (host->delay_after_stop) { + struct timeval now; + int time_since_stop; +@@ -812,10 +1013,12 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + } + + bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD); +-} + ++ return true; ++} + +-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host); ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host, ++ unsigned long *irq_flags); + static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host); + + static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) +@@ -825,6 +1028,7 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + data = host->data; + BUG_ON(!data); + ++ log_event("FDA<", (u32)host->mrq, (u32)host->cmd); + pr_debug("finish_data(error %d, stop %d, sbc %d)\n", + data->error, data->stop ? 1 : 0, + host->mrq->sbc ? 1 : 0); +@@ -832,10 +1036,7 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + +- if (data->error) { +- data->bytes_xfered = 0; +- } else +- data->bytes_xfered = data->blksz * data->blocks; ++ data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks); + + host->data_complete = 1; + +@@ -850,9 +1051,9 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + } + else + bcm2835_sdhost_transfer_complete(host); ++ log_event("FDA>", (u32)host->mrq, (u32)host->cmd); + } + +- + static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + { + struct mmc_data *data; +@@ -864,6 +1065,7 @@ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + data = host->data; + host->data = NULL; + ++ log_event("TCM<", (u32)data, data->error); + pr_debug("transfer_complete(error %d, stop %d)\n", + data->error, data->stop ? 1 : 0); + +@@ -872,88 +1074,114 @@ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + * a) open-ended multiblock transfer (no CMD23) + * b) error in multiblock transfer + */ +- if (data->stop && +- (data->error || +- !host->mrq->sbc)) { +- host->flush_fifo = 1; +- bcm2835_sdhost_send_command(host, data->stop); +- if (host->delay_after_stop) +- do_gettimeofday(&host->stop_time); +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); ++ if (host->mrq->stop && (data->error || !host->use_sbc)) { ++ if (bcm2835_sdhost_send_command(host, host->mrq->stop)) { ++ /* No busy, so poll for completion */ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, NULL); ++ ++ if (host->delay_after_stop) ++ do_gettimeofday(&host->stop_time); ++ } + } else { ++ bcm2835_sdhost_wait_transfer_complete(host); + tasklet_schedule(&host->finish_tasklet); + } ++ log_event("TCM>", (u32)data, 0); + } + +-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) ++/* If irq_flags is valid, the caller is in a thread context and is allowed ++ to sleep */ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host, ++ unsigned long *irq_flags) + { + u32 sdcmd; +- unsigned long timeout; ++ u32 retries; + #ifdef DEBUG + struct timeval before, after; + int timediff = 0; + #endif + ++ log_event("FCM<", (u32)host->mrq, (u32)host->cmd); + pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD)); + + BUG_ON(!host->cmd || !host->mrq); + +-#ifdef DEBUG +- do_gettimeofday(&before); +-#endif +- /* Wait max 100 ms */ +- timeout = 10000; ++ /* Poll quickly at first */ ++ ++ retries = host->cmd_quick_poll_retries; ++ if (!retries) { ++ /* Work out how many polls take 1us by timing 10us */ ++ struct timeval start, now; ++ int us_diff; ++ ++ retries = 1; ++ do { ++ int i; ++ ++ retries *= 2; ++ ++ do_gettimeofday(&start); ++ ++ for (i = 0; i < retries; i++) { ++ cpu_relax(); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ } ++ ++ do_gettimeofday(&now); ++ us_diff = (now.tv_sec - start.tv_sec) * 1000000 + ++ (now.tv_usec - start.tv_usec); ++ } while (us_diff < 10); ++ ++ host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1; ++ retries = 1; // We've already waited long enough this time ++ } ++ ++ retries = host->cmd_quick_poll_retries; + for (sdcmd = bcm2835_sdhost_read(host, SDCMD); +- (sdcmd & SDCMD_NEW_FLAG) && timeout; +- timeout--) { +- if (host->flush_fifo) { +- while (bcm2835_sdhost_read(host, SDHSTS) & +- SDHSTS_DATA_FLAG) +- (void)bcm2835_sdhost_read(host, SDDATA); +- } +- udelay(10); ++ (sdcmd & SDCMD_NEW_FLAG) && !(sdcmd & SDCMD_FAIL_FLAG) && retries; ++ retries--) { ++ cpu_relax(); + sdcmd = bcm2835_sdhost_read(host, SDCMD); + } +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + +- (after.tv_usec - before.tv_usec); + +- pr_debug(" finish_command - waited %dus\n", timediff); +-#endif ++ if (!retries) { ++ unsigned long wait_max; ++ ++ if (!irq_flags) { ++ /* Schedule the work */ ++ log_event("CWWQ", 0, 0); ++ schedule_work(&host->cmd_wait_wq); ++ return; ++ } ++ ++ /* Wait max 100 ms */ ++ wait_max = jiffies + msecs_to_jiffies(100); ++ while (time_before(jiffies, wait_max)) { ++ spin_unlock_irqrestore(&host->lock, *irq_flags); ++ usleep_range(1, 10); ++ spin_lock_irqsave(&host->lock, *irq_flags); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ if (!(sdcmd & SDCMD_NEW_FLAG) || ++ (sdcmd & SDCMD_FAIL_FLAG)) ++ break; ++ } ++ } + +- if (timeout == 0) { ++ /* Check for errors */ ++ if (sdcmd & SDCMD_NEW_FLAG) { + pr_err("%s: command never completed.\n", + mmc_hostname(host->mmc)); + bcm2835_sdhost_dumpregs(host); + host->cmd->error = -EIO; + tasklet_schedule(&host->finish_tasklet); + return; +- } +- +- if (host->flush_fifo) { +- for (timeout = 100; +- (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout; +- timeout--) { +- (void)bcm2835_sdhost_read(host, SDDATA); +- } +- host->flush_fifo = 0; +- if (timeout == 0) { +- pr_err("%s: FIFO never drained.\n", +- mmc_hostname(host->mmc)); +- bcm2835_sdhost_dumpregs(host); +- host->cmd->error = -EIO; +- tasklet_schedule(&host->finish_tasklet); +- return; +- } +- } +- +- /* Check for errors */ +- if (sdcmd & SDCMD_FAIL_FLAG) +- { ++ } else if (sdcmd & SDCMD_FAIL_FLAG) { + u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); + ++ /* Clear the errors */ ++ bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS); ++ + if (host->debug) + pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", + mmc_hostname(host->mmc), sdcmd, sdhsts, +@@ -976,7 +1204,7 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + mmc_hostname(host->mmc), + host->cmd->opcode); + bcm2835_sdhost_dumpregs(host); +- host->cmd->error = -EIO; ++ host->cmd->error = -EILSEQ; + } + tasklet_schedule(&host->finish_tasklet); + return; +@@ -991,31 +1219,31 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + pr_debug("%s: finish_command %08x %08x %08x %08x\n", + mmc_hostname(host->mmc), + host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]); ++ log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]); + } else { + host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0); + pr_debug("%s: finish_command %08x\n", + mmc_hostname(host->mmc), + host->cmd->resp[0]); ++ log_event("RSP ", host->cmd->resp[0], 0); + } + } + +- host->cmd->error = 0; +- + if (host->cmd == host->mrq->sbc) { + /* Finished CMD23, now send actual command. */ + host->cmd = NULL; +- bcm2835_sdhost_send_command(host, host->mrq->cmd); ++ if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) { ++ if (host->data && host->dma_desc) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_start_dma(host); + +- if (host->cmd->data && host->use_dma) +- /* DMA transfer starts now, PIO starts after irq */ +- bcm2835_sdhost_transfer_dma(host); +- +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); +- } else if (host->cmd == host->mrq->stop) ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, NULL); ++ } ++ } else if (host->cmd == host->mrq->stop) { + /* Finished CMD12 */ + tasklet_schedule(&host->finish_tasklet); +- else { ++ } else { + /* Processed actual command. */ + host->cmd = NULL; + if (!host->data) +@@ -1023,6 +1251,7 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + else if (host->data_complete) + bcm2835_sdhost_transfer_complete(host); + } ++ log_event("FCM>", (u32)host->mrq, (u32)host->cmd); + } + + static void bcm2835_sdhost_timeout(unsigned long data) +@@ -1033,10 +1262,12 @@ static void bcm2835_sdhost_timeout(unsigned long data) + host = (struct bcm2835_host *)data; + + spin_lock_irqsave(&host->lock, flags); ++ log_event("TIM<", 0, 0); + + if (host->mrq) { + pr_err("%s: timeout waiting for hardware interrupt.\n", + mmc_hostname(host->mmc)); ++ log_dump(); + bcm2835_sdhost_dumpregs(host); + + if (host->data) { +@@ -1057,74 +1288,15 @@ static void bcm2835_sdhost_timeout(unsigned long data) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void bcm2835_sdhost_pio_timeout(unsigned long data) +-{ +- struct bcm2835_host *host; +- unsigned long flags; +- +- host = (struct bcm2835_host *)data; +- +- spin_lock_irqsave(&host->lock, flags); +- +- if (host->data) { +- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); +- +- if (sdhsts & SDHSTS_REW_TIME_OUT) { +- pr_err("%s: transfer timeout\n", +- mmc_hostname(host->mmc)); +- if (host->debug) +- bcm2835_sdhost_dumpregs(host); +- } else { +- pr_err("%s: unexpected transfer timeout\n", +- mmc_hostname(host->mmc)); +- bcm2835_sdhost_dumpregs(host); +- } +- +- bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK, +- SDHSTS); +- +- host->data->error = -ETIMEDOUT; +- +- bcm2835_sdhost_finish_data(host); +- } +- +- mmiowb(); +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) ++static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + { +- if (enable) +- host->hcfg |= SDHCFG_SDIO_IRPT_EN; +- else +- host->hcfg &= ~SDHCFG_SDIO_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- mmiowb(); +-} +- +-static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable) +-{ +- struct bcm2835_host *host = mmc_priv(mmc); +- unsigned long flags; +- +- pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable); +- spin_lock_irqsave(&host->lock, flags); +- bcm2835_sdhost_enable_sdio_irq_nolock(host, enable); +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) +-{ +- const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT | +- SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | +- SDHSTS_FIFO_ERROR); +- ++ log_event("IRQB", (u32)host->cmd, intmask); + if (!host->cmd) { + pr_err("%s: got command busy interrupt 0x%08x even " + "though no command operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return 0; ++ return; + } + + if (!host->use_busy) { +@@ -1132,7 +1304,7 @@ static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + "though not expecting one.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return 0; ++ return; + } + host->use_busy = 0; + +@@ -1155,28 +1327,23 @@ static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + } else if (intmask & SDHSTS_CMD_TIME_OUT) + host->cmd->error = -ETIMEDOUT; + ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); + } + else +- bcm2835_sdhost_finish_command(host); +- +- return handled; ++ bcm2835_sdhost_finish_command(host, NULL); + } + +-static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) ++static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) + { +- const u32 handled = (SDHSTS_REW_TIME_OUT | +- SDHSTS_CRC16_ERROR | +- SDHSTS_FIFO_ERROR); +- + /* There are no dedicated data/space available interrupt + status bits, so it is necessary to use the single shared + data/space available FIFO status bits. It is therefore not + an error to get here when there is no data transfer in + progress. */ ++ log_event("IRQD", (u32)host->data, intmask); + if (!host->data) +- return 0; ++ return; + + if (intmask & (SDHSTS_CRC16_ERROR | + SDHSTS_FIFO_ERROR | +@@ -1187,46 +1354,37 @@ static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) + else + host->data->error = -ETIMEDOUT; + +- bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); +- return handled; ++ if (host->debug) { ++ log_dump(); ++ bcm2835_sdhost_dumpregs(host); ++ } + } + +- /* Use the block interrupt for writes after the first block */ +- if (host->data->flags & MMC_DATA_WRITE) { ++ if (host->data->error) { ++ bcm2835_sdhost_finish_data(host); ++ } else if (host->data->flags & MMC_DATA_WRITE) { ++ /* Use the block interrupt for writes after the first block */ + host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); + host->hcfg |= SDHCFG_BLOCK_IRPT_EN; + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- if (host->data->error) +- bcm2835_sdhost_finish_data(host); +- else +- bcm2835_sdhost_transfer_pio(host); ++ bcm2835_sdhost_transfer_pio(host); + } else { +- if (!host->data->error) { +- bcm2835_sdhost_transfer_pio(host); +- host->blocks--; +- } ++ bcm2835_sdhost_transfer_pio(host); ++ host->blocks--; + if ((host->blocks == 0) || host->data->error) + bcm2835_sdhost_finish_data(host); + } +- +- return handled; + } + +-static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) ++static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) + { +- struct dma_chan *dma_chan; +- u32 dir_data; +- const u32 handled = (SDHSTS_REW_TIME_OUT | +- SDHSTS_CRC16_ERROR | +- SDHSTS_FIFO_ERROR); +- ++ log_event("IRQK", (u32)host->data, intmask); + if (!host->data) { + pr_err("%s: got block interrupt 0x%08x even " + "though no data operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return handled; ++ return; + } + + if (intmask & (SDHSTS_CRC16_ERROR | +@@ -1238,158 +1396,69 @@ static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) + else + host->data->error = -ETIMEDOUT; + +- if (host->debug) ++ if (host->debug) { ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); +- return handled; ++ } + } + +- if (!host->use_dma) { ++ if (!host->dma_desc) { + BUG_ON(!host->blocks); +- host->blocks--; +- if ((host->blocks == 0) || host->data->error) { +- /* Cancel the timer */ +- del_timer(&host->pio_timer); +- ++ if (host->data->error || (--host->blocks == 0)) { + bcm2835_sdhost_finish_data(host); + } else { + bcm2835_sdhost_transfer_pio(host); +- +- /* Reset the timer */ +- mod_timer(&host->pio_timer, +- jiffies + host->pio_timeout); + } + } else if (host->data->flags & MMC_DATA_WRITE) { +- dma_chan = host->dma_chan_tx; +- dir_data = DMA_TO_DEVICE; +- dma_unmap_sg(dma_chan->device->dev, +- host->data->sg, host->data->sg_len, +- dir_data); +- + bcm2835_sdhost_finish_data(host); + } +- +- return handled; + } + +- + static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id) + { + irqreturn_t result = IRQ_NONE; + struct bcm2835_host *host = dev_id; +- u32 unexpected = 0, early = 0; +- int loops = 0; +-#ifndef CONFIG_ARCH_BCM2835 +- int cardint = 0; +-#endif +- spin_lock(&host->lock); ++ u32 intmask; + +- for (loops = 0; loops < 1; loops++) { +- u32 intmask, handled; +- +- intmask = bcm2835_sdhost_read(host, SDHSTS); +- handled = intmask & (SDHSTS_BUSY_IRPT | +- SDHSTS_BLOCK_IRPT | +- SDHSTS_SDIO_IRPT | +- SDHSTS_DATA_FLAG); +- if ((handled == SDHSTS_DATA_FLAG) && +- (loops == 0) && !host->data) { +- pr_err("%s: sdhost_irq data interrupt 0x%08x even " +- "though no data operation was in progress.\n", +- mmc_hostname(host->mmc), +- (unsigned)intmask); +- +- bcm2835_sdhost_dumpregs(host); +- } ++ spin_lock(&host->lock); + +- if (!handled) +- break; ++ intmask = bcm2835_sdhost_read(host, SDHSTS); ++ log_event("IRQ<", intmask, 0); + +- if (loops) +- early |= handled; ++ bcm2835_sdhost_write(host, ++ SDHSTS_BUSY_IRPT | ++ SDHSTS_BLOCK_IRPT | ++ SDHSTS_SDIO_IRPT | ++ SDHSTS_DATA_FLAG, ++ SDHSTS); + ++ if (intmask & SDHSTS_BLOCK_IRPT) { ++ bcm2835_sdhost_block_irq(host, intmask); + result = IRQ_HANDLED; ++ } + +- /* Clear all interrupts and notifications */ +- bcm2835_sdhost_write(host, intmask, SDHSTS); +- +- if (intmask & SDHSTS_BUSY_IRPT) +- handled |= bcm2835_sdhost_busy_irq(host, intmask); +- +- /* There is no true data interrupt status bit, so it is +- necessary to qualify the data flag with the interrupt +- enable bit */ +- if ((intmask & SDHSTS_DATA_FLAG) && +- (host->hcfg & SDHCFG_DATA_IRPT_EN)) +- handled |= bcm2835_sdhost_data_irq(host, intmask); +- +- if (intmask & SDHSTS_BLOCK_IRPT) +- handled |= bcm2835_sdhost_block_irq(host, intmask); +- +- if (intmask & SDHSTS_SDIO_IRPT) { +-#ifndef CONFIG_ARCH_BCM2835 +- cardint = 1; +-#else +- bcm2835_sdhost_enable_sdio_irq_nolock(host, false); +- host->thread_isr |= SDHSTS_SDIO_IRPT; +- result = IRQ_WAKE_THREAD; +-#endif +- } ++ if (intmask & SDHSTS_BUSY_IRPT) { ++ bcm2835_sdhost_busy_irq(host, intmask); ++ result = IRQ_HANDLED; ++ } + +- unexpected |= (intmask & ~handled); ++ /* There is no true data interrupt status bit, so it is ++ necessary to qualify the data flag with the interrupt ++ enable bit */ ++ if ((intmask & SDHSTS_DATA_FLAG) && ++ (host->hcfg & SDHCFG_DATA_IRPT_EN)) { ++ bcm2835_sdhost_data_irq(host, intmask); ++ result = IRQ_HANDLED; + } + + mmiowb(); + ++ log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0); + spin_unlock(&host->lock); + +- if (early) +- pr_debug("%s: early %x (loops %d)\n", +- mmc_hostname(host->mmc), early, loops); +- +- if (unexpected) { +- pr_err("%s: unexpected interrupt 0x%08x.\n", +- mmc_hostname(host->mmc), unexpected); +- bcm2835_sdhost_dumpregs(host); +- } +- +-#ifndef CONFIG_ARCH_BCM2835 +- if (cardint) +- mmc_signal_sdio_irq(host->mmc); +-#endif +- + return result; + } + +-#ifdef CONFIG_ARCH_BCM2835 +-static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id) +-{ +- struct bcm2835_host *host = dev_id; +- unsigned long flags; +- u32 isr; +- +- spin_lock_irqsave(&host->lock, flags); +- isr = host->thread_isr; +- host->thread_isr = 0; +- spin_unlock_irqrestore(&host->lock, flags); +- +- if (isr & SDHSTS_SDIO_IRPT) { +- sdio_run_irqs(host->mmc); +- +-/* Is this necessary? Why re-enable an interrupt which is enabled? +- spin_lock_irqsave(&host->lock, flags); +- if (host->flags & SDHSTS_SDIO_IRPT_ENABLED) +- bcm2835_sdhost_enable_sdio_irq_nolock(host, true); +- spin_unlock_irqrestore(&host->lock, flags); +-*/ +- } +- +- return isr ? IRQ_HANDLED : IRQ_NONE; +-} +-#endif +- +- +- + void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + { + int div = 0; /* Initialized for compiler warning */ +@@ -1399,9 +1468,8 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock); + + if ((host->overclock_50 > 50) && +- (clock == 50*MHZ)) { ++ (clock == 50*MHZ)) + clock = host->overclock_50 * MHZ + (MHZ - 1); +- } + + /* The SDCDIV register has 11 bits, and holds (div - 2). + But in data mode the max is 50MHz wihout a minimum, and only the +@@ -1448,6 +1516,11 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + clock = host->max_clk / (div + 2); + host->mmc->actual_clock = clock; + ++ /* Calibrate some delays */ ++ ++ host->ns_per_fifo_word = (1000000000/clock) * ++ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); ++ + if (clock > input_clock) { + /* Save the closest value, to make it easier + to reduce in the event of error */ +@@ -1483,6 +1556,7 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + { + struct bcm2835_host *host; + unsigned long flags; ++ u32 edm, fsm; + + host = mmc_priv(mmc); + +@@ -1503,6 +1577,8 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + } + + /* Reset the error statuses in case this is a retry */ ++ if (mrq->sbc) ++ mrq->sbc->error = 0; + if (mrq->cmd) + mrq->cmd->error = 0; + if (mrq->data) +@@ -1518,28 +1594,58 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + return; + } + ++ if (host->use_dma && mrq->data && ++ (mrq->data->blocks > host->pio_limit)) ++ bcm2835_sdhost_prepare_dma(host, mrq->data); ++ + spin_lock_irqsave(&host->lock, flags); + + WARN_ON(host->mrq != NULL); +- + host->mrq = mrq; + +- if (mrq->sbc) +- bcm2835_sdhost_send_command(host, mrq->sbc); +- else +- bcm2835_sdhost_send_command(host, mrq->cmd); ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ fsm = edm & SDEDM_FSM_MASK; + +- mmiowb(); +- spin_unlock_irqrestore(&host->lock, flags); ++ log_event("REQ<", (u32)mrq, edm); ++ if ((fsm != SDEDM_FSM_IDENTMODE) && ++ (fsm != SDEDM_FSM_DATAMODE)) { ++ pr_err("%s: previous command (%d) not complete (EDM %x)\n", ++ mmc_hostname(host->mmc), ++ bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK, ++ edm); ++ log_event("REQ!", (u32)mrq, edm); ++ log_dump(); ++ bcm2835_sdhost_dumpregs(host); ++ mrq->cmd->error = -EILSEQ; ++ tasklet_schedule(&host->finish_tasklet); ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } + +- if (!mrq->sbc && mrq->cmd->data && host->use_dma) +- /* DMA transfer starts now, PIO starts after irq */ +- bcm2835_sdhost_transfer_dma(host); ++ host->use_sbc = !!mrq->sbc && ++ (host->mrq->data->flags & USE_CMD23_FLAGS); ++ if (host->use_sbc) { ++ if (bcm2835_sdhost_send_command(host, mrq->sbc)) { ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, &flags); ++ } ++ } else if (bcm2835_sdhost_send_command(host, mrq->cmd)) { ++ if (host->data && host->dma_desc) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_start_dma(host); + +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); +-} ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, &flags); ++ } ++ ++ log_event("CMD ", (u32)mrq->cmd->opcode, ++ mrq->data ? (u32)mrq->data->blksz : 0); ++ mmiowb(); + ++ log_event("REQ>", (u32)mrq, 0); ++ spin_unlock_irqrestore(&host->lock, flags); ++} + + static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { +@@ -1556,6 +1662,8 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + spin_lock_irqsave(&host->lock, flags); + ++ log_event("IOS<", ios->clock, 0); ++ + if (!ios->clock || ios->clock != host->clock) { + bcm2835_sdhost_set_clock(host, ios->clock); + host->clock = ios->clock; +@@ -1578,44 +1686,53 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, int blk_size) +-{ +- /* There is a bug in the host controller hardware that makes +- reading the final sector of the card as part of a multiple read +- problematic. Detect that case and shorten the read accordingly. +- */ +- /* csd.capacity is in weird units - convert to sectors */ +- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9)); +- +- if ((direction == MMC_DATA_READ) && +- ((blk_pos + blk_size) == card_sectors)) +- blk_size--; +- +- return blk_size; +-} +- +- + static struct mmc_host_ops bcm2835_sdhost_ops = { + .request = bcm2835_sdhost_request, + .set_ios = bcm2835_sdhost_set_ios, +- .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, + .hw_reset = bcm2835_sdhost_reset, +- .multi_io_quirk = bcm2835_sdhost_multi_io_quirk, + }; + ++static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ host = container_of(work, struct bcm2835_host, cmd_wait_wq); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ log_event("CWK<", (u32)host->cmd, (u32)host->mrq); ++ ++ /* ++ * If this tasklet gets rescheduled while running, it will ++ * be run again afterwards but without any active request. ++ */ ++ if (!host->mrq) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ ++ bcm2835_sdhost_finish_command(host, &flags); ++ ++ mmiowb(); ++ ++ log_event("CWK>", (u32)host->cmd, 0); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} + + static void bcm2835_sdhost_tasklet_finish(unsigned long param) + { + struct bcm2835_host *host; + unsigned long flags; + struct mmc_request *mrq; ++ struct dma_chan *terminate_chan = NULL; + + host = (struct bcm2835_host *)param; + + spin_lock_irqsave(&host->lock, flags); + ++ log_event("TSK<", (u32)host->mrq, 0); + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. +@@ -1650,11 +1767,23 @@ static void bcm2835_sdhost_tasklet_finish(unsigned long param) + + mmiowb(); + ++ host->dma_desc = NULL; ++ terminate_chan = host->dma_chan; ++ host->dma_chan = NULL; ++ + spin_unlock_irqrestore(&host->lock, flags); +- mmc_request_done(host->mmc, mrq); +-} + ++ if (terminate_chan) ++ { ++ int err = dmaengine_terminate_all(terminate_chan); ++ if (err) ++ pr_err("%s: failed to terminate DMA (%d)\n", ++ mmc_hostname(host->mmc), err); ++ } + ++ mmc_request_done(host->mmc, mrq); ++ log_event("TSK>", (u32)mrq, 0); ++} + + int bcm2835_sdhost_add_host(struct bcm2835_host *host) + { +@@ -1676,10 +1805,10 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc->f_max, mmc->f_min, mmc->max_busy_timeout); + + /* host controller capabilities */ +- mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ mmc->caps |= + MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE | +- (ALLOW_CMD23 * MMC_CAP_CMD23); ++ ((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23); + + spin_lock_init(&host->lock); + +@@ -1689,9 +1818,9 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + pr_err("%s: unable to initialise DMA channels. " + "Falling back to PIO\n", + mmc_hostname(mmc)); +- host->have_dma = false; ++ host->use_dma = false; + } else { +- host->have_dma = true; ++ host->use_dma = true; + + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +@@ -1708,7 +1837,7 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } + } else { +- host->have_dma = false; ++ host->use_dma = false; + } + + mmc->max_segs = 128; +@@ -1723,21 +1852,15 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + tasklet_init(&host->finish_tasklet, + bcm2835_sdhost_tasklet_finish, (unsigned long)host); + +- setup_timer(&host->timer, bcm2835_sdhost_timeout, +- (unsigned long)host); ++ INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work); + +- setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout, ++ setup_timer(&host->timer, bcm2835_sdhost_timeout, + (unsigned long)host); + + bcm2835_sdhost_init(host, 0); +-#ifndef CONFIG_ARCH_BCM2835 ++ + ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/, + mmc_hostname(mmc), host); +-#else +- ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, +- bcm2835_sdhost_thread_irq, +- IRQF_SHARED, mmc_hostname(mmc), host); +-#endif + if (ret) { + pr_err("%s: failed to request IRQ %d: %d\n", + mmc_hostname(mmc), host->irq, ret); +@@ -1748,11 +1871,11 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc_add_host(mmc); + + pio_limit_string[0] = '\0'; +- if (host->have_dma && (host->pio_limit > 0)) ++ if (host->use_dma && (host->pio_limit > 0)) + sprintf(pio_limit_string, " (>%d)", host->pio_limit); + pr_info("%s: %s loaded - DMA %s%s\n", + mmc_hostname(mmc), DRIVER_NAME, +- host->have_dma ? "enabled" : "disabled", ++ host->use_dma ? "enabled" : "disabled", + pio_limit_string); + + return 0; +@@ -1774,6 +1897,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + int ret; + + pr_debug("bcm2835_sdhost_probe\n"); ++ log_init(); + mmc = mmc_alloc_host(sizeof(*host), dev); + if (!mmc) + return -ENOMEM; +@@ -1781,8 +1905,11 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + mmc->ops = &bcm2835_sdhost_ops; + host = mmc_priv(mmc); + host->mmc = mmc; ++ host->cmd_quick_poll_retries = 0; + host->pio_timeout = msecs_to_jiffies(500); ++ host->pio_limit = 1; + host->max_delay = 1; /* Warn if over 1ms */ ++ host->allow_dma = 1; + spin_lock_init(&host->lock); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1798,8 +1925,6 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + (unsigned long)iomem->start, + (unsigned long)host->phys_addr); + +- host->allow_dma = ALLOW_DMA; +- + if (node) { + /* Read any custom properties */ + of_property_read_u32(node, +@@ -1811,11 +1936,18 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + of_property_read_u32(node, + "brcm,pio-limit", + &host->pio_limit); +- host->allow_dma = ALLOW_DMA && ++ host->allow_dma = + !of_property_read_bool(node, "brcm,force-pio"); + host->debug = of_property_read_bool(node, "brcm,debug"); + } + ++ host->dma_chan = NULL; ++ host->dma_desc = NULL; ++ ++ /* Formally recognise the other way of disabling DMA */ ++ if (host->pio_limit == 0x7fffffff) ++ host->allow_dma = false; ++ + if (host->allow_dma) { + if (node) { + host->dma_chan_tx = +@@ -1900,15 +2032,12 @@ static int bcm2835_sdhost_remove(struct platform_device *pdev) + return 0; + } + +- + static const struct of_device_id bcm2835_sdhost_match[] = { + { .compatible = "brcm,bcm2835-sdhost" }, + { } + }; + MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match); + +- +- + static struct platform_driver bcm2835_sdhost_driver = { + .probe = bcm2835_sdhost_probe, + .remove = bcm2835_sdhost_remove, + +From b6b2c6595459c46765517f681901a6b31dfb4d47 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 12 Feb 2016 15:38:00 +0000 +Subject: [PATCH 265/278] BCM270X_DT: Use bcm2835-sdhost as standard + +Also add new base dtparams sd_overclock, sd_force_pio, +sd_pio_limit and sd_debug. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 15 +++++++-- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 15 +++++++-- + arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 - + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 20 ++++++++++-- + arch/arm/boot/dts/bcm2708_common.dtsi | 17 +++++++++- + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 15 +++++++-- + arch/arm/boot/dts/overlays/README | 11 ++++++- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 32 ++++++++++++++++-- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 47 +++++++-------------------- + 9 files changed, 124 insertions(+), 49 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index d41d31c..f75f771 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -128,5 +135,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 684852f..26e968f 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -118,5 +125,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +index ec4bfef..b776f4c 100755 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +@@ -91,6 +91,5 @@ + i2c0_baudrate = <&i2c0>,"clock-frequency:0"; + i2c1_baudrate = <&i2c1>,"clock-frequency:0"; + i2c2_baudrate = <&i2c2>,"clock-frequency:0"; +- core_freq = <&clk_core>,"clock-frequency:0"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 713e5a2..a85d9d6 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,5 +1,12 @@ + /include/ "bcm2708.dtsi" + ++&gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++}; ++ + &leds { + act_led: act { + label = "led0"; +@@ -8,9 +15,12 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ non-removable; ++ status = "okay"; + }; + + &fb { +@@ -19,6 +29,8 @@ + + / { + __overrides__ { ++ core_freq = <&clk_core>,"clock-frequency:0"; ++ + act_led_gpio = <&act_led>,"gpios:4"; + act_led_activelow = <&act_led>,"gpios:8"; + act_led_trigger = <&act_led>,"linux,default-trigger"; +@@ -26,5 +38,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 924edc8..4c8ce77 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,6 +14,7 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; ++ sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -65,7 +66,7 @@ + brcm,dma-channel-mask = <0x0f35>; + }; + +- intc: interrupt-controller { ++ intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2708-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; +@@ -126,6 +127,19 @@ + status = "disabled"; + }; + ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "disabled"; ++ }; ++ + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +@@ -191,6 +205,7 @@ + dmas = <&dma 11>, + <&dma 11>; + dma-names = "tx", "rx"; ++ brcm,overclock-50 = <0>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index a8e8b7c..24aa53a 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -128,5 +135,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 3f7a25d..3aaa3da 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -112,6 +112,16 @@ Params: + random Set to "on" to enable the hardware random + number generator (default "on") + ++ sd_overclock Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ ++ sd_force_pio Disable DMA support for SD driver (default off) ++ ++ sd_pio_limit Number of blocks above which to use DMA for ++ SD card (default 1) ++ ++ sd_debug Enable debug output from SD driver (default off) ++ + uart0 Set to "off" to disable uart0 (default "on") + + watchdog Set to "on" to enable the hardware watchdog +@@ -422,7 +432,6 @@ Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock + Load: dtoverlay=mmc,= + Params: overclock_50 Clock (in MHz) to use when the MMC framework + requests 50MHz +- force_pio Disable DMA support + + + Name: mz61581 +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 4579ff2..2222fd8 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,14 +6,42 @@ + + fragment@0 { + target = <&mmc>; +- + frag0: __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc_pins>; ++ bus-width = <4>; + brcm,overclock-50 = <0>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ mmc_pins: mmc_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <7>; /* alt3 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sdhost>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ /* Redirect the existing sd_overclock and sd_force_pio dtparams */ ++ fragment@3 { ++ target-path = "/__overrides__"; ++ ++ __overlay__ { ++ sd_overclock = <&mmc>,"brcm,overclock-50:0"; + }; + }; + + __overrides__ { + overclock_50 = <&frag0>,"brcm,overclock-50:0"; +- force_pio = <&frag0>,"brcm,force-pio?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 2da14a4..de3d1b0 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -1,56 +1,31 @@ + /dts-v1/; + /plugin/; + ++/* Provide backwards compatible aliases for the old sdhost dtparams. */ ++ + /{ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; +- __overlay__ { +- #address-cells = <1>; +- #size-cells = <1>; +- +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,delay-after-stop = <0>; +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; +- }; ++ target = <&sdhost>; ++ frag0: __overlay__ { ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; + }; + }; + + fragment@1 { +- target = <&gpio>; +- __overlay__ { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- }; +- }; +- +- fragment@2 { + target = <&mmc>; + __overlay__ { +- /* Find a way to disable the other driver */ +- compatible = ""; + status = "disabled"; + }; + }; + + __overrides__ { +- overclock_50 = <&sdhost>,"brcm,overclock-50:0"; +- force_pio = <&sdhost>,"brcm,force-pio?"; +- pio_limit = <&sdhost>,"brcm,pio-limit:0"; +- debug = <&sdhost>,"brcm,debug?"; ++ overclock_50 = <&frag0>,"brcm,overclock-50:0"; ++ force_pio = <&frag0>,"brcm,force-pio?"; ++ pio_limit = <&frag0>,"brcm,pio-limit:0"; ++ debug = <&frag0>,"brcm,debug?"; + }; + }; + +From 3fa93dd52f7a97f68efff0b96838eacc6e8de795 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 12 Feb 2016 14:50:25 +0000 +Subject: [PATCH 266/278] dcw_otg: trim xfer length when buffer larger than + allocated size is received + +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +index 8db3dfc..d672a76 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -737,6 +737,11 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, + DWC_OTG_HC_XFER_COMPLETE, + &short_read); + ++ if (urb->actual_length + xfer_length > urb->length) { ++ DWC_WARN("%s(): trimming xfer length\n", __func__); ++ xfer_length = urb->length - urb->actual_length; ++ } ++ + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && xfer_length && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, +@@ -1423,6 +1428,12 @@ static void update_urb_state_xfer_intr(dwc_hc_t * hc, + { + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd, + halt_status, NULL); ++ ++ if (urb->actual_length + bytes_transferred > urb->length) { ++ DWC_WARN("%s(): trimming xfer length\n", __func__); ++ bytes_transferred = urb->length - urb->actual_length; ++ } ++ + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && bytes_transferred && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, + +From bb93822cc5f82f48c32b2e01371f45ad2a006d9e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 15 Feb 2016 10:00:27 +0000 +Subject: [PATCH 267/278] bcm2835-sdhost: Restore ATOMIC flag to PIO sg mapping + +Allocation problems have been seen in a wireless driver, and +this is the only change which might have been responsible. +--- + drivers/mmc/host/bcm2835-sdhost.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 84d120f..13b9d38 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -881,15 +881,14 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + host->flush_fifo = 0; + host->data->bytes_xfered = 0; + +- + if (!host->dma_desc) { + /* Use PIO */ +- int flags; ++ int flags = SG_MITER_ATOMIC; + + if (data->flags & MMC_DATA_READ) +- flags = SG_MITER_TO_SG; ++ flags |= SG_MITER_TO_SG; + else +- flags = SG_MITER_FROM_SG; ++ flags |= SG_MITER_FROM_SG; + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); + host->blocks = data->blocks; + } + +From 3a62fd51d873754d49b0ccbc525e5542a7554b15 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 16 Feb 2016 08:47:56 +0000 +Subject: [PATCH 268/278] Revert "Add blk_pos parameter to mmc multi_io_quirk + callback" + +This reverts commit aab95f9b10e8c3d32de2bf163b86f220c88214fe. + +The bcm2835-sdhost driver no longer needs this patch. +--- + drivers/mmc/card/block.c | 1 - + drivers/mmc/host/omap_hsmmc.c | 4 +--- + drivers/mmc/host/sh_mobile_sdhi.c | 4 +--- + drivers/mmc/host/tmio_mmc_pio.c | 4 +--- + include/linux/mmc/host.h | 4 +--- + 5 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index 8484ec9..31d2627 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1415,7 +1415,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + brq->data.blocks = card->host->ops->multi_io_quirk(card, + (rq_data_dir(req) == READ) ? + MMC_DATA_READ : MMC_DATA_WRITE, +- blk_rq_pos(req), + brq->data.blocks); + } + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index ebb6bf4..d0abdffb 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1749,9 +1749,7 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) + } + + static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + /* This controller can't do multiblock reads due to hw bugs */ + if (direction == MMC_DATA_READ) +diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c +index 4f1ccf3..354f4f3 100644 +--- a/drivers/mmc/host/sh_mobile_sdhi.c ++++ b/drivers/mmc/host/sh_mobile_sdhi.c +@@ -170,9 +170,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) + } + + static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + /* + * In Renesas controllers, when performing a +diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c +index 0c87f4f..dba7e1c 100644 +--- a/drivers/mmc/host/tmio_mmc_pio.c ++++ b/drivers/mmc/host/tmio_mmc_pio.c +@@ -1001,9 +1001,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) + } + + static int tmio_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + struct tmio_mmc_host *host = mmc_priv(card->host); + +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index d3cdad9..b0258e8 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -140,9 +140,7 @@ struct mmc_host_ops { + * I/O. Returns the number of supported blocks for the request. + */ + int (*multi_io_quirk)(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size); ++ unsigned int direction, int blk_size); + }; + + struct mmc_card; + +From 462c17a8e24cc362d233d674e84d1c7f9a937ced Mon Sep 17 00:00:00 2001 +From: Craig Roberts +Date: Tue, 16 Feb 2016 10:03:42 +0000 +Subject: [PATCH 269/278] Updated smsc95xx driver to check for a valid MAC + address in eeprom before using smsc95xx.macaddr parameter passed on command + line. + +The built-in RPi adaptor will still get a MAC address based on the parameter passed on the command line as the RPi hardware does not have an eeprom, +however usb->ethernet adaptors using the same driver should have an eeprom with MAC address as part of their hardware and therefore will use this +meaning they don't end up with the same MAC address as the built-in RPi adaptor. +--- + drivers/net/usb/smsc95xx.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index f664c1b..6dec199 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -821,10 +821,6 @@ static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac) + + static void smsc95xx_init_mac_address(struct usbnet *dev) + { +- /* Check module parameters */ +- if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) +- return; +- + /* try reading mac address from EEPROM */ + if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { +@@ -835,7 +831,11 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) + } + } + +- /* no eeprom, or eeprom values are invalid. generate random MAC */ ++ /* Check module parameters */ ++ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) ++ return; ++ ++ /* no eeprom, or eeprom values are invalid, and no module parameter specified to set MAC. Generate random MAC */ + eth_hw_addr_random(dev->net); + netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); + } + +From 041772c61aaedcda1f900d404d656041186a3f92 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 17 Feb 2016 19:02:31 +0000 +Subject: [PATCH 270/278] dcw_otg: Make trimming messages less noisy + +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +index d672a76..e6b38ac3 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -738,7 +738,8 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, + &short_read); + + if (urb->actual_length + xfer_length > urb->length) { +- DWC_WARN("%s(): trimming xfer length\n", __func__); ++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n", ++ hc->dev_addr, __func__, __LINE__); + xfer_length = urb->length - urb->actual_length; + } + +@@ -1430,7 +1431,8 @@ static void update_urb_state_xfer_intr(dwc_hc_t * hc, + halt_status, NULL); + + if (urb->actual_length + bytes_transferred > urb->length) { +- DWC_WARN("%s(): trimming xfer length\n", __func__); ++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n", ++ hc->dev_addr, __func__, __LINE__); + bytes_transferred = urb->length - urb->actual_length; + } + + +From 39af28b0dec15877e252808fe742ac5fe0fefc44 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 18 Feb 2016 15:28:14 +0000 +Subject: [PATCH 271/278] BCM270X_DT: at86rf233 overlay - drop to 3MHz + +The consensus is that 6MHz is too fast, but that 3MHz is OK. + +See: https://github.com/raspberrypi/linux/issues/1294 + https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts -index 70f50ea..0460269 100644 +index 0460269..eab4052 100644 --- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts @@ -25,7 +25,7 @@ interrupts = <23 4>; /* active high */ reset-gpio = <&gpio 24 1>; sleep-gpio = <&gpio 25 1>; -- spi-max-frequency = <7500000>; -+ spi-max-frequency = <6000000>; +- spi-max-frequency = <6000000>; ++ spi-max-frequency = <3000000>; xtal-trim = /bits/ 8 <0xf>; }; }; -From 625d90e2f7b2de52e0ba82e66e076915402e9c8b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 1 Oct 2015 11:49:11 +0100 -Subject: [PATCH 201/204] config: Add CONFIG_UHID - ---- - 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 6f4021b..6a914fb 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -843,6 +843,7 @@ CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y -+CONFIG_UHID=m - CONFIG_HID_A4TECH=m - CONFIG_HID_ACRUX=m - CONFIG_HID_APPLE=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 015540b..7a477e3 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -836,6 +836,7 @@ CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y -+CONFIG_UHID=m - CONFIG_HID_A4TECH=m - CONFIG_HID_ACRUX=m - CONFIG_HID_APPLE=m - -From 7a8dc0c298b4619fe8658481d0b3ae0ac1231a5e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 4 Oct 2015 12:30:01 +0100 -Subject: [PATCH 202/204] config: Add CONFIG_CRYPTO_USER_API_SKCIPHER - ---- - 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 6a914fb..05383c0 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -1239,6 +1239,7 @@ CONFIG_CRYPTO_WP512=m - CONFIG_CRYPTO_CAST5=m - CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set -+CONFIG_CRYPTO_USER_API_SKCIPHER=m - # CONFIG_CRYPTO_HW is not set - CONFIG_ARM_CRYPTO=y - CONFIG_CRYPTO_SHA1_ARM_NEON=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 7a477e3..0f315d8 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -1235,6 +1235,7 @@ CONFIG_CRYPTO_WP512=m - CONFIG_CRYPTO_CAST5=m - CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set -+CONFIG_CRYPTO_USER_API_SKCIPHER=m - # CONFIG_CRYPTO_HW is not set - CONFIG_ARM_CRYPTO=y - CONFIG_CRYPTO_SHA1_ARM=m - -From c7158fd021cf31f5fb67768796aecabde5ff6727 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 4 Oct 2015 12:36:44 +0100 -Subject: [PATCH 203/204] config: Add options for supporting openlabs 802.15.4 - radio - ---- - arch/arm/configs/bcm2709_defconfig | 6 ++++++ - arch/arm/configs/bcmrpi_defconfig | 6 ++++++ - 2 files changed, 12 insertions(+) - -diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 05383c0..fb402e8 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -283,6 +283,9 @@ CONFIG_VLAN_8021Q=m - CONFIG_VLAN_8021Q_GVRP=y - CONFIG_ATALK=m - CONFIG_6LOWPAN=m -+CONFIG_IEEE802154=m -+CONFIG_IEEE802154_6LOWPAN=m -+CONFIG_MAC802154=m - CONFIG_NET_SCHED=y - CONFIG_NET_SCH_CBQ=m - CONFIG_NET_SCH_HTB=m -@@ -529,6 +532,9 @@ CONFIG_ZD1211RW=m - CONFIG_MWIFIEX=m - CONFIG_MWIFIEX_SDIO=m - CONFIG_WIMAX_I2400M_USB=m -+CONFIG_IEEE802154_AT86RF230=m -+CONFIG_IEEE802154_MRF24J40=m -+CONFIG_IEEE802154_CC2520=m - CONFIG_INPUT_POLLDEV=m - # CONFIG_INPUT_MOUSEDEV_PSAUX is not set - CONFIG_INPUT_JOYDEV=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 0f315d8..eb81555e 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -276,6 +276,9 @@ CONFIG_VLAN_8021Q=m - CONFIG_VLAN_8021Q_GVRP=y - CONFIG_ATALK=m - CONFIG_6LOWPAN=m -+CONFIG_IEEE802154=m -+CONFIG_IEEE802154_6LOWPAN=m -+CONFIG_MAC802154=m - CONFIG_NET_SCHED=y - CONFIG_NET_SCH_CBQ=m - CONFIG_NET_SCH_HTB=m -@@ -522,6 +525,9 @@ CONFIG_ZD1211RW=m - CONFIG_MWIFIEX=m - CONFIG_MWIFIEX_SDIO=m - CONFIG_WIMAX_I2400M_USB=m -+CONFIG_IEEE802154_AT86RF230=m -+CONFIG_IEEE802154_MRF24J40=m -+CONFIG_IEEE802154_CC2520=m - CONFIG_INPUT_POLLDEV=m - # CONFIG_INPUT_MOUSEDEV_PSAUX is not set - CONFIG_INPUT_JOYDEV=m - -From 6c1d6379ed6d95956ba255936da39f06543ddb7f Mon Sep 17 00:00:00 2001 +From 3d3db343497bb670583f20a835deb0c082f68ec0 Mon Sep 17 00:00:00 2001 From: Phil Elwell -Date: Thu, 8 Oct 2015 13:33:28 +0100 -Subject: [PATCH 204/204] scripts/mkknlimg: Improve ARCH_BCM2835 detection +Date: Thu, 18 Feb 2016 16:23:12 +0000 +Subject: [PATCH 272/278] SQUASH: Update overlay README for at86rf233 -The board support code contains sufficient strings to be able to -distinguish 2708 vs. 2835 builds, so remove the check for -bcm2835-pm-wdt which could exist in either. - -Also, since the canned configuration is no longer built in (it's -a module), remove the config string checking. - -See: https://github.com/raspberrypi/linux/issues/1157 --- - scripts/mkknlimg | 41 +++++------------------------------------ - 1 file changed, 5 insertions(+), 36 deletions(-) + arch/arm/boot/dts/overlays/README | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/scripts/mkknlimg b/scripts/mkknlimg -index 3dff948..3998d43 100755 ---- a/scripts/mkknlimg -+++ b/scripts/mkknlimg -@@ -50,12 +50,6 @@ if (! -r $kernel_file) - usage(); - } +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 3aaa3da..87db77e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -188,7 +188,7 @@ Load: dtoverlay=at86rf233,= + Params: interrupt GPIO used for INT (default 23) + reset GPIO used for Reset (default 24) + sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 6000000) ++ speed SPI bus speed in Hz (default 3000000) + trim Fine tuning of the internal capacitance + arrays (0=+0pF, 15=+4.5pF, default 15) --my @wanted_config_lines = --( -- 'CONFIG_BCM2708_DT', -- 'CONFIG_ARCH_BCM2835' --); -- - my @wanted_strings = - ( - 'bcm2708_fb', -@@ -63,7 +57,8 @@ my @wanted_strings = - 'brcm,bcm2835-sdhost', - 'brcm,bcm2708-pinctrl', - 'brcm,bcm2835-gpio', -- 'brcm,bcm2835-pm-wdt' -+ 'brcm,bcm2835', -+ 'brcm,bcm2836' - ); + +From bed58e0b16c38a922ae64649ca945176812aeeee Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 19 Feb 2016 12:04:48 +0000 +Subject: [PATCH 273/278] bcm2835-sdhost: Downgrade log message status + +--- + drivers/mmc/host/bcm2835-sdhost.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 13b9d38..eee313fa 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -239,8 +239,8 @@ static void log_init(void) + sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr, + GFP_KERNEL); + if (sdhost_log_buf) { +- pr_err("sdhost: log_buf @ %p (%x)\n", +- sdhost_log_buf, sdhost_log_addr); ++ pr_info("sdhost: log_buf @ %p (%x)\n", ++ sdhost_log_buf, sdhost_log_addr); + timer_base = ioremap_nocache(BCM2708_PERI_BASE + 0x3000, SZ_4K); + if (!timer_base) + pr_err("sdhost: failed to remap timer\n"); + +From b7c08e8a592a761cc957061513c0fe8e854ab612 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 15 Jan 2016 16:48:27 +0000 +Subject: [PATCH 274/278] config: Enable HCI over UARTs + +--- + arch/arm/configs/bcm2709_defconfig | 3 +++ + arch/arm/configs/bcmrpi_defconfig | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index d61f42a..4bcb1d8 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -375,6 +375,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m + CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_3WIRE=y ++CONFIG_BT_HCIUART_BCM=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m + CONFIG_BT_HCIBFUSB=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index ccdde92..e0035ac 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -368,6 +368,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m + CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_3WIRE=y ++CONFIG_BT_HCIUART_BCM=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m + CONFIG_BT_HCIBFUSB=m + +From 6b0a564e3f880441e4c7a26b9cc463bb7a474b29 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 17 Dec 2015 13:37:07 +0000 +Subject: [PATCH 275/278] 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. +--- + drivers/bluetooth/hci_h5.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c +index 3455cec..5350703 100644 +--- a/drivers/bluetooth/hci_h5.c ++++ b/drivers/bluetooth/hci_h5.c +@@ -314,7 +314,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_req, 2) == 0) { + h5_link_control(hu, conf_rsp, 2); +- h5_link_control(hu, conf_req, 3); ++ if (h5->state != H5_ACTIVE) ++ h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_rsp, 2) == 0) { + if (H5_HDR_LEN(hdr) > 2) + h5->tx_win = (data[2] & 7); + +From f26d6689baad3fcf8fa69479ec48997efe5aeb59 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 23 Feb 2016 17:26:48 +0000 +Subject: [PATCH 276/278] 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 +/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the +other serial port is provided by the 8250 driver which doesn't +use the same logic. +--- + drivers/tty/serial/amba-pl011.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 2585cd8..86ec446 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2220,7 +2220,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) + if (uap == NULL) + return -ENOMEM; - my $res = try_extract($kernel_file, $tmpfile1); -@@ -98,12 +93,11 @@ if ($res) - config_bool($res, 'brcm,bcm2835-mmc') || - config_bool($res, 'brcm,bcm2835-sdhost')) - { -- $dtok ||= config_bool($res, 'CONFIG_BCM2708_DT'); -- $dtok ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); - $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl'); - $dtok ||= config_bool($res, 'brcm,bcm2835-gpio'); -- $is_283x ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); -- $is_283x ||= config_bool($res, 'brcm,bcm2835-pm-wdt'); -+ $is_283x ||= config_bool($res, 'brcm,bcm2835'); -+ $is_283x ||= config_bool($res, 'brcm,bcm2836'); -+ $dtok ||= $is_283x; - $append_trailer = 1; - } - else -@@ -205,31 +199,6 @@ sub try_extract - $res->{$match} = 1; - } ++ /* Don't use DT serial aliases - it causes the device to ++ be renumbered to ttyAMA1 if it is the second serial port in the ++ system, even though the other one is ttyS0. The 8250 driver ++ doesn't use this logic, so always remains ttyS0. + i = pl011_probe_dt_alias(i, &dev->dev); ++ */ -- my $config_pattern = '^('.join('|', @wanted_config_lines).')=(.*)$'; -- my $cf1 = 'IKCFG_ST\037\213\010'; -- my $cf2 = '0123456789'; -- -- my $pos = `tr "$cf1\n$cf2" "\n$cf2=" < "$knl" | grep -abo "^$cf2"`; -- if ($pos) -- { -- $pos =~ s/:.*[\r\n]*$//s; -- $pos += 8; -- my $err = (system("tail -c+$pos \"$knl\" | zcat > $tmp 2> /dev/null") >> 8); -- if (($err == 0) || ($err == 2)) -- { -- if (open(my $fh, '<', $tmp)) -- { -- while (my $line = <$fh>) -- { -- chomp($line); -- $res->{$1} = $2 if ($line =~ /$config_pattern/); -- } -- -- close($fh); -- } -- } -- } -- - return $res; - } + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); + +From cb5a6e22a60cd95da802c7767183b05fb7637f56 Mon Sep 17 00:00:00 2001 +From: campag +Date: Wed, 24 Feb 2016 16:45:42 +0000 +Subject: [PATCH 277/278] Add 1-bit SDIO with the minimum pins required for + that mode: GPIOs 22-25. + +--- + arch/arm/boot/dts/overlays/README | 21 ++++++++++++++ + arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts | 36 ++++++++++++++++++++++++ + 2 files changed, 57 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 87db77e..8b2d59e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -654,6 +654,27 @@ Params: overclock_50 SD Clock (in MHz) to use when the MMC framework + bus_width Set the SDIO host bus width (default 4 bits) + ++Name: sdio-1bit ++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, ++ and enables 1-bit SDIO via GPIOs 22-25. ++Load: dtoverlay=sdio-1bit,= ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz ++ ++ force_pio Disable DMA support (default off) ++ ++ pio_limit Number of blocks above which to use DMA ++ (default 1) ++ ++ debug Enable debug output (default off) ++ ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) ++ ++ + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! + Load: dtoverlay=smi +diff --git a/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts b/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts +new file mode 100644 +index 0000000..46d4538 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts +@@ -0,0 +1,36 @@ ++/* Enable 1-bit SDIO from MMC interface via GPIOs 22-25. Includes sdhost overlay. */ ++ ++/include/ "sdhost-overlay.dts" ++ ++/{ ++ compatible = "brcm,bcm2708"; ++ ++ fragment@3 { ++ target = <&mmc>; ++ sdio_mmc: __overlay__ { ++ compatible = "brcm,bcm2835-mmc"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio_pins>; ++ non-removable; ++ bus-width = <1>; ++ brcm,overclock-50 = <0>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&gpio>; ++ __overlay__ { ++ sdio_pins: sdio_pins { ++ brcm,pins = <22 23 24 25>; ++ brcm,function = <7 7 7 7>; /* ALT3 = SD1 */ ++ brcm,pull = <0 2 2 2>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ poll_once = <&sdio_mmc>,"non-removable?"; ++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0"; ++ }; ++}; + +From ef4ef49f5d92fe9050b065f7ead913c3ab502300 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Tue, 23 Feb 2016 17:28:23 +0100 +Subject: [PATCH 278/278] ASoC: bcm: add missing .owner fields in sound card + drivers + +If snd_soc_card.owner is not set the kernel won't do usage refcounting +and one can remove the card driver module while it's in use (eg playback +active) - which leads to a kernel crash. + +The missing owner field also prevents ALSA slot ordering +(options snd slots=module-name1,module-name-2,...) from working with +the I2S cards as it has no module name to match against. + +Fix these issues by setting the .owner field in the snd_soc_card structs. + +Signed-off-by: Matthias Reichl +--- + sound/soc/bcm/hifiberry_amp.c | 1 + + sound/soc/bcm/hifiberry_dac.c | 1 + + sound/soc/bcm/hifiberry_dacplus.c | 1 + + sound/soc/bcm/hifiberry_digi.c | 1 + + sound/soc/bcm/iqaudio-dac.c | 1 + + sound/soc/bcm/raspidac3.c | 1 + + sound/soc/bcm/rpi-dac.c | 1 + + sound/soc/bcm/rpi-proto.c | 1 + + 8 files changed, 8 insertions(+) + +diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c +index 5903915..0bb12e4 100644 +--- a/sound/soc/bcm/hifiberry_amp.c ++++ b/sound/soc/bcm/hifiberry_amp.c +@@ -61,6 +61,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { + + static struct snd_soc_card snd_rpi_hifiberry_amp = { + .name = "snd_rpi_hifiberry_amp", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_amp_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_dac.c b/sound/soc/bcm/hifiberry_dac.c +index 3ab0f47..29ecc08 100644 +--- a/sound/soc/bcm/hifiberry_dac.c ++++ b/sound/soc/bcm/hifiberry_dac.c +@@ -63,6 +63,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_dac = { + .name = "snd_rpi_hifiberry_dac", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index 50b66a1..a3525f7 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -288,6 +288,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_dacplus = { + .name = "snd_rpi_hifiberry_dacplus", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_dacplus_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index 80732b8..9840e15 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -164,6 +164,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_digi = { + .name = "snd_rpi_hifiberry_digi", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_digi_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai), + }; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index 5ade006..2424b00 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -78,6 +78,7 @@ static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_iqaudio_dac = { + .name = "IQaudIODAC", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_iqaudio_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), + }; +diff --git a/sound/soc/bcm/raspidac3.c b/sound/soc/bcm/raspidac3.c +index fddaeec..c2936c5 100644 +--- a/sound/soc/bcm/raspidac3.c ++++ b/sound/soc/bcm/raspidac3.c +@@ -128,6 +128,7 @@ static struct snd_soc_dai_link snd_rpi_raspidac3_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_raspidac3 = { + .name = "RaspiDAC Rev.3x HiFi Audio Card", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_raspidac3_dai, + .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai), + }; +diff --git a/sound/soc/bcm/rpi-dac.c b/sound/soc/bcm/rpi-dac.c +index d5fac1b..59dc89e 100644 +--- a/sound/soc/bcm/rpi-dac.c ++++ b/sound/soc/bcm/rpi-dac.c +@@ -60,6 +60,7 @@ static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_rpi_dac = { + .name = "snd_rpi_rpi_dac", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_rpi_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai), + }; +diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c +index c6e45a0..9db678e 100644 +--- a/sound/soc/bcm/rpi-proto.c ++++ b/sound/soc/bcm/rpi-proto.c +@@ -91,6 +91,7 @@ static struct snd_soc_dai_link snd_rpi_proto_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_proto = { + .name = "snd_rpi_proto", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_proto_dai, + .num_links = ARRAY_SIZE(snd_rpi_proto_dai), + }; diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index 32cf12da6a..73e7b4fab8 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 5e9c268f96c85ea7722958b1f6f73c8d13a822dc Mon Sep 17 00:00:00 2001 +From ffd06bc2da1c5a433250de4013263bcd4f0da46e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/204] Main bcm2708/bcm2709 linux port +Subject: [PATCH 001/278] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -181,10 +181,10 @@ index 19f4cc6..3ec1319 100644 source "arch/arm/mach-alpine/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 0c12ffb..18db6c4 100644 +index f775d71..5b29257 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -1197,6 +1197,14 @@ choice +@@ -1196,6 +1196,14 @@ choice options; the platform specific options are deprecated and will be soon removed. @@ -7002,10 +7002,10 @@ index b5bedae..b0258e8 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From 7408b83b52329a004068c5749e1733d8cb9028cb Mon Sep 17 00:00:00 2001 +From 948ac9440c4e80652fc31e3ff88280d43d9f1bb9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 002/204] Add bcm2708_gpio driver +Subject: [PATCH 002/278] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -7635,10 +7635,10 @@ index 0000000..fb69624 + +#endif -From d86df54c296ad49447cb90e8c9ea1d2c8bd2b82b Mon Sep 17 00:00:00 2001 +From 16d13e64d51ee66289f7bc61126e4a751895a880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 1 May 2015 19:11:03 +0200 -Subject: [PATCH 003/204] mailbox: bcm2708: Add bcm2708-vcio +Subject: [PATCH 003/278] mailbox: bcm2708: Add bcm2708-vcio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -8269,10 +8269,10 @@ index 0000000..cc284ed + +#endif -From a01bebe2f26586b5b8021847cc12f83f9fd0a27f Mon Sep 17 00:00:00 2001 +From 92e60879b7ea380f2d9becfb0b606a3ceb6c2d13 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/204] Add dwc_otg driver +Subject: [PATCH 004/278] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -9180,10 +9180,10 @@ index 358ca8d..abaac7c 100644 return i; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 1e9a8c9..7e9f79f 100644 +index e56ad83..2574b3e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -4906,7 +4906,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -4927,7 +4927,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; @@ -9441,7 +9441,7 @@ index a6315ab..165dd53 100644 diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c new file mode 100644 -index 0000000..a896d73 +index 0000000..a896d73f --- /dev/null +++ b/drivers/usb/gadget/file_storage.c @@ -0,0 +1,3676 @@ @@ -13146,10 +13146,10 @@ index 197a6a3..5496cd0 100644 tristate "i.MX21 HCD support" depends on ARM && ARCH_MXC diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 65b0b6a..49399f2 100644 +index da03d8b..bda597d 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile -@@ -68,6 +68,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o +@@ -67,6 +67,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o @@ -17280,7 +17280,7 @@ index 0000000..b802042 +#endif /* DWC_LIBMODULE */ diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c new file mode 100644 -index 0000000..49b07e1 +index 0000000..49b07e17 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c @@ -0,0 +1,1275 @@ @@ -29807,7 +29807,7 @@ index 0000000..bbb3d32 +#endif //DWC_UTE_CFI diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.h b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h new file mode 100644 -index 0000000..55fd337 +index 0000000..55fd337a --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h @@ -0,0 +1,320 @@ @@ -59769,7 +59769,7 @@ index 0000000..c8d2e0e +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c new file mode 100644 -index 0000000..c8590b5 +index 0000000..c8590b52 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c @@ -0,0 +1,5147 @@ @@ -69546,10 +69546,10 @@ index 0000000..cdc9963 +test_main(); +0; -From a7a65674af3af5dcc29121afaae50c0cf6b2e13b Mon Sep 17 00:00:00 2001 +From 405ca74b632474bdab6ef5a2b799f10faecbf950 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/204] bcm2708 watchdog driver +Subject: [PATCH 005/278] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -69986,10 +69986,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); -From d2d531d448b63465a680fb3e15c0e843267ff50f Mon Sep 17 00:00:00 2001 +From 6b76bbd2a9a4053ded1573cb3a4c0c0687181acc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 006/204] bcm2708 framebuffer driver +Subject: [PATCH 006/278] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -73428,10 +73428,10 @@ index 3c14e43..7626beb6a 100644 +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 7b98bf652df7771dd8eb79528dd7e276f2038585 Mon Sep 17 00:00:00 2001 +From da2171b008b0082775a7b690a0e77282405976f4 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 007/204] dmaengine: Add support for BCM2708 +Subject: [PATCH 007/278] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75199,10 +75199,10 @@ index 0000000..2310e34 + +#endif /* _PLAT_BCM2708_DMA_H */ -From 44cbf9ce5089b224b53fa45eade2bfb7111bc2db Mon Sep 17 00:00:00 2001 +From 3f8f3a9418ada97a4279e71fbe7bc14fca3266fd Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 008/204] MMC: added alternative MMC driver +Subject: [PATCH 008/278] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -77018,10 +77018,10 @@ index 0000000..b7c4883 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From b0a083aa54f21ac74e866d9c016653d247e6d2b7 Mon Sep 17 00:00:00 2001 +From 6fc9ed66cfea50cfca82e4590d515b38f8bb1515 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 009/204] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 009/278] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -78791,10 +78791,10 @@ index 0000000..eef8a24 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From a48f15d3cdee3004a03d04e296247625130dcbf7 Mon Sep 17 00:00:00 2001 +From 23e9f454193f3ab369e9d0eda3674e241e437d27 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 010/204] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 010/278] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix @@ -80119,10 +80119,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From ebd29c2fcd995ebe287b4d9e771bd1f6730e6e13 Mon Sep 17 00:00:00 2001 +From e71e3228c8bc7181b31a7e2881f9358e6f53dc05 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 011/204] bcm2708: alsa sound driver +Subject: [PATCH 011/278] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -82964,10 +82964,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From 4978dc22bb85d1c218085aa253224bdaea6f89fc Mon Sep 17 00:00:00 2001 +From 41131d689f4ed20636685d602c658e543542fdbb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 012/204] bcm2708 vchiq driver +Subject: [PATCH 012/278] bcm2708 vchiq driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -96221,10 +96221,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From 5c91907c6aec2d89bf1d57ab85e01bfdab1f0801 Mon Sep 17 00:00:00 2001 +From 8c6b124a066e8b865779a968653844c2f7ba4d44 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 16:07:06 +0100 -Subject: [PATCH 013/204] vc_mem: Add vc_mem driver +Subject: [PATCH 013/278] vc_mem: Add vc_mem driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -97230,10 +97230,10 @@ index 0000000..20a4753 + +#endif /* _VC_MEM_H */ -From 40c1f77329886c79e9ac40afe3dee52dec5a0f5f Mon Sep 17 00:00:00 2001 +From 0465331ab045339e339d6df2dab587c4d97e641e Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 014/204] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 014/278] vcsm: VideoCore shared memory service for BCM2835 Add experimental support for the VideoCore shared memory service. This allows user processes to allocate memory from VideoCore's @@ -101643,10 +101643,10 @@ index 0000000..0bfb42e +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 89476e1e5132eb053f40bcad4d31903c2660d737 Mon Sep 17 00:00:00 2001 +From fa4f1898341f37f413e0482d047740c4a1249dba Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 015/204] Add hwrng (hardware random number generator) driver +Subject: [PATCH 015/278] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 13 +++- @@ -101823,10 +101823,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From 0f09a4b263925916b493657ad19334d1b62ee299 Mon Sep 17 00:00:00 2001 +From c66d7e987408cc8921ca9d426142212ce64a181e Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 016/204] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 016/278] 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 @@ -102679,10 +102679,10 @@ index 0000000..24563ec +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 7dc35f47e29f40755b9a66b6c1b8f693d0a7e414 Mon Sep 17 00:00:00 2001 +From 3b17bb7823c2b8a43cb85a8633382684a786cf8f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 017/204] Add cpufreq driver +Subject: [PATCH 017/278] Add cpufreq driver Signed-off-by: popcornmix --- @@ -102955,10 +102955,10 @@ index 0000000..6735da9 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From d8057ff6ba5dece8ae393713e563362dc53bbde4 Mon Sep 17 00:00:00 2001 +From 9c00340088fe26bd04a11c9b2aca62245912f04c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 018/204] Added hwmon/thermal driver for reporting core +Subject: [PATCH 018/278] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -103255,10 +103255,10 @@ index 0000000..3bc80f1 + +module_platform_driver(bcm2835_thermal_driver); -From 320c58bca444bc390f7eccfebbb529fe8e98ed10 Mon Sep 17 00:00:00 2001 +From adfdb7dbb59687542d233ff56f453e1580c0890f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:41:33 +0100 -Subject: [PATCH 019/204] Add Chris Boot's spi driver. +Subject: [PATCH 019/278] Add Chris Boot's spi driver. spi: bcm2708: add device tree support @@ -104170,10 +104170,10 @@ index 0000000..041b5e2 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From db4e6f4abd7eb95d3224be99d7f04c791f4ceb8d Mon Sep 17 00:00:00 2001 +From 36e25710ce594f2f0e6c5ad00f750fd50cc098ac Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 020/204] Add Chris Boot's i2c driver +Subject: [PATCH 020/278] Add Chris Boot's i2c driver i2c-bcm2708: fixed baudrate @@ -104974,10 +104974,10 @@ index 0000000..8773203 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From fb0599a8dc95e605fe75e510c39a99e77fe627f8 Mon Sep 17 00:00:00 2001 +From 26b716f6035f208f954627d06e8580875d713f63 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 021/204] bcm2835: add v4l2 camera device +Subject: [PATCH 021/278] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -112304,10 +112304,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From 55141e6e23fd7c2f2b98d6f472dd4e1f11fcdb50 Mon Sep 17 00:00:00 2001 +From 4ea8726fc5f8574c73f4534f633012794926dfd2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 022/204] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 022/278] scripts/dtc: Update to upstream version with overlay patches --- @@ -117520,10 +117520,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 8bddbe464074570457bca032ebee779eb9814d13 Mon Sep 17 00:00:00 2001 +From cc34f5b569f58526b93a28d202c3e07e600fcd83 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 023/204] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 023/278] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -118008,10 +118008,10 @@ index 0000000..3dff948 + return (($val eq 'y') || ($val eq '1')); +} -From febe480850daa451009a87a3b86278f3d7dbaa10 Mon Sep 17 00:00:00 2001 +From 377ebe45a8b20a9a44e1c53f00f7cbc0b3667f08 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 024/204] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 024/278] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -118066,10 +118066,10 @@ index d91f721..02feb00 100644 pr_debug("Command line is: %s\n", (char*)data); -From 35658cc32f834e0bad12e6206b7ffb6af9eddbe6 Mon Sep 17 00:00:00 2001 +From fb27a2784f3557a053b7d0afd66517523d7a6970 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 025/204] BCM2708: Add core Device Tree support +Subject: [PATCH 025/278] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -120252,7 +120252,7 @@ index 0000000..2c81448 +}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts new file mode 100644 -index 0000000..5e7633a +index 0000000..5e7633ae --- /dev/null +++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts @@ -0,0 +1,34 @@ @@ -121328,7 +121328,7 @@ index 0000000..40bf0e1 +}; diff --git a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts new file mode 100644 -index 0000000..7fc6ac9 +index 0000000..7fc6ac99 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts @@ -0,0 +1,34 @@ @@ -121946,10 +121946,10 @@ index 0000000..66a98f6 + }; +}; -From 7c4a63015f03594469922e65ae613bbc4e54c4cf Mon Sep 17 00:00:00 2001 +From df318861bb615aeccab05e3adfe9afbedc990046 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 026/204] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 026/278] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -122026,7 +122026,7 @@ index 0705d88..771992a 100644 case FBIOBLANK: ret = do_fb_ioctl(info, cmd, arg); diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h -index fb795c3..fa72af0 100644 +index fb795c3..fa72af0c 100644 --- a/include/uapi/linux/fb.h +++ b/include/uapi/linux/fb.h @@ -34,6 +34,11 @@ @@ -122042,10 +122042,11 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 4f1485790c96ee05b7fd08c23905f8957c8f2b61 Mon Sep 17 00:00:00 2001 + +From c45570b46933912e967c3065fc22c8ba667ba12d Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 029/204] Speed up console framebuffer imageblit function +Subject: [PATCH 029/278] 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 @@ -122254,10 +122255,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From efd2fa9ef6e7848d0494f1a66d46e9280d507f4e Mon Sep 17 00:00:00 2001 +From 5028743160d3d29afd26eac7998617c90a349205 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 030/204] Allow mac address to be set in smsc95xx +Subject: [PATCH 030/278] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -122348,10 +122349,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 625c18792c5c8272af5237599d44d852e0996bdf Mon Sep 17 00:00:00 2001 +From e5eb9a45c70ee50e76e136eaddcc3f71db1fa27b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 031/204] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 031/278] 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 @@ -122749,10 +122750,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 8b7527453528e339a4586eec937857f1b994daae Mon Sep 17 00:00:00 2001 +From 7a7604c7f5e332d2f5f694165a5c74e06442fe17 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 033/204] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 033/278] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -122795,10 +122796,10 @@ index 4d65b66..dd258ff 100644 { printk("cgroup: using legacy files on the default hierarchy\n"); diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 68dea90..6fd0c4f 100644 +index aac1c98..d25efbc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -5389,6 +5389,7 @@ struct cgroup_subsys memory_cgrp_subsys = { +@@ -5390,6 +5390,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .dfl_cftypes = memory_files, .legacy_cftypes = mem_cgroup_legacy_files, .early_init = 0, @@ -122807,10 +122808,10 @@ index 68dea90..6fd0c4f 100644 /** -From 727594aaa8ab739ea1c22eca69bf5400948af0d1 Mon Sep 17 00:00:00 2001 +From d9d47cc54a8e9bd7862e2bc5faaf5ad596607902 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 034/204] ASoC: Add support for BCM2708 +Subject: [PATCH 034/278] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -123953,10 +123954,10 @@ index 0000000..6fdcbc1 + +#endif -From c0c7b62d38423b62ad3223b79f7f60802c6c1e5c Mon Sep 17 00:00:00 2001 +From ae4d28cda5572ee772f9b13b2a0bb5e65692d3e5 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 035/204] ASoC: Add support for PCM5102A codec +Subject: [PATCH 035/278] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -124081,10 +124082,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 0f2fff9145ec3742650115b422b3fa4983002668 Mon Sep 17 00:00:00 2001 +From 665cab7a61982780599002ad9cc7a4f31448f5fc Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 036/204] BCM2708: Add I2S support to board file +Subject: [PATCH 036/278] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -124173,10 +124174,10 @@ index a3b65dc..a515992 100644 for (i = 0; i <= 1; i++) { void __iomem *base; -From b7db156b7135bd8023bc2e553fa802f10b33df21 Mon Sep 17 00:00:00 2001 +From 70d231945fafd27ceee934ff71d56793e7798eae Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 037/204] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 037/278] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -124325,10 +124326,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From c48e1b97199c72f611b2f0937d36bc98a7169bba Mon Sep 17 00:00:00 2001 +From 251ca1c8fbb88f0aec430199c7e14bead17c026f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 038/204] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 038/278] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -124376,10 +124377,10 @@ index 01f2de7..1d9b788 100644 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; -From 46355bc118b045051f833c56844bba4b71b6b666 Mon Sep 17 00:00:00 2001 +From 032100077129e77cbff9cae10adaaa5ecb3b05f2 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 039/204] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 039/278] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -124674,10 +124675,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 81991e83d009ef30b23b0f7190042479293aa418 Mon Sep 17 00:00:00 2001 +From da878ad7d43c9aed76026e4cf0bef31a0f2b8ffd Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 040/204] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 040/278] 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 @@ -124717,10 +124718,10 @@ index 1e403f6..d4efa85 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From bf20cf45c9c208ff4a47465f3297196806b95da7 Mon Sep 17 00:00:00 2001 +From c1c7d648404af9015fa1013b6a4b07e3423610b5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 041/204] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 041/278] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -124985,10 +124986,10 @@ index 0000000..92e9e46 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From ebfceb0a7d6a4854618c00339d571421b7a18b68 Mon Sep 17 00:00:00 2001 +From 189af09ac6a681842d1c75b6652e5e066997c8d8 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 042/204] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 042/278] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -125035,10 +125036,10 @@ index 6d53beb..a062d7f 100644 bcm_register_device_dt(&snd_rpi_dac_device); bcm_register_device_dt(&snd_pcm1794a_codec_device); -From b9597317ed9afa6fe3712758c0ad5d1b11766d60 Mon Sep 17 00:00:00 2001 +From 30fa17f1cb4328667047e63a1ac54cab62a3555f Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 043/204] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 043/278] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -125060,10 +125061,10 @@ index d4efa85..f3f26a2 100644 .dapm_widgets = wm8804_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets), -From 098e66a4235451ad64c8bc1349496fc68a0e16fc Mon Sep 17 00:00:00 2001 +From 7610b8a6d167550ae9dbeda954db51c2ed4134ba Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 044/204] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 044/278] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -125271,10 +125272,10 @@ index 0000000..aff7377 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From a2878cc4a414348ab3b5be3ad44f04ae8e77e3ab Mon Sep 17 00:00:00 2001 +From 79f174399444552afe7d42382e54d202507b7271 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 045/204] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 045/278] vmstat: Workaround for issue where dirty page count goes negative See: @@ -125301,10 +125302,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 0fb0113068c3d68d396dff09129369bd7719bb41 Mon Sep 17 00:00:00 2001 +From 42230f1cba840d81df5cd35bdbd48c45df9ca589 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 046/204] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 046/278] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -125340,10 +125341,10 @@ index eab5bd6..ca47de9 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From b5950dd391670c2090ca047af33ba1f5b330b272 Mon Sep 17 00:00:00 2001 +From b085ae1eafc7cdcfe97089a86727ea30c8d349e0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 047/204] Added support for HiFiBerry DAC+ +Subject: [PATCH 047/278] 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. @@ -125554,10 +125555,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 83ead1b240ffde9c9c592533b4b116ae721e6893 Mon Sep 17 00:00:00 2001 +From 5f3d09ef343808fcb4eaea246a183c2a17f9b08e Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 048/204] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 048/278] 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. @@ -126426,10 +126427,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From d78d9b666c8a7fb477945825a161505701e11b28 Mon Sep 17 00:00:00 2001 +From a84d873c468d6174228a76577eba1147927daa86 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Apr 2015 19:14:18 +0100 -Subject: [PATCH 049/204] bcm2708: Allow option card devices to be configured +Subject: [PATCH 049/278] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -126454,10 +126455,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 0cf6cbc05769deca2546837472623fc4e7b56c11 Mon Sep 17 00:00:00 2001 +From 42c8b50f6678c4f59c2204d1d7c0ec912cd32772 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 18:45:39 +0100 -Subject: [PATCH 050/204] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 050/278] Adding Device Tree support for some RPi audio cards --- arch/arm/mach-bcm2709/bcm2709.c | 143 ++++++++++++++++++++++++++++++++++++++ @@ -126820,10 +126821,10 @@ index 126f1e9..7c6598e 100644 }; -From 1548b70b26d3607e2f51c46f98c09f704911e4ae Mon Sep 17 00:00:00 2001 +From 7de01b445ffa2aa4e91ed15ea47c72d174206639 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 051/204] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 051/278] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -126959,10 +126960,10 @@ index 57e1f3d..721559b 100644 +module_param(pps_gpio_pin, int, 0644); +MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS"); -From c7e1fd615565779916e66d987595521dcefc691c Mon Sep 17 00:00:00 2001 +From b13179f136708067775cb241b279261905560f99 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 052/204] Update ds1307 driver for device-tree support +Subject: [PATCH 052/278] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -126989,10 +126990,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From 5d7ba67c43373946a8b3c8bed5f2e6e23090a09d Mon Sep 17 00:00:00 2001 +From d50a101ba1069645a4c2c038b3fb95323df00cec Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 053/204] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 053/278] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -127103,10 +127104,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From dfc29014435e46cbc28a4cdcdf1bff215964e13b Mon Sep 17 00:00:00 2001 +From f8756b0e5c80a63f1c1c173a84da775321150744 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 054/204] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 054/278] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -127325,10 +127326,10 @@ index d08591b..08d184c 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From ee705807744ab8001d5ae997102c0c8c9785dafe Mon Sep 17 00:00:00 2001 +From a1bf8f355612aa4e1c096d1be7c1f197defbf431 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 055/204] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 055/278] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -127415,10 +127416,10 @@ index 9a2b000..60accc5 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 27e98ca305c67ee354c42983a43f09b2e59ce5b5 Mon Sep 17 00:00:00 2001 +From e57a92eb3b4c6fd8934cca427af2f1bd2b2e42ff Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 056/204] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 056/278] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -127440,10 +127441,10 @@ index 8d908e3..7a1900d 100644 .can_sleep = false, }; -From e4022c2c7ada3dc69da92db183132c86cdc7d730 Mon Sep 17 00:00:00 2001 +From befbd426f62340bb92fbd3d2e48fbe2612d9b9a7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 057/204] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 057/278] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -127471,10 +127472,10 @@ index 7a1900d..62f85aa 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From d1c711959d41518b10f7c2797cac744c543468ad Mon Sep 17 00:00:00 2001 +From fc1edd9bb24b7b4df3b282e5ee27ed04185e8639 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 058/204] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 058/278] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -127620,10 +127621,10 @@ index 62f85aa..c7cf266 100644 }, }; -From 3c62244d144a37b12b9af16a34eb67b4b7cf48ba Mon Sep 17 00:00:00 2001 +From b1db004a2b8fdb0bfe2f81423d5005e400e6e9b4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 059/204] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 059/278] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -127650,10 +127651,10 @@ index c7cf266..986779a 100644 pc->irq_data[i].irqgroup = i; -From f8391406e17d282f010b8deebe0ccd26f8ea2e49 Mon Sep 17 00:00:00 2001 +From 83ac9da37cc24d10d043483504598d5a7b8b0579 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 27 Feb 2015 15:10:24 +0000 -Subject: [PATCH 060/204] enc28j60: Add device tree compatible string and an +Subject: [PATCH 060/278] enc28j60: Add device tree compatible string and an overlay --- @@ -127687,10 +127688,10 @@ index b1b5f66..c6b6e1a 100644 .probe = enc28j60_probe, .remove = enc28j60_remove, -From eb2703ff418ab3b72d09375f7c2aa49aee9f4a0e Mon Sep 17 00:00:00 2001 +From 5175ca5355ce497abc7f20547e1c196c6340b6ae Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 061/204] Add driver for rpi-proto +Subject: [PATCH 061/278] 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 @@ -127905,10 +127906,10 @@ index 0000000..c6e45a0 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From d3d38e562e57db9c529f93aedfe9fca8b5c70a38 Mon Sep 17 00:00:00 2001 +From 6e9afafe59c9218786dcb17ad4fa0c3d7b9f7098 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Thu, 2 Apr 2015 12:22:55 +0100 -Subject: [PATCH 062/204] Add Device Tree support for RPi-DAC. +Subject: [PATCH 062/278] Add Device Tree support for RPi-DAC. --- sound/soc/bcm/rpi-dac.c | 21 +++++++++++++++++++++ @@ -127983,10 +127984,10 @@ index b4eaa44..afe1b41 100644 }; -From b15b358e11a817bcc7c3d8354c8a2f6f7d30a806 Mon Sep 17 00:00:00 2001 +From 8aeb303a194b5462abfcc948d3caf7591b20b7c0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 063/204] config: Add default configs +Subject: [PATCH 063/278] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1204 ++++++++++++++++++++++++++++++++++++ @@ -130411,10 +130412,10 @@ index 0000000..6a41231 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From 97b84b787de84ad70a3a3a2d7faa9c898c89077c Mon Sep 17 00:00:00 2001 +From 731be886de4b348da553b902006c3f6789af8f82 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 064/204] smsx95xx: fix crimes against truesize +Subject: [PATCH 064/278] 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. @@ -130449,10 +130450,10 @@ index e29a323..aff63dc usbnet_skb_return(dev, ax_skb); } -From f00f1c85db60369955c57b255c2588ff56d59fa7 Mon Sep 17 00:00:00 2001 +From 515f9ddee95bc0b06c48f55b6400923dc94923eb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 17 Apr 2015 16:58:45 +0100 -Subject: [PATCH 065/204] smsc95xx: Disable turbo mode by default +Subject: [PATCH 065/278] smsc95xx: Disable turbo mode by default --- drivers/net/usb/smsc95xx.c | 2 +- @@ -130472,10 +130473,10 @@ index aff63dc..08a8a8c 100755 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); -From 122b539270dc7e0d8ee3b6926c77f5aedb06fb67 Mon Sep 17 00:00:00 2001 +From 9b347c3aeefea0d450ea8247689d422686026086 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Apr 2015 19:30:22 +0100 -Subject: [PATCH 066/204] Add blk_pos parameter to mmc multi_io_quirk callback +Subject: [PATCH 066/278] Add blk_pos parameter to mmc multi_io_quirk callback --- drivers/mmc/card/block.c | 1 + @@ -130558,10 +130559,10 @@ index b0258e8..d3cdad9 100644 struct mmc_card; -From ec8a45bdc3e0afbf5ab8ba7735608e7ca11feca7 Mon Sep 17 00:00:00 2001 +From 0e99a42d44b7ab980a2aeceb0b5f0c84b12ab36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Apr 2015 17:24:02 +0200 -Subject: [PATCH 067/204] bcm2835: bcm2835_defconfig +Subject: [PATCH 067/278] bcm2835: bcm2835_defconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -131891,10 +131892,10 @@ index 31cb073..2e8a95a 100644 # CONFIG_XZ_DEC_ARM is not set # CONFIG_XZ_DEC_ARMTHUMB is not set -From af1868e02b629a2e2092bf358540d6ca4dcdff6c Mon Sep 17 00:00:00 2001 +From cd8f18b0cda05e394d92dadff530f1a719ba86ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 1 May 2015 23:00:15 +0200 -Subject: [PATCH 068/204] BCM270x_DT: Add mailbox bcm2708-vcio +Subject: [PATCH 068/278] BCM270x_DT: Add mailbox bcm2708-vcio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -131935,10 +131936,10 @@ index 721559b..4a00561 100644 #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); -From ab35f5a7f3921cd9d5d9f09f4bd82675822048dc Mon Sep 17 00:00:00 2001 +From cb26b0e8f2122493e80b261b2da19e4c415face3 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 069/204] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 069/278] rpi-ft5406: Add touchscreen driver for pi LCD display --- drivers/input/touchscreen/Kconfig | 7 + @@ -132255,10 +132256,10 @@ index cc284ed..d3ea839 100644 VCMSG_SET_CURSOR_STATE = 0x00008011, }; -From f12bdfa033dd3c639b037c3acefc6df99e51936d Mon Sep 17 00:00:00 2001 +From cd11b6897bc01c2adf21962394c9f42bfb54c37d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Oct 2014 11:47:53 +0100 -Subject: [PATCH 070/204] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 070/278] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -133783,10 +133784,10 @@ index 3e58d71..0622891 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) -From b52da83347f05007471699518545f3c8827d762a Mon Sep 17 00:00:00 2001 +From 1770dea7a8120ee58efed780c332c930b014d3dc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 27 May 2015 17:22:15 +0100 -Subject: [PATCH 071/204] bcm2835-audio: Create the platform device if the DT +Subject: [PATCH 071/278] bcm2835-audio: Create the platform device if the DT node is disabled For backwards compatibility, allow the built-in ALSA driver to be enabled @@ -133840,10 +133841,10 @@ index 4a00561..dec8043 100644 bcm_register_device_dt(&bcm2708_spi_device); -From 1b9a56248747ddcba15df7f60cf739eea2977349 Mon Sep 17 00:00:00 2001 +From 4cf804c9a4fa1fc254408c0d46e8c44e248dbcbb 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 072/204] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 072/278] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -133902,10 +133903,10 @@ index 70f2f39..f7fdacd 100644 static const char * const bcm2835_compat[] = { -From 6c1d2a6d20e29c2fb1809297925045701d8a4a2a Mon Sep 17 00:00:00 2001 +From d835ceec34bffd5a6698fcbdeece1956c79e7a24 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 16 Jun 2015 17:47:27 +0100 -Subject: [PATCH 073/204] platform: Add force_core command line setting to boot +Subject: [PATCH 073/278] platform: Add force_core command line setting to boot from a different core number --- @@ -133976,10 +133977,10 @@ index dec8043..fe71c50 100644 module_param(serial, uint, 0644); module_param(uart_clock, uint, 0644); -From fbedbf309c2ee139e3eace31eb388fc0c8c75301 Mon Sep 17 00:00:00 2001 +From 50b10764be01dcdb6edd986b748241fbbd7073db Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Jun 2015 17:46:17 +0100 -Subject: [PATCH 074/204] mach-bcm270x: Enable the building of pinctrl-bcm2835 +Subject: [PATCH 074/278] mach-bcm270x: Enable the building of pinctrl-bcm2835 --- drivers/pinctrl/Makefile | 1 + @@ -133998,10 +133999,10 @@ index 6eadf04..9119513 100644 obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ -From 697b347118f88f65839dbf93dfc583b06407e791 Mon Sep 17 00:00:00 2001 +From 65003cc7d24bd4923a53f99867947d9853982868 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 19 Jun 2015 16:41:39 +0100 -Subject: [PATCH 075/204] BCM270X_DT: Document the i2s-mmap overlay +Subject: [PATCH 075/278] BCM270X_DT: Document the i2s-mmap overlay --- arch/arm/boot/dts/overlays/README | 6 ++++++ @@ -134025,10 +134026,10 @@ index 3e08f98..7fa6d33 100644 Info: Configures the IQaudio DAC audio card Load: dtoverlay=iqaudio-dac -From 459023e570ec920d21cf3d01988a595f9027c87c Mon Sep 17 00:00:00 2001 +From 9144d4795d200ac8b0a8b7758490536a07ab85f7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 17 Jun 2015 11:36:53 +0100 -Subject: [PATCH 076/204] bcm2835-sdhost: Improve error handling and recovery +Subject: [PATCH 076/278] bcm2835-sdhost: Improve error handling and recovery 1) Expose the hw_reset method to the MMC framework, removing many internal calls by the driver. @@ -135120,10 +135121,10 @@ index eef8a24..6277e43 100644 if (host->allow_dma) { -From 1b37e961ff949769a09160dcc9567c47f8d093e6 Mon Sep 17 00:00:00 2001 +From eb34bef3eb5d52fbffdafa4effc8ccfda4485169 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 4 Jun 2015 13:11:46 -0700 -Subject: [PATCH 077/204] ARM: bcm2835: Add the Raspberry Pi firmware driver +Subject: [PATCH 077/278] ARM: bcm2835: Add the Raspberry Pi firmware driver This gives us a function for making mailbox property channel requests of the firmware, which is most notable in that it will let us get and @@ -135158,7 +135159,7 @@ index 6517132..564aa5b 100644 source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile -index 3fdd391..ee101a2 100644 +index 3fdd3912..ee101a2 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o @@ -135557,10 +135558,10 @@ index 0000000..9d9efb7 + void *data, size_t tag_size); +struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); -From 9666e309b64fbf73d945c934dc3e991e25218fba Mon Sep 17 00:00:00 2001 +From 075b2d72e1264fc04af611bc41eee436ceaff7f9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 22 Mar 2015 13:33:23 +0000 -Subject: [PATCH 078/204] config: Enable ZSMALLOC, ZRAM and PGTABLE_MAPPING +Subject: [PATCH 078/278] config: Enable ZSMALLOC, ZRAM and PGTABLE_MAPPING --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -135612,10 +135613,10 @@ index 6a41231..cacde14 100644 CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_DRBD=m -From a767c3cb4c6604ad27b92a36644de098f8bdcabb Mon Sep 17 00:00:00 2001 +From cbdda3d7b1a65d7c6632d8f16cf04a0d5cbf4098 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Mon, 22 Jun 2015 16:27:07 +0100 -Subject: [PATCH 079/204] Add rpi-ft5406 overlay Add rpi-ft5406 driver as +Subject: [PATCH 079/278] Add rpi-ft5406 overlay Add rpi-ft5406 driver as module --- @@ -135702,10 +135703,10 @@ index cacde14..f952ff2 100644 CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y -From f13481ed18c0a520fc1776890d1066c1397b358f Mon Sep 17 00:00:00 2001 +From 4ab37825009c6c16ecb6a9c2a7df1a345f26264c Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 23 Jun 2015 09:53:40 +0100 -Subject: [PATCH 080/204] Fix driver detection failure Check that the buffer +Subject: [PATCH 080/278] Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected --- @@ -135726,10 +135727,10 @@ index f55151b..d41851d 100644 dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", request.tag.val); } -From 7b53303429e40fddef7ffeb405f898af16adf578 Mon Sep 17 00:00:00 2001 +From b01066ab66dca860c9945c684f7e47c57487812d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Jun 2015 13:24:01 +0100 -Subject: [PATCH 081/204] config: Enable 8250 serial port +Subject: [PATCH 081/278] config: Enable 8250 serial port --- arch/arm/configs/bcm2709_defconfig | 7 +++++++ @@ -135777,10 +135778,10 @@ index f952ff2..0c25d8b 100644 CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_BCM2835=m -From 1ae977a7312c852775ea4bd9da294d7010e42dff Mon Sep 17 00:00:00 2001 +From 412a2aa22a41480a5cd8c8a9e4d04a53ef7e7215 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Jun 2015 14:10:58 +0100 -Subject: [PATCH 082/204] config: Enable POWER_RESET_GPIO +Subject: [PATCH 082/278] config: Enable POWER_RESET_GPIO --- arch/arm/configs/bcm2709_defconfig | 2 ++ @@ -135814,10 +135815,10 @@ index 0c25d8b..e757db6 100644 CONFIG_THERMAL=y CONFIG_THERMAL_BCM2835=y -From 5c8ef44617382fa1fa35577714eb1d4e2e17b647 Mon Sep 17 00:00:00 2001 +From 98d15d42c04280aef66aff4046f56c5e3318c132 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 26 Jun 2015 17:37:38 +0100 -Subject: [PATCH 083/204] bcm2708-vcio: Remove restriction of only a single +Subject: [PATCH 083/278] bcm2708-vcio: Remove restriction of only a single instance being open We need more than one process to be able to use mailbox interface (e.g. HW cursor in fbturbo and hello_fft). @@ -135862,10 +135863,10 @@ index d91672b..06fb2c2f 100644 return 0; -From cc364b46f26d4d8fc925ab96616e2443f29a0a60 Mon Sep 17 00:00:00 2001 +From a71bb19d93713b3c541c083c24e86eb6d45c28c4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 26 Jun 2015 08:39:19 +0100 -Subject: [PATCH 084/204] BCM270X_DT: Create a "core" clock, use it for SPI and +Subject: [PATCH 084/278] BCM270X_DT: Create a "core" clock, use it for SPI and sdhost --- @@ -136016,10 +136017,10 @@ index b408ab4..897204a 100644 }; }; -From 18fdf653ca9b05f1e30a4e1cb6bb9320b6642ea9 Mon Sep 17 00:00:00 2001 +From c401db2817365906fc115b0dfc072c8da716e155 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 09:24:31 +0100 -Subject: [PATCH 085/204] BCM270X_DT: Add MCP7941X to i2c-rtc overlay +Subject: [PATCH 085/278] BCM270X_DT: Add MCP7941X to i2c-rtc overlay --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -136072,10 +136073,10 @@ index 6bccfdc..7052c71 100644 pcf8523 = <&pcf8523>,"status"; pcf8563 = <&pcf8563>,"status"; -From 4b29016b330d96063fcb94f935b2c0a18a3a3fde Mon Sep 17 00:00:00 2001 +From 8f8f098f97eb8082f9bd795b6a730942ba7ad9a9 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 24 Jun 2015 11:23:06 +0100 -Subject: [PATCH 086/204] dts/overlays: document DHT11 overlay +Subject: [PATCH 086/278] dts/overlays: document DHT11 overlay --- arch/arm/boot/dts/overlays/README | 8 ++++++++ @@ -136101,10 +136102,10 @@ index 425eb19..9406cf3 100644 -From a64baab36c2fea4043c2e862efd5f2ce979d3671 Mon Sep 17 00:00:00 2001 +From 9ec9b89d68946fbf8c25830d55071547760fde8b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 087/204] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 087/278] 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 @@ -136219,10 +136220,10 @@ index e5332f1..6e3fec2 100644 "%s: pm_power_off function already registered", __func__); -From 751f8f85e9ecb31382f4b15fbf04311da32bd403 Mon Sep 17 00:00:00 2001 +From 6adbb3dc7508aa8e58e1c70a507c6466f81bf429 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 17 Jun 2015 17:10:40 +0100 -Subject: [PATCH 088/204] BCM270x_DT: Default Compute Module i2c, i2s and spi +Subject: [PATCH 088/278] BCM270x_DT: Default Compute Module i2c, i2s and spi support --- @@ -136312,10 +136313,10 @@ index e82fcb2..af252bd 100755 }; }; -From 310ac993d7e597234de083f9e28a950beea57e05 Mon Sep 17 00:00:00 2001 +From b6368c9b7bc077242f2d596eeaac9aec63df13e3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 22 Jun 2015 14:21:55 +0100 -Subject: [PATCH 089/204] BCM270X_DT: Sort nodes by bus address, and +Subject: [PATCH 089/278] BCM270X_DT: Sort nodes by bus address, and consolidate aliases --- @@ -136557,10 +136558,10 @@ index 24fa849..ccb9c31 100644 &gpio { -From e2eb20fe73389475f652fa9ad78db6b9dc5fd780 Mon Sep 17 00:00:00 2001 +From 216d21fd3963c13e5847e43fa8c5c6a2e297cea6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 22 Jun 2015 14:23:03 +0100 -Subject: [PATCH 090/204] i2c-bcm2708/BCM270X_DT: Add support for I2C2 +Subject: [PATCH 090/278] i2c-bcm2708/BCM270X_DT: Add support for I2C2 The third I2C bus (I2C2) is normally reserved for HDMI use. Careless use of this bus can break an attached display - use with caution. @@ -136733,10 +136734,10 @@ index 8773203..7a24fbe 100644 goto out_free_bi; } -From 9845042a17cd1bfc818801e7a5793b00346bb242 Mon Sep 17 00:00:00 2001 +From 2b9cbc7f2e7593e2eb125b0f34ad2d03fcf1d96d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 29 Jun 2015 12:14:02 +0100 -Subject: [PATCH 091/204] BCM270X_DT: Correct the lirc-rpi overlay +Subject: [PATCH 091/278] BCM270X_DT: Correct the lirc-rpi overlay documentation The polarity of the "sense" parameter was inverted with respect to reality. @@ -136762,10 +136763,10 @@ index 0ed7094..ec762d2 100644 (default "-1") -From e75018d8c8385653326af3519474b108f0f74945 Mon Sep 17 00:00:00 2001 +From 9b2fe8a5ea1bac2e924fa6666db64cbe8b83d8ef Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 08:47:09 +0100 -Subject: [PATCH 092/204] bcm2835-sdhost: Further improve overclock back-off +Subject: [PATCH 092/278] bcm2835-sdhost: Further improve overclock back-off --- drivers/mmc/host/bcm2835-sdhost.c | 144 +++++++++++++++++++++----------------- @@ -137057,10 +137058,10 @@ index 6277e43..a03db06 100644 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -From 13cbc57aa3f9dd10bdc8dad7915626d1697c9903 Mon Sep 17 00:00:00 2001 +From 0cf94d9b94bbdd94e4a19163cddc5abe5381acb1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 10:28:59 +0100 -Subject: [PATCH 093/204] i2c-bcm2708: Increase timeouts to allow larger +Subject: [PATCH 093/278] i2c-bcm2708: Increase timeouts to allow larger transfers Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting @@ -137098,10 +137099,10 @@ index 7a24fbe..8b8762d 100644 dev_err(&adap->dev, "transfer timed out\n"); goto error_timeout; -From f7d430536dec32c07a6ba6eb7ed6167ff4974855 Mon Sep 17 00:00:00 2001 +From 1e8798376b1b70d8df42ba906ef5878ffcb903ab Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 10:33:52 +0100 -Subject: [PATCH 094/204] spi-bcm2708: Increase timeout from 150ms to 1s +Subject: [PATCH 094/278] spi-bcm2708: Increase timeout from 150ms to 1s See: https://github.com/raspberrypi/linux/issues/260 --- @@ -137125,10 +137126,10 @@ index 041b5e2..5c0214e 100644 struct bcm2708_spi { spinlock_t lock; -From 9f8135d6ddcbf9ab9dd9678249c3b8c5d17a9229 Mon Sep 17 00:00:00 2001 +From 0eed7dbb226536a9445fe1566a41a7a778691151 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 15 Jun 2015 09:59:38 +0100 -Subject: [PATCH 095/204] bcm2708-spi: Don't use static pin configuration with +Subject: [PATCH 095/278] bcm2708-spi: Don't use static pin configuration with DT Also remove superfluous error checking - the SPI framework ensures the @@ -137167,10 +137168,10 @@ index 5c0214e..781c747 100644 master = spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!master) { -From 8c4cdb44d24dba5443a6bc18b7729ba76967acaa Mon Sep 17 00:00:00 2001 +From 5644403b7733de2453b7b7ac763e57d44d6a36fe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 15 Jun 2015 10:10:59 +0100 -Subject: [PATCH 096/204] bcm2708-i2s: Don't use static pin configuration with +Subject: [PATCH 096/278] bcm2708-i2s: Don't use static pin configuration with DT --- @@ -137193,10 +137194,10 @@ index a515992..5e93cd6 100644 /* * Adjust the data length according to the format. -From 21f6968a52663113eab7b89f7cb192e92d8ea951 Mon Sep 17 00:00:00 2001 +From 4490f5e794c9149eb639c6aec401f3a98e0ec00d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 097/204] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 097/278] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -137216,10 +137217,10 @@ index b4fd8de..f459feb 100644 for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From afddc0087e5b1db8311454fa66909bc400151982 Mon Sep 17 00:00:00 2001 +From be547c10063a14396459e4e2c2546338d5a77847 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 26 Jun 2015 08:50:11 +0100 -Subject: [PATCH 098/204] BCM270X_DT: Add overlay to enable uart1 +Subject: [PATCH 098/278] BCM270X_DT: Add overlay to enable uart1 N.B. The UART1 clock is derived from the core clock. The firmware will update clock-frequency if core_freq is set, but be aware @@ -137388,10 +137389,10 @@ index e757db6..363c894 100644 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y -From 9b7dfacf1ff658c5aa03075776f71c8d6e16564e Mon Sep 17 00:00:00 2001 +From 3cd5a3b39286adbe2b423ce3dde7791242ba64e2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 099/204] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 099/278] 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 @@ -137472,10 +137473,10 @@ index a506773..cf3190f 100644 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From c26edc1513a5086a1a4e0c16746d52423b0259c8 Mon Sep 17 00:00:00 2001 +From 2b98853697886d2501c01c383539177fb5eb75a2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 17:37:38 +0100 -Subject: [PATCH 100/204] BCM270X_DT: Change pio_limit of sdhost driver to 1 +Subject: [PATCH 100/278] BCM270X_DT: Change pio_limit of sdhost driver to 1 --- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 +- @@ -137495,10 +137496,10 @@ index 897204a..2da14a4 100644 }; }; -From 83dda549d089cd0117282ec6edebd697fa59f173 Mon Sep 17 00:00:00 2001 +From f368064ae85f81c2d163da5ee7c77a4d94e283ed Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Jul 2015 12:51:52 +0100 -Subject: [PATCH 101/204] bcm2835-sdhost: Clear HBLC for PIO mode +Subject: [PATCH 101/278] bcm2835-sdhost: Clear HBLC for PIO mode Also update pio_limit default in overlay README. --- @@ -137534,10 +137535,10 @@ index a03db06..d65870a 100644 BUG_ON(!host->data); } -From ecdc3c6d8615d2f5df08e2514cb0b6b12be840e1 Mon Sep 17 00:00:00 2001 +From 68df77076b8e0f71af92240b40d16989716807bc Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 3 Jul 2015 12:21:01 +0100 -Subject: [PATCH 102/204] BCM270X_DT: I2S needs function Alt2 +Subject: [PATCH 102/278] BCM270X_DT: I2S needs function Alt2 --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 2 +- @@ -137599,10 +137600,10 @@ index f25f0a2..62d1c62 100644 }; -From 906a4b80abdc53ea1369eb0ecf310a4b906d2f1c Mon Sep 17 00:00:00 2001 +From 585f0b76376a9b64a0c8908aec010a889357211e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:16:15 +0200 -Subject: [PATCH 103/204] configs: Incorporate v4.1 dependency changes +Subject: [PATCH 103/278] configs: Incorporate v4.1 dependency changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -137765,10 +137766,10 @@ index 363c894..80f84d7 100644 CONFIG_CRC_ITU_T=y CONFIG_LIBCRC32C=y -From 03edd2dd4b9c016f440383c9fae725f5c4e73eca Mon Sep 17 00:00:00 2001 +From 76e06d1c860c0d2ce97aa0cd689657cf649b73c8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 3 Jul 2015 15:47:33 +0100 -Subject: [PATCH 104/204] bcmrpi_defconfigs: Add SND_SOC_WM8804_I2C (for +Subject: [PATCH 104/278] bcmrpi_defconfigs: Add SND_SOC_WM8804_I2C (for HifiBerry Digi) 4.1 has split out support for the I2C and SPI variants, so it now @@ -137803,10 +137804,10 @@ index 80f84d7..14b91fdf 100644 CONFIG_SOUND_PRIME=m CONFIG_HIDRAW=y -From b1c7182dc37e87b47377b529de6e54a431fc07aa Mon Sep 17 00:00:00 2001 +From 08cb2a5643825c1dbe4e6817c523e100c7e90746 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Sat, 4 Jul 2015 19:55:23 +0100 -Subject: [PATCH 105/204] squash: BCM270X_DT: I2S only needs Alt2 on 28-31 +Subject: [PATCH 105/278] squash: BCM270X_DT: I2S only needs Alt2 on 28-31 See: https://github.com/raspberrypi/linux/issues/1046 --- @@ -137855,10 +137856,10 @@ index 62d1c62..f25f0a2 100644 }; -From b52bc261c9b3c08ac73aca166afb05090ffca7eb Mon Sep 17 00:00:00 2001 +From fe05ba5439e24590b4b1bc180b597bf8cb993d11 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 8 Jul 2015 14:48:57 +0100 -Subject: [PATCH 106/204] vchiq_arm: Two cacheing fixes +Subject: [PATCH 106/278] vchiq_arm: Two cacheing fixes 1) Make fragment size vary with cache line size Without this patch, non-cache-line-aligned transfers may corrupt @@ -138129,10 +138130,10 @@ index c739083..5edba23 100644 kfree(pagelist); } -From fc0a0a8a198ad39fa58dd4e2b3efba0a89a9d627 Mon Sep 17 00:00:00 2001 +From 7603d917647e2522d8067c0c6bcd9acc37f4b392 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 09:10:36 +0100 -Subject: [PATCH 107/204] BCM270X_DT: Overlay for the Fen Logic VGA666 board +Subject: [PATCH 107/278] BCM270X_DT: Overlay for the Fen Logic VGA666 board The VGA666 board requires GPIOs 2-21 (so no I2C or UART). Using the overlay (instead of a custom dt-blob.bin) has the advantage that it will @@ -138214,10 +138215,10 @@ index 0000000..7fcab96 + }; +}; -From c9eb6844bc315ee5ab2c807f873ca04d45fc6303 Mon Sep 17 00:00:00 2001 +From 8dea50173689a51c32610aea81198c7a0022519d Mon Sep 17 00:00:00 2001 From: petit-miner Date: Fri, 10 Jul 2015 13:59:18 +0200 -Subject: [PATCH 108/204] Added support for 2 mcp2515 CAN Bus IC +Subject: [PATCH 108/278] Added support for 2 mcp2515 CAN Bus IC See: https://github.com/raspberrypi/linux/issues/1018 https://github.com/raspberrypi/linux/pull/1049 @@ -138347,10 +138348,10 @@ index 0000000..6bef9ae + }; +}; -From 632d8b6abe925d8300a9c824856ea7c286d95229 Mon Sep 17 00:00:00 2001 +From f77141196c685ee3ec5781b190a042977ec5b868 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 5 May 2015 13:27:45 -0700 -Subject: [PATCH 109/204] mailbox: Enable BCM2835 mailbox support +Subject: [PATCH 109/278] mailbox: Enable BCM2835 mailbox support This mailbox driver provides a single mailbox channel to write 32-bit values to the VPU and get a 32-bit response. The Raspberry Pi @@ -138629,10 +138630,10 @@ index 0000000..4b13268 +MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); +MODULE_LICENSE("GPL v2"); -From d9468dc86cfdb7fed108e1e888979b622d578f71 Mon Sep 17 00:00:00 2001 +From 0abc1ba7051398796ce2f655bf52c3045e6b0253 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 13 May 2015 13:10:32 -0700 -Subject: [PATCH 110/204] mailbox/bcm2835: Fix mailbox full detection. +Subject: [PATCH 110/278] mailbox/bcm2835: Fix mailbox full detection. With the VC reader blocked and the ARM writing, MAIL0_STA reads empty permanently while MAIL1_STA goes from empty (0x40000000) to non-empty @@ -138671,10 +138672,10 @@ index 4b13268..0b47dd4 100644 return ret; } -From 518512c73c439f3684fbe42f07048b79be906f4a Mon Sep 17 00:00:00 2001 +From bd47b7bc661d21a2d73fcd8048ea69cf5eed854e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:19:30 +0200 -Subject: [PATCH 111/204] mailbox: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 111/278] mailbox: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -138790,10 +138791,10 @@ index 19b491d..cc07d71 100644 dev_dbg(dev, "%s: mailbox not free\n", __func__); mutex_unlock(&con_mutex); -From 69b0fd32b30439447e33723fde68aadaed7d9b42 Mon Sep 17 00:00:00 2001 +From 6990286fa34cb0dc7b5a89cb18045ee7c48237fc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 4 Jun 2015 13:11:47 -0700 -Subject: [PATCH 112/204] ARM: bcm2835: Add the firmware driver information to +Subject: [PATCH 112/278] ARM: bcm2835: Add the firmware driver information to the RPi DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -138827,10 +138828,10 @@ index 466f02b..5cdfd5a 100644 audio: audio { compatible = "brcm,bcm2835-audio"; -From 0438cbca296cfb3bc165b1f54c4e16f57f5760f0 Mon Sep 17 00:00:00 2001 +From 5584119926486bd13ba9a249d2bb7d3fcccf6b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:21:20 +0200 -Subject: [PATCH 113/204] firmware: bcm2835: Add missing property tags +Subject: [PATCH 113/278] firmware: bcm2835: Add missing property tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -138892,10 +138893,10 @@ index 9d9efb7..d3933af 100644 RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From 2df587b5e056fb8a0eba5efc2023533efb2807be Mon Sep 17 00:00:00 2001 +From fb58672855848cde55e4f6c7f66ccc2364c2ae58 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 114/204] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 114/278] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139001,10 +139002,10 @@ index dd506cd3..b980d53 100644 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From c9295b68944211995a84d596a904f9657b4482c6 Mon Sep 17 00:00:00 2001 +From c11b1cbade80f88de34bb774efd4332d5a7229e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:26:10 +0200 -Subject: [PATCH 115/204] firmware: bcm2835: Support legacy mailbox API +Subject: [PATCH 115/278] firmware: bcm2835: Support legacy mailbox API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139094,10 +139095,10 @@ index d3933af..9a08cf1 100644 u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, -From 2f10d2c9d55ec24c07d869e591d7db9fdde5dfa6 Mon Sep 17 00:00:00 2001 +From f45011102e9f4cda3eb313ba41d418bec61f059b 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 116/204] char: broadcom: Add vcio module +Subject: [PATCH 116/278] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139321,10 +139322,10 @@ index 0000000..c19bc20 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From 8bcd6e604c131b2009b0d9e47561cead558c3d82 Mon Sep 17 00:00:00 2001 +From 1878457cbd4737017a1d9c236160bd8e51274baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:37:19 +0200 -Subject: [PATCH 117/204] BCM270x: Switch to firmware driver +Subject: [PATCH 117/278] BCM270x: Switch to firmware driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139931,10 +139932,10 @@ index 06fb2c2f..2e4031b 100644 MODULE_DESCRIPTION("ARM I/O to VideoCore processor"); MODULE_LICENSE("GPL"); -From 51a7a4a822bc6ab6927bc0522e5afb6bda8f52b4 Mon Sep 17 00:00:00 2001 +From f199fb695244ef2c56baf961669481dceb1c5de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:39:21 +0200 -Subject: [PATCH 118/204] bcm2835: Switch to firmware driver +Subject: [PATCH 118/278] bcm2835: Switch to firmware driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -139990,10 +139991,10 @@ index 47f2a6a..c284414 100644 CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y -From 46dd86c7b1dd676e614daca70ec3b7a31cc905f9 Mon Sep 17 00:00:00 2001 +From c44ca0bd5ac0fa61e25683079b78046afde9b609 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Jul 2015 13:25:31 +0100 -Subject: [PATCH 119/204] Merge pull request #1059 from pelwell/rpi-4.0.y +Subject: [PATCH 119/278] Merge pull request #1059 from pelwell/rpi-4.0.y w1_therm: Back-port locking improvements from 4.2-rc1 --- @@ -140188,10 +140189,10 @@ index 55eb86c..2f029e8 100644 { int err, i; -From 86a4624ee6bc33f41fd7f53d081096ed4aa28cca Mon Sep 17 00:00:00 2001 +From 98ab473b5499e7572b83b165fb1faad941b34ff6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 11:11:51 +0100 -Subject: [PATCH 120/204] vchiq_arm: Sort out the vmalloc case +Subject: [PATCH 120/278] vchiq_arm: Sort out the vmalloc case See: https://github.com/raspberrypi/linux/issues/1055 --- @@ -140230,10 +140231,10 @@ index 5edba23..56bff05 100644 *need_release = 0; /* do not try and release vmalloc pages */ } else { -From 18952e8ccf8d64fb32bb7b2bbd04967047f02840 Mon Sep 17 00:00:00 2001 +From 504380d8268a59d54123ec5276ec0a6ae2f78073 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 121/204] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 121/278] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -140254,10 +140255,10 @@ index 8fab566..a9db602 100644 }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 58f35e5dc8355250d21db3b7ba0aa560d76a0adc Mon Sep 17 00:00:00 2001 +From 50521168f2e04219e9274032b1352fffbc623366 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 122/204] Merge pull request #1043 from XECDesign/sense-4.0 +Subject: [PATCH 122/278] Merge pull request #1043 from XECDesign/sense-4.0 mfd: Add Raspberry Pi Sense HAT core driver --- @@ -141190,10 +141191,10 @@ index 0000000..56196dc + +#endif -From 7ec906836d03f54c2f62372c25a413af323c2564 Mon Sep 17 00:00:00 2001 +From 29bb619a239e455d18e9551bd3178cd2a200b056 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jul 2015 13:46:08 +0100 -Subject: [PATCH 123/204] leds-gpio: Implement the brightness_get method +Subject: [PATCH 123/278] leds-gpio: Implement the brightness_get method The power LED uses some clever logic that means it is driven by a voltage measuring circuit when configured as input, otherwise @@ -141236,10 +141237,10 @@ index 3cfbd6a..4e4e132 100644 state = !!gpiod_get_value_cansleep(led_dat->gpiod); else -From 0cfac48f6780a5038da6e0fc0e37dfc3975f2077 Mon Sep 17 00:00:00 2001 +From 1a2d904e7a40d547a5ccff5767d9c1ad690f5a08 Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Fri, 17 Jul 2015 09:50:55 +0200 -Subject: [PATCH 124/204] dmaengine: bcm2708-dmaengine: Fix memory leak when +Subject: [PATCH 124/278] dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer --- @@ -141259,10 +141260,10 @@ index 987ed53..73c6c00 100644 bcm2835_dma_abort(c->chan_base); -From 095268253a866ff43278ff24f4a7502949c6cf92 Mon Sep 17 00:00:00 2001 +From 7778211a9bc17f57bb07a1c66ffa8d4cd687f22f Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:13 +0200 -Subject: [PATCH 125/204] BCM270X_DT: Fix I2S register map +Subject: [PATCH 125/278] BCM270X_DT: Fix I2S register map --- arch/arm/boot/dts/bcm2708_common.dtsi | 4 ++-- @@ -141284,10 +141285,10 @@ index 2dd25f7..728e14a 100644 //dmas = <&dma 2>, // <&dma 3>; -From 649b011d757054ad6d9d5702f8d3bf670a42e404 Mon Sep 17 00:00:00 2001 +From d18f5eacd5bd806b85a6d5251f42abcd7163ff0e Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 126/204] BCM2835_DT: Fix I2S register map +Subject: [PATCH 126/278] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -141341,10 +141342,10 @@ index 4a63704..1135120 100644 dmas = <&dma 2>, <&dma 3>; -From 5076ca8360f9ad0d46a060fcde7eefe7fb10eea1 Mon Sep 17 00:00:00 2001 +From 4dcfd42ad88596da2d80b03c0177534e43aa5ba8 Mon Sep 17 00:00:00 2001 From: David Frey Date: Tue, 14 Jul 2015 15:57:36 +0200 -Subject: [PATCH 127/204] config: Enable SHT drivers for raspberry pi +Subject: [PATCH 127/278] config: Enable SHT drivers for raspberry pi The SHT temperature and humidity sensors are often used in weather station projects. @@ -141386,10 +141387,10 @@ index b9b5bdf..7b24274 100644 CONFIG_THERMAL_BCM2835=y CONFIG_WATCHDOG=y -From 2e23dd0be7034e7aee9795288d9de1ed151ad5fd Mon Sep 17 00:00:00 2001 +From 5494637b49c6566e5194466943058f3c746e6fcb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 14:07:14 +0100 -Subject: [PATCH 128/204] BCM270X_DT: Correct typo in overlays/README +Subject: [PATCH 128/278] BCM270X_DT: Correct typo in overlays/README --- arch/arm/boot/dts/overlays/README | 2 +- @@ -141409,10 +141410,10 @@ index 8792f98..ed484ae 100644 i2c_arm Set to "on" to enable the ARM's i2c interface -From dc0a5bcc935ccc881fb4043dc949af755d3e8f1c Mon Sep 17 00:00:00 2001 +From 0b9e10a4f393083b470d2498cc36bf96c5874b58 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 10:53:26 +0100 -Subject: [PATCH 129/204] bcm2835-sdhost: Add the ERASE capability +Subject: [PATCH 129/278] bcm2835-sdhost: Add the ERASE capability See: https://github.com/raspberrypi/linux/issues/1076 --- @@ -141433,10 +141434,10 @@ index d65870a..57a6ad3 100644 spin_lock_init(&host->lock); -From 54ef0643fae43fff2cb1583919a34f787ad132af Mon Sep 17 00:00:00 2001 +From a7e50e9d4ea5809bea8cbff68a0ac5982d262744 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 17:32:18 +0100 -Subject: [PATCH 130/204] bcm2835-sdhost: Ignore CRC7 for MMC CMD1 +Subject: [PATCH 130/278] bcm2835-sdhost: Ignore CRC7 for MMC CMD1 It seems that the sdhost interface returns CRC7 errors for CMD1, which is the MMC-specific SEND_OP_COND. Returning these errors to @@ -141500,10 +141501,10 @@ index 57a6ad3..84f645f 100644 if (host->cmd->flags & MMC_RSP_PRESENT) { -From 24f4ffb4f7a2f5b37197a168485207216b736adb Mon Sep 17 00:00:00 2001 +From bfc887c5a51aed2b54bb7ec3350b60f241f62740 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jul 2015 14:48:21 +0100 -Subject: [PATCH 131/204] BCM270X_DT: Add unit address to gpio node name +Subject: [PATCH 131/278] BCM270X_DT: Add unit address to gpio node name --- arch/arm/boot/dts/bcm2708_common.dtsi | 2 +- @@ -141523,10 +141524,10 @@ index 728e14a..cb608df 100644 reg = <0x7e200000 0xb4>; interrupts = <2 17>, <2 18>; -From 7d633f69a6cbc12d37782f6ab96e402eb1b18949 Mon Sep 17 00:00:00 2001 +From 17c28653e1dd93b3f85bc9603db780a20e433d5c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 24 Jul 2015 10:36:32 +0100 -Subject: [PATCH 132/204] BCM270X_DT: Use i2c_arm for rtc and bmp085 overlays +Subject: [PATCH 132/278] BCM270X_DT: Use i2c_arm for rtc and bmp085 overlays --- arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts | 2 +- @@ -141560,10 +141561,10 @@ index 7052c71..fed4bd8 100644 #address-cells = <1>; #size-cells = <0>; -From 70694a4073fa62862c93ab409b49d3d86071a6c0 Mon Sep 17 00:00:00 2001 +From 0caf9d051a535a8ae01f2bb4d7ebbf870eda68f3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 24 Jul 2015 12:11:31 +0100 -Subject: [PATCH 133/204] BCM2708_DT: CM dtparams for audio, watchdog and RNG +Subject: [PATCH 133/278] BCM2708_DT: CM dtparams for audio, watchdog and RNG --- arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 8 ++++---- @@ -141593,10 +141594,10 @@ index 34d4bc6..713e5a2 100644 }; }; -From a36ecdc70162e181fac2f7b7afb952639df22384 Mon Sep 17 00:00:00 2001 +From 9393cd2eb6a2e5cb43b226c48e7562a20bdde6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:13:18 +0200 -Subject: [PATCH 134/204] vchiq: Use firmware API +Subject: [PATCH 134/278] vchiq: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -141712,10 +141713,10 @@ index 31e2cba..e11c0e0 100644 err = vchiq_debugfs_init(); if (err != 0) -From 97df14a49141d2831362aac3d18875d271b1a97f Mon Sep 17 00:00:00 2001 +From 11c9e83521909809bf0dd53860e31a1de18b2774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:17:10 +0200 -Subject: [PATCH 135/204] thermal: bcm2835: Use firmware API +Subject: [PATCH 135/278] thermal: bcm2835: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -141998,10 +141999,10 @@ index 3bc80f1..c1d8f1b 100644 -module_platform_driver(bcm2835_thermal_driver); +MODULE_LICENSE("GPL"); -From c2e3b884a9498adb58d4d403465e2d99ddd79e61 Mon Sep 17 00:00:00 2001 +From ea78d55755fd86c6dd39a084f941a0f0c7547944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:18:36 +0200 -Subject: [PATCH 136/204] cpufreq: bcm2835: Use firmware API +Subject: [PATCH 136/278] cpufreq: bcm2835: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142185,10 +142186,10 @@ index 6735da9..3eb9e93 100644 } -From 1ef7396bd8f7fa5452d762b9c534552604c0ec35 Mon Sep 17 00:00:00 2001 +From b33aacadbb1c946cda4904762fd659e491202a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:20:59 +0200 -Subject: [PATCH 137/204] fbdev: bcm2708: Use firmware API +Subject: [PATCH 137/278] fbdev: bcm2708: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142604,10 +142605,10 @@ index f6ac7da..06a96d16 100644 free_irq(fb->dma_irq, fb); -From e24a0ff68aeded060486f55911653aec60ea87c7 Mon Sep 17 00:00:00 2001 +From 06ef9603501eaa19b408f0dcb2256de4cd607a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 20 Jul 2015 12:27:17 +0200 -Subject: [PATCH 138/204] bcm2835: Add firmware property to affected devices +Subject: [PATCH 138/278] bcm2835: Add firmware property to affected devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142688,10 +142689,10 @@ index 1135120..807264d 100644 clocks { -From 4fa2f3a62adf17ef122476d8fc63b132a717d71f Mon Sep 17 00:00:00 2001 +From 763f71573d07480bb1d8f2f99eeb878f7c44f8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 21 Jul 2015 19:09:39 +0200 -Subject: [PATCH 139/204] rpi-ft5406: Use firmware API +Subject: [PATCH 139/278] rpi-ft5406: Use firmware API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142831,10 +142832,10 @@ index d41851d..c08817e 100644 ts->regs = (struct ft5406_regs *) ts->ts_base; -From 70b5d66ef90adc3ee74708ecf15fd5fd3c6a3f9e Mon Sep 17 00:00:00 2001 +From 65b515748a861ae662ac45b5d3a989f044cfde56 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 140/204] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 140/278] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -142966,10 +142967,10 @@ index 5916d6c..db66246 100644 } -From 48ff5ec47ad9778a6d2eb5d75ee2e161302673fa Mon Sep 17 00:00:00 2001 +From c8650561dc2a36e433e769a9abb6e23c68a1242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 15:50:04 +0200 -Subject: [PATCH 141/204] dwc_otg: Add ARCH_BCM2835 support +Subject: [PATCH 141/278] dwc_otg: Add ARCH_BCM2835 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143022,10 +143023,10 @@ index 0f4ebcd..5c83309 100644 } -From 28a1fd2b8afaf5524cca8890394f9fc07c8a8b71 Mon Sep 17 00:00:00 2001 +From da4400c6f9f667118be6d6b84f5277631479a526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 15:50:24 +0200 -Subject: [PATCH 142/204] bcm2835: Use DWC_OTG +Subject: [PATCH 142/278] bcm2835: Use DWC_OTG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143068,10 +143069,10 @@ index c284414..14ef294 100644 CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From cf7a056866fba1d602de661a47cd0548dfe2304b Mon Sep 17 00:00:00 2001 +From 1b7fdbfce8a0b6d481783f7b58aeb3a5d0018efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:33:16 +0200 -Subject: [PATCH 143/204] Fix RASPBERRYPI_FIRMWARE dependents +Subject: [PATCH 143/278] Fix RASPBERRYPI_FIRMWARE dependents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143152,10 +143153,10 @@ index b89998b7..08678b9 100644 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT -From 16b9943dbfbc7d7f19f44e91808dc1450ca9d4b4 Mon Sep 17 00:00:00 2001 +From 08e28b36aa1f14a39c8f61e9be0cb8776c7128f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:33:46 +0200 -Subject: [PATCH 144/204] vc_mem: Remove unnecessary include +Subject: [PATCH 144/278] vc_mem: Remove unnecessary include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143178,10 +143179,10 @@ index fcde6b1..be64f23 100644 #define DRIVER_NAME "vc-mem" -From d98428b8e2a5bb9815aaa3eed3e0777f50f55196 Mon Sep 17 00:00:00 2001 +From 90ad3d4c3ed68a9524942c6bc46e7d0ed6503f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:06 +0200 -Subject: [PATCH 145/204] configs: Remove BCM2708_MBOX +Subject: [PATCH 145/278] configs: Remove BCM2708_MBOX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143230,10 +143231,10 @@ index 7b24274..0859113 100644 # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXTCON=m -From b3b0ebfd9dd4bcd6fe8d787aa7740a47f419da9f Mon Sep 17 00:00:00 2001 +From 5390f1521dd8fcef75cd21e26543be02370af6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:31 +0200 -Subject: [PATCH 146/204] bcm2708-vcio: Remove module +Subject: [PATCH 146/278] bcm2708-vcio: Remove module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -143507,10 +143508,10 @@ index d3ea839..0000000 - -#endif -From 6fadac31b6bf0690059342642ff4453d6d95a2d8 Mon Sep 17 00:00:00 2001 +From 2beb16e7abcd4faf212d69fc89291ec75909e8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 24 Jul 2015 19:34:55 +0200 -Subject: [PATCH 147/204] Revert "firmware: bcm2835: Support legacy mailbox +Subject: [PATCH 147/278] Revert "firmware: bcm2835: Support legacy mailbox API" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -143601,10 +143602,10 @@ index 9a08cf1..d3933af 100644 u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, -From 9418fab5167ef4095a62ba3b11d9e420595cf559 Mon Sep 17 00:00:00 2001 +From cf926787c9db379504cb78d2cf65dc1283665591 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Tue, 30 Jun 2015 12:35:39 +0100 -Subject: [PATCH 148/204] pinctrl: bcm2835: Clear the event latch register when +Subject: [PATCH 148/278] pinctrl: bcm2835: Clear the event latch register when disabling interrupts It's possible to hit a race condition if interrupts are generated on a GPIO @@ -143641,10 +143642,10 @@ index 986779a..61ef002 100644 spin_unlock_irqrestore(&pc->irq_lock[bank], flags); } -From 1a099cd189c09d3dc5d2e0ed2061cb9b0dcd2a0b Mon Sep 17 00:00:00 2001 +From 74345136dd3f9bee648635995c25f88def12cfa9 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 4 Aug 2015 01:15:20 +0100 -Subject: [PATCH 149/204] dwc_otg: fiq_fsm: Make high-speed isochronous strided +Subject: [PATCH 149/278] dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly Certain low-bandwidth high-speed USB devices (specialist audio devices, @@ -143784,10 +143785,10 @@ index 3f71f29..8db3dfc 100644 case FIQ_PER_SPLIT_LS_ABORTED: -From 671205b0f0ec871b8fcabbab6d9a2ffb3444378c Mon Sep 17 00:00:00 2001 +From ae470066222c5f32ef5172fd12ff5027b11f5d6f Mon Sep 17 00:00:00 2001 From: Uli Middelberg Date: Wed, 17 Jun 2015 10:36:56 +0200 -Subject: [PATCH 150/204] added basic docker support +Subject: [PATCH 150/278] added basic docker support --- arch/arm/configs/bcm2709_defconfig | 3 +++ @@ -143851,10 +143852,10 @@ index 0859113..06e7529 100644 CONFIG_FSCACHE_STATS=y CONFIG_FSCACHE_HISTOGRAM=y -From 1621191b72eef418410908e1b789381f2956275e Mon Sep 17 00:00:00 2001 +From 1c1c7183d63895d394e79eaf0971801ca5ec005d Mon Sep 17 00:00:00 2001 From: Garrett Date: Thu, 2 Jul 2015 19:32:04 -0500 -Subject: [PATCH 151/204] bcm2835 camera planar/packed stride length +Subject: [PATCH 151/278] bcm2835 camera planar/packed stride length Added a field to the mmal_fmt struct used to compute the bytes per line when using a particular format. This results in the correct stride being @@ -144026,10 +144027,10 @@ index 35698c8..15788a1 100644 /* buffer for one video frame */ -From 86b0488fa249c00bd7c381fe637026a7f33a6ffa Mon Sep 17 00:00:00 2001 +From c172a7453e174a470f4642fa1ad37195d96a6611 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 17 Aug 2015 10:49:44 +0100 -Subject: [PATCH 154/204] BCM270X_DT: Add pwm and pwm-2chan overlays +Subject: [PATCH 154/278] BCM270X_DT: Add pwm and pwm-2chan overlays From the README entries: Legal pin,function combinations for each channel: @@ -144295,10 +144296,10 @@ index b1541f4..90591a9 100644 PWM framework driver for BCM2835 controller (Raspberry Pi) -From 0d1f86de027a4406151de275663b2cb68d3b39f5 Mon Sep 17 00:00:00 2001 +From 4b1505ce4c7c75ad68164fb46a5384cf1e8f4d7c Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Apr 2015 07:33:03 +0000 -Subject: [PATCH 155/204] spi: bcm2835: fallback to interrupt for polling +Subject: [PATCH 155/278] spi: bcm2835: fallback to interrupt for polling timeouts exceeding 2 jiffies The polling mode of the driver is designed for transfers that run @@ -144434,10 +144435,10 @@ index cf3190f..505a993 100644 struct spi_device *spi, struct spi_transfer *tfr) -From 9a96e7390f5bb3db6138d07ffe6145c17e53246d Mon Sep 17 00:00:00 2001 +From 2fead4f30a07f85c28e730c4d41332c8c9ba2eca Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Sun, 10 May 2015 20:47:28 +0000 -Subject: [PATCH 156/204] spi: bcm2835: enable dma modes for transfers meeting +Subject: [PATCH 156/278] spi: bcm2835: enable dma modes for transfers meeting certain conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -144860,10 +144861,10 @@ index 505a993..27fb5b0 100644 } -From 6e92fd1644001ba7827e2706c0ed4fd4c2d85bc1 Mon Sep 17 00:00:00 2001 +From 93ff62a97a33f9de56bcd1cc3c9ceddbe49836a8 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 12 May 2015 10:32:08 +0000 -Subject: [PATCH 157/204] spi: bcm2835: fix kbuild compile warnings/errors and +Subject: [PATCH 157/278] spi: bcm2835: fix kbuild compile warnings/errors and a typo fixes several warnings/error emmitted by the kbuild system: @@ -144919,10 +144920,10 @@ index 27fb5b0..52aaf2d 100644 "Unaligned spi tx-transfer bridging page\n"); return false; -From 63ad0b9f2b638c3968473d46f732de9f28ad184b Mon Sep 17 00:00:00 2001 +From b2a51b3e348bab5c16db54e6071256519cf642b7 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 12 May 2015 19:43:59 +0800 -Subject: [PATCH 158/204] spi: bcm2835: bcm2835_dma_release() can be static +Subject: [PATCH 158/278] spi: bcm2835: bcm2835_dma_release() can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown @@ -144954,10 +144955,42 @@ index 52aaf2d..bad36c5 100644 struct dma_slave_config slave_config; const __be32 *addr; -From f3260b7d15164b1ddd0f080592defb79949db0aa Mon Sep 17 00:00:00 2001 +From b001cd6a6bebdbfbca679e60c090d7f9a964f231 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Wed, 22 Jul 2015 07:43:28 +0000 +Subject: [PATCH 159/278] spi: bcm2835: fixed compile issues due to embedded + comments... replaced with #if to avoid issues in the future. + +Signed-off-by: Martin Sperl +--- + drivers/spi/spi-bcm2835.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index bad36c5..b5c1123 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -609,6 +609,7 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, + return 0; + } + ++#if 0 + static void bcm2835_spi_handle_err(struct spi_master *master, + struct spi_message *msg) + { +@@ -623,6 +624,7 @@ static void bcm2835_spi_handle_err(struct spi_master *master, + /* and reset */ + bcm2835_spi_reset_hw(master); + } ++#endif + + static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { + +From 04e67d061baea0c514289df9157e7a8e7be9adf5 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Jul 2015 08:34:41 +0000 -Subject: [PATCH 159/204] dt-overlay to enable dma for spi driver +Subject: [PATCH 160/278] dt-overlay to enable dma for spi driver Signed-off-by: Martin Sperl --- @@ -145005,10 +145038,10 @@ index 0000000..266cf9d + }; + }; -From 67c4106248a6d4eaee1de239e8f18da5e08ed8fd Mon Sep 17 00:00:00 2001 +From 16f8343e27b8392174402c99535b6e9ef845b1c4 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 22 Jul 2015 12:41:54 +0000 -Subject: [PATCH 160/204] dt: overlay: added documentation of spi-dma overlay +Subject: [PATCH 161/278] dt: overlay: added documentation of spi-dma overlay Signed-off-by: Martin Sperl --- @@ -145033,10 +145066,10 @@ index 1cd2140..bda8c14 100644 Info: 3.5" Color TFT Display by www.tinylcd.com Options: Touch, RTC, keypad -From 1981274d8b58c613e5f3f0f40068f25ffcdbe481 Mon Sep 17 00:00:00 2001 +From 444bb34e3561106d475c4b5a001e2b6df5994697 Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Mon, 17 Aug 2015 18:06:16 +0100 -Subject: [PATCH 161/204] rpisense-fb: add low-light mode and gamma control +Subject: [PATCH 162/278] rpisense-fb: add low-light mode and gamma control --- drivers/video/fbdev/rpisense-fb.c | 68 +++++++++++++++++++++++++++++--- @@ -145179,10 +145212,40 @@ index c4c1118..2ba95d7 100644 struct rpisense; -From 82bd9aca8c50e84e17b9c62a6d5c528aa8f0e490 Mon Sep 17 00:00:00 2001 +From f1feb5092241c6dacd666e9adb344c2308ba8a52 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 18 Aug 2015 11:50:03 +0100 +Subject: [PATCH 163/278] spi: bcm2835: Fix buld error from previous commit + +--- + drivers/spi/spi-bcm2835.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index b5c1123..bad36c5 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -609,7 +609,6 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, + return 0; + } + +-#if 0 + static void bcm2835_spi_handle_err(struct spi_master *master, + struct spi_message *msg) + { +@@ -624,7 +623,6 @@ static void bcm2835_spi_handle_err(struct spi_master *master, + /* and reset */ + bcm2835_spi_reset_hw(master); + } +-#endif + + static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) + { + +From d68e70e1282e2621a355638c4a67d3a7f6254b43 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 19 Aug 2015 11:38:10 +0100 -Subject: [PATCH 162/204] BCM270X_DT: README - add note on indentation +Subject: [PATCH 164/278] BCM270X_DT: README - add note on indentation --- arch/arm/boot/dts/overlays/README | 4 ++++ @@ -145204,10 +145267,10 @@ index bda8c14..ac9c427 100644 Info: Configures the base Raspberry Pi hardware Load: -From b6277bf87e266469ee14448d41209f79f3caa8d1 Mon Sep 17 00:00:00 2001 +From 5c922b5c3dfd8ae456c532a41f403f3ebe443551 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 20 Aug 2015 13:50:18 +0100 -Subject: [PATCH 163/204] bcm2708-dmaengine: Use more DMA channels (but not 12) +Subject: [PATCH 165/278] bcm2708-dmaengine: Use more DMA channels (but not 12) 1) Only the bcm2708_fb drivers uses the legacy DMA API, and it requires a BULK-capable channel, so all other types @@ -145381,10 +145444,521 @@ index 73c6c00..85ce18b 100644 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) -From 72de9ce92b348a0f4f9230affa0e27d3f775342e Mon Sep 17 00:00:00 2001 +From b05ddc77a21e746431e6b81adfe0a0bf86d6c48b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 11 Jul 2015 18:48:10 +0200 +Subject: [PATCH 166/278] staging: fbtft: Add reset to fbtft_init_display_dt() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When an init sequence is present in the Device Tree, +fbtft_init_display_dt() is used to initialize the display. +Add missing reset function call and activation of +chip select for parallel bus. + +Signed-off-by: Noralf Trønnes +--- + drivers/staging/fbtft/fbtft-core.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c +index 53b748b..4f165d3 100644 +--- a/drivers/staging/fbtft/fbtft-core.c ++++ b/drivers/staging/fbtft/fbtft-core.c +@@ -1074,6 +1074,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) + p = of_prop_next_u32(prop, NULL, &val); + if (!p) + return -EINVAL; ++ ++ par->fbtftops.reset(par); ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ + while (p) { + if (val & FBTFT_OF_INIT_CMD) { + val &= 0xFFFF; + +From cd43f83e67e7e0917052444966f737ab896f41f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 19 Jul 2015 18:57:06 +0200 +Subject: [PATCH 167/278] BCM270X_DT: mz61581: Revert to spi-bcm2708 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The MZ61581 display does not work with spi-bcm2835 and software +chip select. It works before the commit: +spi: bcm2835: transform native-cs to gpio-cs on first spi_setup + +Revert to spi-bcm2708 until the cause has been detected and the +issue resolved. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index c06fe12..f674a66 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -12,6 +12,8 @@ + fragment@0 { + target = <&spi0>; + __overlay__ { ++ /* does not work with spi-bcm2835 using software chip selects */ ++ compatible = "brcm,bcm2708-spi"; + status = "okay"; + + spidev@0{ + +From d1dc22f2e8fefa9069ada02c2e66c6bfc4a7809a Mon Sep 17 00:00:00 2001 +From: Luke Wren +Date: Fri, 21 Aug 2015 23:14:48 +0100 +Subject: [PATCH 168/278] Add /dev/gpiomem device for rootless user GPIO access + +Signed-off-by: Luke Wren +--- + arch/arm/boot/dts/bcm2708.dtsi | 6 + + arch/arm/boot/dts/bcm2709.dtsi | 6 + + drivers/char/broadcom/Kconfig | 9 ++ + drivers/char/broadcom/Makefile | 3 + + drivers/char/broadcom/bcm2835-gpiomem.c | 265 ++++++++++++++++++++++++++++++++ + 5 files changed, 289 insertions(+) + create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c + +diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +index 0d47427..3bed0a6 100644 +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -15,5 +15,11 @@ + arm-pmu { + compatible = "arm,arm1176-pmu"; + }; ++ ++ gpiomem { ++ compatible = "brcm,bcm2835-gpiomem"; ++ reg = <0x7e200000 0x1000>; ++ status = "okay"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi +index 5e0b935..811d825 100644 +--- a/arch/arm/boot/dts/bcm2709.dtsi ++++ b/arch/arm/boot/dts/bcm2709.dtsi +@@ -16,6 +16,12 @@ + compatible = "arm,cortex-a7-pmu"; + interrupts = <3 9>; + }; ++ ++ gpiomem { ++ compatible = "brcm,bcm2835-gpiomem"; ++ reg = <0x7e200000 0x1000>; ++ status = "okay"; ++ }; + }; + + timer { +diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig +index fc40846..bc2eb1e 100644 +--- a/drivers/char/broadcom/Kconfig ++++ b/drivers/char/broadcom/Kconfig +@@ -38,3 +38,12 @@ config BCM_VC_SM + help + Support for the VC shared memory on the Broadcom reference + design. Uses the VCHIQ stack. ++ ++config BCM2835_DEVGPIOMEM ++ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835" ++ default m ++ help ++ Provides users with root-free access to the GPIO registers ++ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. ++ +diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile +index 18171e2..664e2c4 100644 +--- a/drivers/char/broadcom/Makefile ++++ b/drivers/char/broadcom/Makefile +@@ -2,3 +2,6 @@ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o + obj-$(CONFIG_BCM_VCIO) += vcio.o + obj-$(CONFIG_BCM_VC_SM) += vc_sm/ ++ ++obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o ++ +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +new file mode 100644 +index 0000000..0085e13 +--- /dev/null ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -0,0 +1,265 @@ ++/** ++ * GPIO memory device driver ++ * ++ * Creates a chardev /dev/gpiomem which will provide user access to ++ * the BCM2835's GPIO registers when it is mmap()'d. ++ * No longer need root for user GPIO access, but without relaxing permissions ++ * on /dev/mem. ++ * ++ * Written by Luke Wren ++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "bcm2835-gpiomem" ++#define DRIVER_NAME "gpiomem-bcm2835" ++#define DEVICE_MINOR 0 ++ ++struct bcm2835_gpiomem_instance { ++ unsigned long gpio_regs_phys; ++ struct device *dev; ++}; ++ ++static struct cdev bcm2835_gpiomem_cdev; ++static dev_t bcm2835_gpiomem_devid; ++static struct class *bcm2835_gpiomem_class; ++static struct device *bcm2835_gpiomem_dev; ++static struct bcm2835_gpiomem_instance *inst; ++ ++ ++/**************************************************************************** ++* ++* GPIO mem chardev file ops ++* ++***************************************************************************/ ++ ++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; ++ } ++ return ret; ++} ++ ++static int bcm2835_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ /* Ignore what the user says - they're getting the GPIO regs ++ whether they like it or not! */ ++ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT; ++ ++ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page, ++ PAGE_SIZE, ++ vma->vm_page_prot); ++ vma->vm_ops = &bcm2835_gpiomem_vm_ops; ++ if (remap_pfn_range(vma, vma->vm_start, ++ gpio_page, ++ PAGE_SIZE, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++static const struct file_operations ++bcm2835_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = bcm2835_gpiomem_open, ++ .release = bcm2835_gpiomem_release, ++ .mmap = bcm2835_gpiomem_mmap, ++}; ++ ++ ++ /**************************************************************************** ++* ++* Probe and remove functions ++* ++***************************************************************************/ ++ ++ ++static int bcm2835_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err; ++ void *ptr_err; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct resource *ioresource; ++ ++ /* Allocate buffers and instance data */ ++ ++ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL); ++ ++ if (!inst) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ ++ inst->dev = dev; ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&bcm2835_gpiomem_devid, ++ DEVICE_MINOR, 1, DEVICE_NAME); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops); ++ bcm2835_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); ++ ptr_err = bcm2835_gpiomem_class; ++ if (IS_ERR(ptr_err)) ++ goto failed_class_create; ++ ++ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL, ++ bcm2835_gpiomem_devid, NULL, ++ "gpiomem"); ++ ptr_err = bcm2835_gpiomem_dev; ++ if (IS_ERR(ptr_err)) ++ goto failed_device_create; ++ ++ /* Get address from device tree if available (*_resource() correctly ++ converts the bus address in device tree to a physical address), ++ or use hardcoded offset + BCM2708_PERI_BASE if not. ++ (In spite of its name 2708 actually seems to have the correct ++ mach-dependent value on 2709 etc, as it is defined in ++ mach-bcm270x/platform.h) */ ++ ++ if (node) { ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ inst->gpio_regs_phys = GPIO_BASE; ++ } ++ ++ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", ++ inst->gpio_regs_phys); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(bcm2835_gpiomem_class); ++failed_class_create: ++ cdev_del(&bcm2835_gpiomem_cdev); ++ err = PTR_ERR(ptr_err); ++failed_cdev_add: ++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); ++failed_alloc_chrdev: ++ kfree(inst); ++failed_inst_alloc: ++ dev_err(inst->dev, "could not load bcm2835_gpiomem"); ++ return err; ++} ++ ++static int bcm2835_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = inst->dev; ++ ++ kfree(inst); ++ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid); ++ class_destroy(bcm2835_gpiomem_class); ++ cdev_del(&bcm2835_gpiomem_cdev); ++ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); ++ ++ dev_info(dev, "GPIO mem driver removed - OK"); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Register the driver with device tree ++* ++***************************************************************************/ ++ ++static const struct of_device_id bcm2835_gpiomem_of_match[] = { ++ {.compatible = "brcm,bcm2835-gpiomem",}, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match); ++ ++static struct platform_driver bcm2835_gpiomem_driver = { ++ .probe = bcm2835_gpiomem_probe, ++ .remove = bcm2835_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = bcm2835_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(bcm2835_gpiomem_driver); ++ ++MODULE_ALIAS("platform:gpiomem-bcm2835"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); ++MODULE_AUTHOR("Luke Wren "); + +From 30390d79fb7c138010adb59ee24420b0db1bd025 Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Mon, 24 Aug 2015 16:02:34 +0100 +Subject: [PATCH 169/278] tpa6130a2: Add headphone switch control + +Signed-off-by: Jan Grulich +--- + sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c +index 6fac9e0..f60ebe1c 100644 +--- a/sound/soc/codecs/tpa6130a2.c ++++ b/sound/soc/codecs/tpa6130a2.c +@@ -4,6 +4,7 @@ + * Copyright (C) Nokia Corporation + * + * Author: Peter Ujfalusi ++ * Modified: Jan Grulich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -52,6 +53,8 @@ struct tpa6130a2_data { + enum tpa_model id; + }; + ++static void tpa6130a2_channel_enable(u8 channel, int enable); ++ + static int tpa6130a2_i2c_read(int reg) + { + struct tpa6130a2_data *data; +@@ -189,7 +192,7 @@ static int tpa6130a2_power(u8 power) + } + + static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) ++ struct snd_ctl_elem_value *ucontrol) + { + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; +@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, + } + + static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) ++ struct snd_ctl_elem_value *ucontrol) + { + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; +@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, + return 1; + } + ++static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ int enable = ucontrol->value.integer.value[0]; ++ unsigned int state; ++ ++ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0; ++ if (state == enable) ++ return 0; /* No change */ ++ ++ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable); ++ return 1; /* Changed */ ++} ++ + /* +- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going ++ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going + * down in gain. + */ + static const unsigned int tpa6130_tlv[] = { +@@ -278,6 +295,9 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { + TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, + tpa6130a2_get_volsw, tpa6130a2_put_volsw, + tpa6130_tlv), ++ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch", ++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, ++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), + }; + + static const unsigned int tpa6140_tlv[] = { +@@ -292,6 +312,9 @@ static const struct snd_kcontrol_new tpa6140a2_controls[] = { + TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, + tpa6130a2_get_volsw, tpa6130a2_put_volsw, + tpa6140_tlv), ++ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch", ++ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, ++ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), + }; + + /* + +From 520c391058dfa211d8886ffc7445d39970c8f8b3 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 164/204] RaspiDAC3 support +Subject: [PATCH 170/278] RaspiDAC3 support Signed-off-by: Jan Grulich --- @@ -145735,10 +146309,10 @@ index 0000000..fddaeec +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From 5639b22eb081048b07152c5bd90d25d7768cb1cf Mon Sep 17 00:00:00 2001 +From 754681b13bca3e13c25d634b712206ed1e025827 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 14 Jul 2015 16:55:02 +0100 -Subject: [PATCH 165/204] config: Add SND_SOC_ADAU1701 module +Subject: [PATCH 171/278] config: Add SND_SOC_ADAU1701 module --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -145770,10 +146344,10 @@ index 8979f23..7dd4fd4 100644 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 6a0f88404b8cc24c073b1d157be02fbc9007788a Mon Sep 17 00:00:00 2001 +From 7ee6b5002a6d79f7e417b3df39a58cfcff6e35ca Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 29 Jul 2015 07:34:10 +0000 -Subject: [PATCH 166/204] spi: bcm2835: fix overflow in calculation of transfer +Subject: [PATCH 172/278] spi: bcm2835: fix overflow in calculation of transfer time This resulted in the use of polling mode when other approaches @@ -145826,10 +146400,10 @@ index bad36c5..b68991c 100644 /* for short requests run polling*/ if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) -From 74f48a53e476a7d34ab0a58c883149b19e5bbdec Mon Sep 17 00:00:00 2001 +From 7a0645687fefdfaa92960e349f54c477e6918061 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Sep 2015 15:14:50 +0100 -Subject: [PATCH 167/204] BCM270X_DT: Add SDIO overlay +Subject: [PATCH 173/278] BCM270X_DT: Add SDIO overlay Enable SDIO from MMC interface via GPIOs 22-27. Includes the sdhost overlay to free up the MMC interface. @@ -145914,521 +146488,10 @@ index 0000000..164f269 + }; +}; -From a216fc64bde9a95901c92deb7bcd7f3fe4567f75 Mon Sep 17 00:00:00 2001 -From: Luke Wren -Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 168/204] Add /dev/gpiomem device for rootless user GPIO access - -Signed-off-by: Luke Wren ---- - arch/arm/boot/dts/bcm2708.dtsi | 6 + - arch/arm/boot/dts/bcm2709.dtsi | 6 + - drivers/char/broadcom/Kconfig | 9 ++ - drivers/char/broadcom/Makefile | 3 + - drivers/char/broadcom/bcm2835-gpiomem.c | 265 ++++++++++++++++++++++++++++++++ - 5 files changed, 289 insertions(+) - create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c - -diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi -index 0d47427..3bed0a6 100644 ---- a/arch/arm/boot/dts/bcm2708.dtsi -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -15,5 +15,11 @@ - arm-pmu { - compatible = "arm,arm1176-pmu"; - }; -+ -+ gpiomem { -+ compatible = "brcm,bcm2835-gpiomem"; -+ reg = <0x7e200000 0x1000>; -+ status = "okay"; -+ }; - }; - }; -diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi -index 5e0b935..811d825 100644 ---- a/arch/arm/boot/dts/bcm2709.dtsi -+++ b/arch/arm/boot/dts/bcm2709.dtsi -@@ -16,6 +16,12 @@ - compatible = "arm,cortex-a7-pmu"; - interrupts = <3 9>; - }; -+ -+ gpiomem { -+ compatible = "brcm,bcm2835-gpiomem"; -+ reg = <0x7e200000 0x1000>; -+ status = "okay"; -+ }; - }; - - timer { -diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig -index fc40846..bc2eb1e 100644 ---- a/drivers/char/broadcom/Kconfig -+++ b/drivers/char/broadcom/Kconfig -@@ -38,3 +38,12 @@ config BCM_VC_SM - help - Support for the VC shared memory on the Broadcom reference - design. Uses the VCHIQ stack. -+ -+config BCM2835_DEVGPIOMEM -+ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835" -+ default m -+ help -+ Provides users with root-free access to the GPIO registers -+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO -+ register page to the user's pointer. -+ -diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile -index 18171e2..664e2c4 100644 ---- a/drivers/char/broadcom/Makefile -+++ b/drivers/char/broadcom/Makefile -@@ -2,3 +2,6 @@ obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ - obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o - obj-$(CONFIG_BCM_VCIO) += vcio.o - obj-$(CONFIG_BCM_VC_SM) += vc_sm/ -+ -+obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o -+ -diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c -new file mode 100644 -index 0000000..0085e13 ---- /dev/null -+++ b/drivers/char/broadcom/bcm2835-gpiomem.c -@@ -0,0 +1,265 @@ -+/** -+ * GPIO memory device driver -+ * -+ * Creates a chardev /dev/gpiomem which will provide user access to -+ * the BCM2835's GPIO registers when it is mmap()'d. -+ * No longer need root for user GPIO access, but without relaxing permissions -+ * on /dev/mem. -+ * -+ * Written by Luke Wren -+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2, as published by the Free -+ * Software Foundation. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVICE_NAME "bcm2835-gpiomem" -+#define DRIVER_NAME "gpiomem-bcm2835" -+#define DEVICE_MINOR 0 -+ -+struct bcm2835_gpiomem_instance { -+ unsigned long gpio_regs_phys; -+ struct device *dev; -+}; -+ -+static struct cdev bcm2835_gpiomem_cdev; -+static dev_t bcm2835_gpiomem_devid; -+static struct class *bcm2835_gpiomem_class; -+static struct device *bcm2835_gpiomem_dev; -+static struct bcm2835_gpiomem_instance *inst; -+ -+ -+/**************************************************************************** -+* -+* GPIO mem chardev file ops -+* -+***************************************************************************/ -+ -+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; -+ } -+ return ret; -+} -+ -+static int bcm2835_gpiomem_release(struct inode *inode, struct file *file) -+{ -+ int dev = iminor(inode); -+ int ret = 0; -+ -+ if (dev != DEVICE_MINOR) { -+ dev_err(inst->dev, "Unknown minor device %d", dev); -+ ret = -ENXIO; -+ } -+ return ret; -+} -+ -+static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = { -+#ifdef CONFIG_HAVE_IOREMAP_PROT -+ .access = generic_access_phys -+#endif -+}; -+ -+static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ /* Ignore what the user says - they're getting the GPIO regs -+ whether they like it or not! */ -+ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT; -+ -+ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page, -+ PAGE_SIZE, -+ vma->vm_page_prot); -+ vma->vm_ops = &bcm2835_gpiomem_vm_ops; -+ if (remap_pfn_range(vma, vma->vm_start, -+ gpio_page, -+ PAGE_SIZE, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+static const struct file_operations -+bcm2835_gpiomem_fops = { -+ .owner = THIS_MODULE, -+ .open = bcm2835_gpiomem_open, -+ .release = bcm2835_gpiomem_release, -+ .mmap = bcm2835_gpiomem_mmap, -+}; -+ -+ -+ /**************************************************************************** -+* -+* Probe and remove functions -+* -+***************************************************************************/ -+ -+ -+static int bcm2835_gpiomem_probe(struct platform_device *pdev) -+{ -+ int err; -+ void *ptr_err; -+ struct device *dev = &pdev->dev; -+ struct device_node *node = dev->of_node; -+ struct resource *ioresource; -+ -+ /* Allocate buffers and instance data */ -+ -+ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL); -+ -+ if (!inst) { -+ err = -ENOMEM; -+ goto failed_inst_alloc; -+ } -+ -+ inst->dev = dev; -+ -+ /* Create character device entries */ -+ -+ err = alloc_chrdev_region(&bcm2835_gpiomem_devid, -+ DEVICE_MINOR, 1, DEVICE_NAME); -+ if (err != 0) { -+ dev_err(inst->dev, "unable to allocate device number"); -+ goto failed_alloc_chrdev; -+ } -+ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops); -+ bcm2835_gpiomem_cdev.owner = THIS_MODULE; -+ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1); -+ if (err != 0) { -+ dev_err(inst->dev, "unable to register device"); -+ goto failed_cdev_add; -+ } -+ -+ /* Create sysfs entries */ -+ -+ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); -+ ptr_err = bcm2835_gpiomem_class; -+ if (IS_ERR(ptr_err)) -+ goto failed_class_create; -+ -+ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL, -+ bcm2835_gpiomem_devid, NULL, -+ "gpiomem"); -+ ptr_err = bcm2835_gpiomem_dev; -+ if (IS_ERR(ptr_err)) -+ goto failed_device_create; -+ -+ /* Get address from device tree if available (*_resource() correctly -+ converts the bus address in device tree to a physical address), -+ or use hardcoded offset + BCM2708_PERI_BASE if not. -+ (In spite of its name 2708 actually seems to have the correct -+ mach-dependent value on 2709 etc, as it is defined in -+ mach-bcm270x/platform.h) */ -+ -+ if (node) { -+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ inst->gpio_regs_phys = ioresource->start; -+ } else { -+ inst->gpio_regs_phys = GPIO_BASE; -+ } -+ -+ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", -+ inst->gpio_regs_phys); -+ -+ return 0; -+ -+failed_device_create: -+ class_destroy(bcm2835_gpiomem_class); -+failed_class_create: -+ cdev_del(&bcm2835_gpiomem_cdev); -+ err = PTR_ERR(ptr_err); -+failed_cdev_add: -+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); -+failed_alloc_chrdev: -+ kfree(inst); -+failed_inst_alloc: -+ dev_err(inst->dev, "could not load bcm2835_gpiomem"); -+ return err; -+} -+ -+static int bcm2835_gpiomem_remove(struct platform_device *pdev) -+{ -+ struct device *dev = inst->dev; -+ -+ kfree(inst); -+ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid); -+ class_destroy(bcm2835_gpiomem_class); -+ cdev_del(&bcm2835_gpiomem_cdev); -+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1); -+ -+ dev_info(dev, "GPIO mem driver removed - OK"); -+ return 0; -+} -+ -+ /**************************************************************************** -+* -+* Register the driver with device tree -+* -+***************************************************************************/ -+ -+static const struct of_device_id bcm2835_gpiomem_of_match[] = { -+ {.compatible = "brcm,bcm2835-gpiomem",}, -+ { /* sentinel */ }, -+}; -+ -+MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match); -+ -+static struct platform_driver bcm2835_gpiomem_driver = { -+ .probe = bcm2835_gpiomem_probe, -+ .remove = bcm2835_gpiomem_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = bcm2835_gpiomem_of_match, -+ }, -+}; -+ -+module_platform_driver(bcm2835_gpiomem_driver); -+ -+MODULE_ALIAS("platform:gpiomem-bcm2835"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); -+MODULE_AUTHOR("Luke Wren "); - -From 4e9cf1447a7ef0f8f46c6a8170f44c78c1690a96 Mon Sep 17 00:00:00 2001 -From: Jan Grulich -Date: Mon, 24 Aug 2015 16:02:34 +0100 -Subject: [PATCH 169/204] tpa6130a2: Add headphone switch control - -Signed-off-by: Jan Grulich ---- - sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++--- - 1 file changed, 26 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c -index 6fac9e0..f60ebe1c 100644 ---- a/sound/soc/codecs/tpa6130a2.c -+++ b/sound/soc/codecs/tpa6130a2.c -@@ -4,6 +4,7 @@ - * Copyright (C) Nokia Corporation - * - * Author: Peter Ujfalusi -+ * Modified: Jan Grulich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License -@@ -52,6 +53,8 @@ struct tpa6130a2_data { - enum tpa_model id; - }; - -+static void tpa6130a2_channel_enable(u8 channel, int enable); -+ - static int tpa6130a2_i2c_read(int reg) - { - struct tpa6130a2_data *data; -@@ -189,7 +192,7 @@ static int tpa6130a2_power(u8 power) - } - - static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; -@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, - } - - static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; -@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, - return 1; - } - -+static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ int enable = ucontrol->value.integer.value[0]; -+ unsigned int state; -+ -+ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0; -+ if (state == enable) -+ return 0; /* No change */ -+ -+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable); -+ return 1; /* Changed */ -+} -+ - /* -- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going -+ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going - * down in gain. - */ - static const unsigned int tpa6130_tlv[] = { -@@ -278,6 +295,9 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { - TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, - tpa6130a2_get_volsw, tpa6130a2_put_volsw, - tpa6130_tlv), -+ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch", -+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, -+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), - }; - - static const unsigned int tpa6140_tlv[] = { -@@ -292,6 +312,9 @@ static const struct snd_kcontrol_new tpa6140a2_controls[] = { - TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, - tpa6130a2_get_volsw, tpa6130a2_put_volsw, - tpa6140_tlv), -+ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch", -+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1, -+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw), - }; - - /* - -From bdad59048f5910ea3c4439ba40a4a14ca8f1be90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sat, 11 Jul 2015 18:48:10 +0200 -Subject: [PATCH 170/204] staging: fbtft: Add reset to fbtft_init_display_dt() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When an init sequence is present in the Device Tree, -fbtft_init_display_dt() is used to initialize the display. -Add missing reset function call and activation of -chip select for parallel bus. - -Signed-off-by: Noralf Trønnes ---- - drivers/staging/fbtft/fbtft-core.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c -index 53b748b..4f165d3 100644 ---- a/drivers/staging/fbtft/fbtft-core.c -+++ b/drivers/staging/fbtft/fbtft-core.c -@@ -1074,6 +1074,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) - p = of_prop_next_u32(prop, NULL, &val); - if (!p) - return -EINVAL; -+ -+ par->fbtftops.reset(par); -+ if (par->gpio.cs != -1) -+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ -+ - while (p) { - if (val & FBTFT_OF_INIT_CMD) { - val &= 0xFFFF; - -From 928b8dbc73acdb75d3f03ef7d5cf9fc639e0280c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 19 Jul 2015 18:57:06 +0200 -Subject: [PATCH 171/204] BCM270X_DT: mz61581: Revert to spi-bcm2708 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The MZ61581 display does not work with spi-bcm2835 and software -chip select. It works before the commit: -spi: bcm2835: transform native-cs to gpio-cs on first spi_setup - -Revert to spi-bcm2708 until the cause has been detected and the -issue resolved. - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index c06fe12..f674a66 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -12,6 +12,8 @@ - fragment@0 { - target = <&spi0>; - __overlay__ { -+ /* does not work with spi-bcm2835 using software chip selects */ -+ compatible = "brcm,bcm2708-spi"; - status = "okay"; - - spidev@0{ - -From 707866acc48470ec677f1fb6befdfd928d9994f1 Mon Sep 17 00:00:00 2001 +From 7fd1e80b9a338c1f5edf22f0503f8da4a7f8a73a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Sep 2015 16:52:34 +0000 -Subject: [PATCH 172/204] vchiq: fix NULL pointer dereference when closing +Subject: [PATCH 174/278] vchiq: fix NULL pointer dereference when closing driver The following code run as root will cause a null pointer dereference oops: @@ -146528,10 +146591,10 @@ index f4d0b66..4055d4b 100644 struct semaphore pop; struct semaphore push; -From 2c90639076be957e3e5eb9f44e0c09719db83f7e Mon Sep 17 00:00:00 2001 +From 073fe0debc4a1183a086f9c2b4823621fba8e859 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:13:17 -0400 -Subject: [PATCH 173/204] bcm2708_fb: remove redundant code as detected by +Subject: [PATCH 175/278] bcm2708_fb: remove redundant code as detected by static analysis static analysis with cppcheck detected some redundant code which @@ -146563,10 +146626,10 @@ index 06a96d16..fed0672 100644 } -From 473b4d43abe530f11f07dbdd9be666a90d75313c Mon Sep 17 00:00:00 2001 +From 875cf2e54234b4391d8a77fcb6fe7a44249291aa Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:15:38 -0400 -Subject: [PATCH 174/204] bcm2708_fb: remove unnecessary initialization of +Subject: [PATCH 176/278] bcm2708_fb: remove unnecessary initialization of result static analysis by cppcheck detected an unnecessary initialization @@ -146595,10 +146658,10 @@ index fed0672..0f62d76 100644 info->var.yoffset = var->yoffset; result = bcm2708_fb_set_par(info); -From 94946643df81ee3acaeed9a5e0eb8944ab8492fe Mon Sep 17 00:00:00 2001 +From 09ecd711af91b371e688a828c603662dddcdca35 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:27:36 -0400 -Subject: [PATCH 175/204] vcsm: increment res_stats MAP_FAIL stats before we +Subject: [PATCH 177/278] vcsm: increment res_stats MAP_FAIL stats before we potentially release the resource resource can be kfree'd when the reference count is zero, so we should @@ -146632,10 +146695,10 @@ index 0bfb42e..b62a3b2 100644 } -From 874c6177f126c4fdb31ed9234fe053581ff632fb Mon Sep 17 00:00:00 2001 +From dfdab3848edea54a4e1a3fbb7aece9305954b347 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:33:39 -0400 -Subject: [PATCH 176/204] bcm2835: camera: check for scene not being found +Subject: [PATCH 178/278] bcm2835: camera: check for scene not being found static analysis by cppcheck detected some potential NULL pointer dereference issues: @@ -146666,10 +146729,10 @@ index 3017b94..f9f903f 100644 return -EINVAL; -From a255eb898f2ff3d63de6dbc201797ff732499dca Mon Sep 17 00:00:00 2001 +From f912909c363f4670fb0a861096668fac03e80bd9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Sep 2015 07:47:51 -0400 -Subject: [PATCH 177/204] bcm2835: memcpy port data to m rather than rmsg +Subject: [PATCH 179/278] bcm2835: memcpy port data to m rather than rmsg static analysis by cppcheck detected a memcpy to rmsg which is not actually initialized at that point. The memcpy should be copying @@ -146681,7 +146744,7 @@ Signed-off-by: Colin Ian King 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/bcm2835/mmal-vchiq.c b/drivers/media/platform/bcm2835/mmal-vchiq.c -index 76f249e..7813225 100644 +index 76f249e..78132254 100644 --- a/drivers/media/platform/bcm2835/mmal-vchiq.c +++ b/drivers/media/platform/bcm2835/mmal-vchiq.c @@ -851,7 +851,7 @@ static int port_info_set(struct vchiq_mmal_instance *instance, @@ -146694,119 +146757,10 @@ index 76f249e..7813225 100644 ret = send_synchronous_mmal_msg(instance, &m, -From bd4d78dcb66955bc2ea1c81232db499e1f662ac6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 13 Sep 2015 15:54:28 +0200 -Subject: [PATCH 178/204] Revert "BCM270X_DT: mz61581: Revert to spi-bcm2708" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit 1820cd05d93b2d465d1616202772efe5bf0d11fe. - -The spi-bcm2835 driver has been fixed, so now we can use it again. - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index f674a66..c06fe12 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -12,8 +12,6 @@ - fragment@0 { - target = <&spi0>; - __overlay__ { -- /* does not work with spi-bcm2835 using software chip selects */ -- compatible = "brcm,bcm2708-spi"; - status = "okay"; - - spidev@0{ - -From 63103cf8b12f79c02f1a6d7a851fbb6727528d33 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sun, 13 Sep 2015 17:17:14 +0200 -Subject: [PATCH 179/204] BCM270X_DT: mz61581: Set txbuflen to 32k -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Because of the spi dma mapping/engine overhead with spi-bcm2835, -txbuflen has to be increased from 4096 to 32768 to maximize -throughput (11MB/s at 128MHz). - -Signed-off-by: Noralf Trønnes ---- - arch/arm/boot/dts/overlays/README | 2 ++ - arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index a749ff7..0aa5aa1 100644 ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -368,6 +368,8 @@ Params: speed Display SPI bus speed - - fps Delay between frame updates - -+ txbuflen Transmit buffer length (default 32768) -+ - debug Debug output level {0-7} - - xohms Touchpanel sensitivity (X-plate resistance) -diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -index c06fe12..9242a6e 100644 ---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts -@@ -57,6 +57,7 @@ - bgr; - fps = <30>; - buswidth = <8>; -+ txbuflen = <32768>; - - reset-gpios = <&gpio 15 0>; - dc-gpios = <&gpio 25 0>; -@@ -103,6 +104,7 @@ - speed = <&mz61581>, "spi-max-frequency:0"; - rotate = <&mz61581>, "rotate:0"; - fps = <&mz61581>, "fps:0"; -+ txbuflen = <&mz61581>, "txbuflen:0"; - debug = <&mz61581>, "debug:0"; - xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; - }; - -From 6881996989b77354049455c95e8af67f278cfa48 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 11 Sep 2015 12:10:15 +0100 -Subject: [PATCH 180/204] bcm2835-mmc: Don't overwrite MMC capabilities from DT - ---- - drivers/mmc/host/bcm2835-mmc.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c -index b7c4883..164bfad 100644 ---- a/drivers/mmc/host/bcm2835-mmc.c -+++ b/drivers/mmc/host/bcm2835-mmc.c -@@ -1327,8 +1327,9 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) - mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; - #endif - /* host controller capabilities */ -- mmc->caps = MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | -- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; -+ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | -+ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | -+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; - - host->flags = SDHCI_AUTO_CMD23; - - -From 7bbc4815e21230a8a011d3f3cf794d765cdacb35 Mon Sep 17 00:00:00 2001 +From 9d4b7e347d5242312445767678dd179d77e14880 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 11 Sep 2015 09:14:01 +0100 -Subject: [PATCH 181/204] BCM270X_DT: Use fixed-factor-clock for uart1 +Subject: [PATCH 180/278] BCM270X_DT: Use fixed-factor-clock for uart1 The BCM2835 mini-UART is almost 8250-compatible, but there is a factor-of-two difference in the clock divider for the baud rate. @@ -146906,10 +146860,681 @@ index f25f0a2..76d44a2 100644 spi = <&spi0>,"status"; i2c0 = <&i2c0>,"status"; -From d851a069d33dba42c5c7fa023ee13f994643fa90 Mon Sep 17 00:00:00 2001 +From 877e636ac93e659f949d389bfad63db1fdfb29dd Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 11 Sep 2015 12:10:15 +0100 +Subject: [PATCH 181/278] bcm2835-mmc: Don't overwrite MMC capabilities from DT + +--- + drivers/mmc/host/bcm2835-mmc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index b7c4883..164bfad 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1327,8 +1327,9 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; + #endif + /* host controller capabilities */ +- mmc->caps = MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | +- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; ++ mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | ++ MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | ++ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; + + host->flags = SDHCI_AUTO_CMD23; + + +From a2c55d70c3c1b45ed04c5e1f6672794774380486 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 13 Sep 2015 15:54:28 +0200 +Subject: [PATCH 182/278] Revert "BCM270X_DT: mz61581: Revert to spi-bcm2708" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 1820cd05d93b2d465d1616202772efe5bf0d11fe. + +The spi-bcm2835 driver has been fixed, so now we can use it again. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index f674a66..c06fe12 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -12,8 +12,6 @@ + fragment@0 { + target = <&spi0>; + __overlay__ { +- /* does not work with spi-bcm2835 using software chip selects */ +- compatible = "brcm,bcm2708-spi"; + status = "okay"; + + spidev@0{ + +From ab97368a3d04c1871395370c1f78fc1e26451302 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sun, 13 Sep 2015 17:17:14 +0200 +Subject: [PATCH 183/278] BCM270X_DT: mz61581: Set txbuflen to 32k +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because of the spi dma mapping/engine overhead with spi-bcm2835, +txbuflen has to be increased from 4096 to 32768 to maximize +throughput (11MB/s at 128MHz). + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index a749ff7..0aa5aa1 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -368,6 +368,8 @@ Params: speed Display SPI bus speed + + fps Delay between frame updates + ++ txbuflen Transmit buffer length (default 32768) ++ + debug Debug output level {0-7} + + xohms Touchpanel sensitivity (X-plate resistance) +diff --git a/arch/arm/boot/dts/overlays/mz61581-overlay.dts b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +index c06fe12..9242a6e 100644 +--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts +@@ -57,6 +57,7 @@ + bgr; + fps = <30>; + buswidth = <8>; ++ txbuflen = <32768>; + + reset-gpios = <&gpio 15 0>; + dc-gpios = <&gpio 25 0>; +@@ -103,6 +104,7 @@ + speed = <&mz61581>, "spi-max-frequency:0"; + rotate = <&mz61581>, "rotate:0"; + fps = <&mz61581>, "fps:0"; ++ txbuflen = <&mz61581>, "txbuflen:0"; + debug = <&mz61581>, "debug:0"; + xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; + }; + +From 6843570d2962f631cd6fad34634f7a3988e6fd78 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Thu, 10 Sep 2015 09:32:14 +0000 +Subject: [PATCH 184/278] backport: spi: bcm2835: BUG: fix wrong use of + PAGE_MASK + +There is a bug in the alignment checking of transfers, +that results in DMA not being used for un-aligned +transfers that do not cross page-boundries, which is valid. + +This is due to a missconception of the meaning PAGE_MASK +when implementing that check originally - (PAGE_SIZE - 1) +should have been used instead. + +Also fixes a copy/paste error. + +Reported-by: +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +Cc: stable@vger.kernel.org +--- + drivers/spi/spi-bcm2835.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c +index b68991c..3835332 100644 +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -386,14 +386,14 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, + /* otherwise we only allow transfers within the same page + * to avoid wasting time on dma_mapping when it is not practical + */ +- if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { ++ if (((size_t)tfr->tx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, + "Unaligned spi tx-transfer bridging page\n"); + return false; + } +- if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { ++ if (((size_t)tfr->rx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, +- "Unaligned spi tx-transfer bridging page\n"); ++ "Unaligned spi rx-transfer bridging page\n"); + return false; + } + + +From b27fa0514e45ed920a49817f453a990b1a913c5e Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:46 +0200 +Subject: [PATCH 185/278] mt7601u: fix dma from stack address + +DMA to variables located on the stack is a bad idea. +For simplicity and to avoid frequent allocations create +a buffer inside the device structure. Protect this +buffer with vendor_req_mutex. Don't protect vendor +requests which don't use this buffer. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +- + drivers/net/wireless/mediatek/mt7601u/usb.c | 63 ++++++++++++------------- + drivers/net/wireless/mediatek/mt7601u/usb.h | 2 + + 3 files changed, 34 insertions(+), 35 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index 9102be6b..6bdfc11 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -146,7 +146,7 @@ enum { + * @rx_lock: protects @rx_q. + * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. + * @mutex: ensures exclusive access from mac80211 callbacks. +- * @vendor_req_mutex: ensures atomicity of vendor requests. ++ * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. + * @reg_atomic_mutex: ensures atomicity of indirect register accesses + * (accesses to RF and BBP). + * @hw_atomic_mutex: ensures exclusive access to HW during critical +@@ -184,6 +184,8 @@ struct mt7601u_dev { + struct mt7601u_eeprom_params *ee; + + struct mutex vendor_req_mutex; ++ void *vend_buf; ++ + struct mutex reg_atomic_mutex; + struct mutex hw_atomic_mutex; + +diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c +index 54dba40..416c604 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/usb.c ++++ b/drivers/net/wireless/mediatek/mt7601u/usb.c +@@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb) + complete(cmpl); + } + +-static int +-__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, +- const u8 direction, const u16 val, const u16 offset, +- void *buf, const size_t buflen) ++int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, ++ const u8 direction, const u16 val, const u16 offset, ++ void *buf, const size_t buflen) + { + int i, ret; + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); +@@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + trace_mt_vend_req(dev, pipe, req, req_type, val, offset, + buf, buflen, ret); + ++ if (ret == -ENODEV) ++ set_bit(MT7601U_STATE_REMOVED, &dev->state); + if (ret >= 0 || ret == -ENODEV) + return ret; + +@@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + return ret; + } + +-int +-mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, +- const u8 direction, const u16 val, const u16 offset, +- void *buf, const size_t buflen) +-{ +- int ret; +- +- mutex_lock(&dev->vendor_req_mutex); +- +- ret = __mt7601u_vendor_request(dev, req, direction, val, offset, +- buf, buflen); +- if (ret == -ENODEV) +- set_bit(MT7601U_STATE_REMOVED, &dev->state); +- +- mutex_unlock(&dev->vendor_req_mutex); +- +- return ret; +-} +- + void mt7601u_vendor_reset(struct mt7601u_dev *dev) + { + mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, +@@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) + u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) + { + int ret; +- __le32 reg; +- u32 val; ++ u32 val = ~0; + + WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); + ++ mutex_lock(&dev->vendor_req_mutex); ++ + ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, +- 0, offset, ®, sizeof(reg)); +- val = le32_to_cpu(reg); +- if (ret > 0 && ret != sizeof(reg)) { ++ 0, offset, dev->vend_buf, MT_VEND_BUF); ++ if (ret == MT_VEND_BUF) ++ val = get_unaligned_le32(dev->vend_buf); ++ else if (ret > 0) + dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", + ret, offset); +- val = ~0; +- } ++ ++ mutex_unlock(&dev->vendor_req_mutex); + + trace_reg_read(dev, offset, val); + return val; +@@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + { + int ret; + ++ mutex_lock(&dev->vendor_req_mutex); ++ + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val & 0xffff, offset, NULL, 0); +- if (ret) +- return ret; +- return mt7601u_vendor_request(dev, req, USB_DIR_OUT, +- val >> 16, offset + 2, NULL, 0); ++ if (!ret) ++ ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, ++ val >> 16, offset + 2, NULL, 0); ++ ++ mutex_unlock(&dev->vendor_req_mutex); ++ ++ return ret; + } + + void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) +@@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf, + + usb_set_intfdata(usb_intf, dev); + ++ dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); ++ if (!dev->vend_buf) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ + ret = mt7601u_assign_pipes(usb_intf, dev); + if (ret) + goto err; +diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h +index 49e188f..bc18202 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/usb.h ++++ b/drivers/net/wireless/mediatek/mt7601u/usb.h +@@ -23,6 +23,8 @@ + + #define MT_VEND_DEV_MODE_RESET 1 + ++#define MT_VEND_BUF sizeof(__le32) ++ + enum mt_vendor_req { + MT_VEND_DEV_MODE = 1, + MT_VEND_WRITE = 2, + +From 7365b42453cef6277126ea65cbd7bbff2e221a8c Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:47 +0200 +Subject: [PATCH 186/278] mt7601u: use correct ieee80211_rx variant + +Rx is run inside a tasklet so ieee80211_rx() should be used +instead of ieee80211_rx_ni(). + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index 7217da4..fb183e3 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -112,7 +112,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, + if (!skb) + return; + +- ieee80211_rx_ni(dev->hw, skb); ++ ieee80211_rx(dev->hw, skb); + } + + static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) + +From 940d45dc308372ea75c867542a1ed1195d185612 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:48 +0200 +Subject: [PATCH 187/278] mt7601u: fix tx status reporting contexts + +mac80211 requires that rx path does not run concurrently with +tx status reporting. Since rx path is run in driver tasklet, +tx status cannot be reported directly from interrupt context +(there would be no way to lock it out). + +Add tasklet for tx and move all possible code from irq handler +there. + +Note: tx tasklet is needed because workqueue is queued very + rarely and that kills TCP performance. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 30 +++++++++++++++++++++---- + drivers/net/wireless/mediatek/mt7601u/init.c | 1 + + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++++ + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 2 ++ + 4 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index fb183e3..63c4854 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -236,23 +236,42 @@ static void mt7601u_complete_tx(struct urb *urb) + skb = q->e[q->start].skb; + trace_mt_tx_dma_done(dev, skb); + +- mt7601u_tx_status(dev, skb); ++ __skb_queue_tail(&dev->tx_skb_done, skb); ++ tasklet_schedule(&dev->tx_tasklet); + + if (q->used == q->entries - q->entries / 8) + ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); + + q->start = (q->start + 1) % q->entries; + q->used--; ++out: ++ spin_unlock_irqrestore(&dev->tx_lock, flags); ++} + +- if (urb->status) +- goto out; ++static void mt7601u_tx_tasklet(unsigned long data) ++{ ++ struct mt7601u_dev *dev = (struct mt7601u_dev *) data; ++ struct sk_buff_head skbs; ++ unsigned long flags; ++ ++ __skb_queue_head_init(&skbs); ++ ++ spin_lock_irqsave(&dev->tx_lock, flags); + + set_bit(MT7601U_STATE_MORE_STATS, &dev->state); + if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) + queue_delayed_work(dev->stat_wq, &dev->stat_work, + msecs_to_jiffies(10)); +-out: ++ ++ skb_queue_splice_init(&dev->tx_skb_done, &skbs); ++ + spin_unlock_irqrestore(&dev->tx_lock, flags); ++ ++ while (!skb_queue_empty(&skbs)) { ++ struct sk_buff *skb = __skb_dequeue(&skbs); ++ ++ mt7601u_tx_status(dev, skb); ++ } + } + + static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, +@@ -475,6 +494,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev) + { + int ret = -ENOMEM; + ++ tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); + tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); + + ret = mt7601u_alloc_tx(dev); +@@ -502,4 +522,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev) + + mt7601u_free_rx(dev); + mt7601u_free_tx(dev); ++ ++ tasklet_kill(&dev->tx_tasklet); + } +diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c +index 45eb079..8f5417e 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/init.c ++++ b/drivers/net/wireless/mediatek/mt7601u/init.c +@@ -456,6 +456,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) + spin_lock_init(&dev->lock); + spin_lock_init(&dev->con_mon_lock); + atomic_set(&dev->avg_ampdu_len, 1); ++ skb_queue_head_init(&dev->tx_skb_done); + + dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); + if (!dev->stat_wq) { +diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c +index 7514bce..e3928cf 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mac.c ++++ b/drivers/net/wireless/mediatek/mt7601u/mac.c +@@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) + } + + mt76_mac_fill_tx_status(dev, &info, stat); ++ ++ local_bh_disable(); + ieee80211_tx_status_noskb(dev->hw, sta, &info); ++ local_bh_enable(); ++ + rcu_read_unlock(); + } + +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index 6bdfc11..bc5e294 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -199,7 +199,9 @@ struct mt7601u_dev { + + /* TX */ + spinlock_t tx_lock; ++ struct tasklet_struct tx_tasklet; + struct mt7601u_tx_queue *tx_q; ++ struct sk_buff_head tx_skb_done; + + atomic_t avg_ampdu_len; + + +From 39ca7c97e0f31402be28d1ea543714f5e1901613 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Fri, 31 Jul 2015 15:04:49 +0200 +Subject: [PATCH 188/278] mt7601u: lock out rx path and tx status reporting + +mac80211 requires that rx path does not run concurrently with +tx status reporting. Add a spinlock which will ensure that. + +Signed-off-by: Jakub Kicinski +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/mediatek/mt7601u/dma.c | 2 ++ + drivers/net/wireless/mediatek/mt7601u/init.c | 1 + + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++-- + drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +++- + drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +++ + 5 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c +index 63c4854..57a80cf 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/dma.c ++++ b/drivers/net/wireless/mediatek/mt7601u/dma.c +@@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, + if (!skb) + return; + ++ spin_lock(&dev->mac_lock); + ieee80211_rx(dev->hw, skb); ++ spin_unlock(&dev->mac_lock); + } + + static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) +diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c +index 8f5417e..c60eb7d 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/init.c ++++ b/drivers/net/wireless/mediatek/mt7601u/init.c +@@ -454,6 +454,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) + spin_lock_init(&dev->tx_lock); + spin_lock_init(&dev->rx_lock); + spin_lock_init(&dev->lock); ++ spin_lock_init(&dev->mac_lock); + spin_lock_init(&dev->con_mon_lock); + atomic_set(&dev->avg_ampdu_len, 1); + skb_queue_head_init(&dev->tx_skb_done); +diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c +index e3928cf..e21c53e 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mac.c ++++ b/drivers/net/wireless/mediatek/mt7601u/mac.c +@@ -182,9 +182,9 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) + + mt76_mac_fill_tx_status(dev, &info, stat); + +- local_bh_disable(); ++ spin_lock_bh(&dev->mac_lock); + ieee80211_tx_status_noskb(dev->hw, sta, &info); +- local_bh_enable(); ++ spin_unlock_bh(&dev->mac_lock); + + rcu_read_unlock(); + } +diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +index bc5e294..428bd2f 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h ++++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +@@ -141,8 +141,9 @@ enum { + /** + * struct mt7601u_dev - adapter structure + * @lock: protects @wcid->tx_rate. ++ * @mac_lock: locks out mac80211's tx status and rx paths. + * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS +- flags in @state. ++ * flags in @state. + * @rx_lock: protects @rx_q. + * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. + * @mutex: ensures exclusive access from mac80211 callbacks. +@@ -177,6 +178,7 @@ struct mt7601u_dev { + struct mt76_wcid __rcu *wcid[N_WCIDS]; + + spinlock_t lock; ++ spinlock_t mac_lock; + + const u16 *beacon_offsets; + +diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c +index 0be2080..a0a33dc 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/tx.c ++++ b/drivers/net/wireless/mediatek/mt7601u/tx.c +@@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; ++ ++ spin_lock(&dev->mac_lock); + ieee80211_tx_status(dev->hw, skb); ++ spin_unlock(&dev->mac_lock); + } + + static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) + +From 2a4c4dc8aaf0bfdfbbaceedaae7aa6a227f73b21 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 15 Sep 2015 15:16:24 +0100 +Subject: [PATCH 189/278] config: Add CIFS_DFS_UPCALL, CIFS_ACL, CIFS_SMB2, + CIFS_FSCACHE + +--- + arch/arm/configs/bcm2709_defconfig | 4 ++++ + arch/arm/configs/bcmrpi_defconfig | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 16a8354..db55b51 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1160,6 +1160,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y + CONFIG_CIFS_UPCALL=y + CONFIG_CIFS_XATTR=y + CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_ACL=y ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_SMB2=y ++CONFIG_CIFS_FSCACHE=y + CONFIG_9P_FS=m + CONFIG_9P_FS_POSIX_ACL=y + CONFIG_NLS_DEFAULT="utf8" +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 7dd4fd4..d474418 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1153,6 +1153,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y + CONFIG_CIFS_UPCALL=y + CONFIG_CIFS_XATTR=y + CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_ACL=y ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_SMB2=y ++CONFIG_CIFS_FSCACHE=y + CONFIG_9P_FS=m + CONFIG_9P_FS_POSIX_ACL=y + CONFIG_NLS_DEFAULT="utf8" + +From 3582f4a5b986d55fb9782b030c7daa0ae8fd4df6 Mon Sep 17 00:00:00 2001 +From: David Lechner +Date: Mon, 14 Sep 2015 19:08:36 -0500 +Subject: [PATCH 190/278] Use dts-dirs feature for overlays. + +The kernel makefiles have a dts-dirs target that is for vendor subdirectories. + +Using this fixes the install_dtbs target, which previously did not install the overlays. +--- + arch/arm/boot/dts/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 12de305..faf293f 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -15,6 +15,9 @@ endif + ifeq ($(CONFIG_ARCH_BCM2835),y) + RPI_DT_OVERLAYS=y + endif ++ifeq ($(RPI_DT_OVERLAYS),y) ++ dts-dirs += overlays ++endif + + dtb-$(CONFIG_ARCH_ALPINE) += \ + alpine-db.dtb +@@ -683,11 +686,10 @@ targets += $(dtb-y) + endif + + always := $(dtb-y) ++subdir-y := $(dts-dirs) + clean-files := *.dtb + + # Enable fixups to support overlays on BCM2708 platforms + ifeq ($(RPI_DT_OVERLAYS),y) + DTC_FLAGS ?= -@ + endif +- +-subdir-y += overlays + +From 47e7b64a15a3bacae29eb7a4c600387c0d9c0995 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 182/204] Add SMI driver +Subject: [PATCH 191/278] Add SMI driver Signed-off-by: Luke Wren --- @@ -148968,10 +149593,10 @@ index 0000000..ee3a75e + +#endif /* BCM2835_SMI_H */ -From f657d984e244c7348152e2edc09cd5decb2f5b55 Mon Sep 17 00:00:00 2001 +From da1b5e6b5a2e0e997e997f628a40393079a1b16f Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 183/204] Add SMI NAND driver +Subject: [PATCH 192/278] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -149125,7 +149750,7 @@ index 0000000..13ce0b7 + }; +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 16a8354..c7671bf 100644 +index db55b51..60f8357 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -392,6 +392,10 @@ CONFIG_DEVTMPFS=y @@ -149150,7 +149775,7 @@ index 16a8354..c7671bf 100644 CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 7dd4fd4..75fa1d0 100644 +index d474418..8ebc8d5 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -385,6 +385,10 @@ CONFIG_DEVTMPFS=y @@ -149479,10 +150104,10 @@ index 0000000..b747326 + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From a3bf36473505511198d71fdf19e6b28b4ee55195 Mon Sep 17 00:00:00 2001 +From dfc75f99bdfb59fb968abc53f70ac3b74c2f6b43 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 16 Sep 2015 17:28:41 +0100 -Subject: [PATCH 184/204] BCM270X_DT: Document SMI overlay +Subject: [PATCH 193/278] BCM270X_DT: Document SMI overlay --- arch/arm/boot/dts/overlays/Makefile | 6 +++--- @@ -149543,10 +150168,10 @@ index 0aa5aa1..4ab4c695 100644 Info: Selects the bcm2708-spi SPI driver Load: dtoverlay=spi-bcm2708 -From 24a9683edd38171e27a170b95a42133c2bd3890f Mon Sep 17 00:00:00 2001 +From a79e0fbb9e48eec364aa3e1803c9f56513ee546e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 17 Sep 2015 17:13:42 +0100 -Subject: [PATCH 185/204] dwc_otg: Force host mode to fix incorrect compute +Subject: [PATCH 194/278] dwc_otg: Force host mode to fix incorrect compute module boards --- @@ -149567,139 +150192,45 @@ index e40060f..beaa8b3 100644 dwc_mdelay(100); } -From 4f8563760264a9aedad6fec09e8adb8c3929c1a3 Mon Sep 17 00:00:00 2001 +From a31d2a648467bc5c8c7ef3e5cba9d7357ccffc2e Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Tue, 15 Sep 2015 15:16:24 +0100 -Subject: [PATCH 186/204] config: Add CIFS_DFS_UPCALL, CIFS_ACL, CIFS_SMB2, - CIFS_FSCACHE +Date: Thu, 1 Oct 2015 11:49:11 +0100 +Subject: [PATCH 195/278] config: Add CONFIG_UHID --- - arch/arm/configs/bcm2709_defconfig | 4 ++++ - arch/arm/configs/bcmrpi_defconfig | 4 ++++ - 2 files changed, 8 insertions(+) + 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 c7671bf..60f8357 100644 +index 60f8357..41727bf 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -1167,6 +1167,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y - CONFIG_CIFS_UPCALL=y - CONFIG_CIFS_XATTR=y - CONFIG_CIFS_POSIX=y -+CONFIG_CIFS_ACL=y -+CONFIG_CIFS_DFS_UPCALL=y -+CONFIG_CIFS_SMB2=y -+CONFIG_CIFS_FSCACHE=y - CONFIG_9P_FS=m - CONFIG_9P_FS_POSIX_ACL=y - CONFIG_NLS_DEFAULT="utf8" +@@ -842,6 +842,7 @@ CONFIG_SND_SOC_WM8804_I2C=m + CONFIG_SND_SIMPLE_CARD=m + CONFIG_SOUND_PRIME=m + CONFIG_HIDRAW=y ++CONFIG_UHID=m + CONFIG_HID_A4TECH=m + CONFIG_HID_ACRUX=m + CONFIG_HID_APPLE=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 75fa1d0..8ebc8d5 100644 +index 8ebc8d5..bc0f523 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -1160,6 +1160,10 @@ CONFIG_CIFS_WEAK_PW_HASH=y - CONFIG_CIFS_UPCALL=y - CONFIG_CIFS_XATTR=y - CONFIG_CIFS_POSIX=y -+CONFIG_CIFS_ACL=y -+CONFIG_CIFS_DFS_UPCALL=y -+CONFIG_CIFS_SMB2=y -+CONFIG_CIFS_FSCACHE=y - CONFIG_9P_FS=m - CONFIG_9P_FS_POSIX_ACL=y - CONFIG_NLS_DEFAULT="utf8" +@@ -835,6 +835,7 @@ CONFIG_SND_SOC_WM8804_I2C=m + CONFIG_SND_SIMPLE_CARD=m + CONFIG_SOUND_PRIME=m + CONFIG_HIDRAW=y ++CONFIG_UHID=m + CONFIG_HID_A4TECH=m + CONFIG_HID_ACRUX=m + CONFIG_HID_APPLE=m -From dee40d2ad759e6f0d9737f15c9c00a9149d55b73 Mon Sep 17 00:00:00 2001 -From: David Lechner -Date: Mon, 14 Sep 2015 19:08:36 -0500 -Subject: [PATCH 187/204] Use dts-dirs feature for overlays. - -The kernel makefiles have a dts-dirs target that is for vendor subdirectories. - -Using this fixes the install_dtbs target, which previously did not install the overlays. ---- - arch/arm/boot/dts/Makefile | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 12de305..faf293f 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -15,6 +15,9 @@ endif - ifeq ($(CONFIG_ARCH_BCM2835),y) - RPI_DT_OVERLAYS=y - endif -+ifeq ($(RPI_DT_OVERLAYS),y) -+ dts-dirs += overlays -+endif - - dtb-$(CONFIG_ARCH_ALPINE) += \ - alpine-db.dtb -@@ -683,11 +686,10 @@ targets += $(dtb-y) - endif - - always := $(dtb-y) -+subdir-y := $(dts-dirs) - clean-files := *.dtb - - # Enable fixups to support overlays on BCM2708 platforms - ifeq ($(RPI_DT_OVERLAYS),y) - DTC_FLAGS ?= -@ - endif -- --subdir-y += overlays - -From 51ccad4fd102f2eb4d2a8115ff2a06ec01676acd Mon Sep 17 00:00:00 2001 -From: Martin Sperl -Date: Thu, 10 Sep 2015 09:32:14 +0000 -Subject: [PATCH 192/204] backport: spi: bcm2835: BUG: fix wrong use of - PAGE_MASK - -There is a bug in the alignment checking of transfers, -that results in DMA not being used for un-aligned -transfers that do not cross page-boundries, which is valid. - -This is due to a missconception of the meaning PAGE_MASK -when implementing that check originally - (PAGE_SIZE - 1) -should have been used instead. - -Also fixes a copy/paste error. - -Reported-by: -Signed-off-by: Martin Sperl -Signed-off-by: Mark Brown -Cc: stable@vger.kernel.org ---- - drivers/spi/spi-bcm2835.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c -index b68991c..3835332 100644 ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -386,14 +386,14 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, - /* otherwise we only allow transfers within the same page - * to avoid wasting time on dma_mapping when it is not practical - */ -- if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { -+ if (((size_t)tfr->tx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { - dev_warn_once(&spi->dev, - "Unaligned spi tx-transfer bridging page\n"); - return false; - } -- if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { -+ if (((size_t)tfr->rx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) { - dev_warn_once(&spi->dev, -- "Unaligned spi tx-transfer bridging page\n"); -+ "Unaligned spi rx-transfer bridging page\n"); - return false; - } - - -From 16e92c1ffaf2b25fc3b410ba8e1dc6a457b645f7 Mon Sep 17 00:00:00 2001 +From e2bed14c7bea9eb805bea8ac0d10952dc0070032 Mon Sep 17 00:00:00 2001 From: Stuart MacLean Date: Fri, 2 Oct 2015 15:12:59 +0100 -Subject: [PATCH 193/204] Add support for the HiFiBerry DAC+ Pro. +Subject: [PATCH 196/278] Add support for the HiFiBerry DAC+ Pro. The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators. @@ -150247,10 +150778,645 @@ index e12764d..8d16b2f 100644 dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From f1c2c5ab06e1597d0aa0593c5dec52cf580332e3 Mon Sep 17 00:00:00 2001 +From 1cddc8af1c04d0958bd2bb968cfe1f06936a0398 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sun, 4 Oct 2015 12:30:01 +0100 +Subject: [PATCH 197/278] config: Add CONFIG_CRYPTO_USER_API_SKCIPHER + +--- + 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 41727bf..a13cd93 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1238,6 +1238,7 @@ CONFIG_CRYPTO_WP512=m + CONFIG_CRYPTO_CAST5=m + CONFIG_CRYPTO_DES=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_SKCIPHER=m + # CONFIG_CRYPTO_HW is not set + CONFIG_ARM_CRYPTO=y + CONFIG_CRYPTO_SHA1_ARM_NEON=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index bc0f523..5cf54ea 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1234,6 +1234,7 @@ CONFIG_CRYPTO_WP512=m + CONFIG_CRYPTO_CAST5=m + CONFIG_CRYPTO_DES=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_SKCIPHER=m + # CONFIG_CRYPTO_HW is not set + CONFIG_ARM_CRYPTO=y + CONFIG_CRYPTO_SHA1_ARM=m + +From 371b2e422fd6f8d724d8b51613b9cc07f0ea7887 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sun, 4 Oct 2015 12:36:44 +0100 +Subject: [PATCH 198/278] config: Add options for supporting openlabs 802.15.4 + radio + +--- + arch/arm/configs/bcm2709_defconfig | 6 ++++++ + arch/arm/configs/bcmrpi_defconfig | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index a13cd93..630da1b 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -283,6 +283,9 @@ CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m + CONFIG_6LOWPAN=m ++CONFIG_IEEE802154=m ++CONFIG_IEEE802154_6LOWPAN=m ++CONFIG_MAC802154=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -529,6 +532,9 @@ CONFIG_ZD1211RW=m + CONFIG_MWIFIEX=m + CONFIG_MWIFIEX_SDIO=m + CONFIG_WIMAX_I2400M_USB=m ++CONFIG_IEEE802154_AT86RF230=m ++CONFIG_IEEE802154_MRF24J40=m ++CONFIG_IEEE802154_CC2520=m + CONFIG_INPUT_POLLDEV=m + # CONFIG_INPUT_MOUSEDEV_PSAUX is not set + CONFIG_INPUT_JOYDEV=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 5cf54ea..df4cebc 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -276,6 +276,9 @@ CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m + CONFIG_6LOWPAN=m ++CONFIG_IEEE802154=m ++CONFIG_IEEE802154_6LOWPAN=m ++CONFIG_MAC802154=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -522,6 +525,9 @@ CONFIG_ZD1211RW=m + CONFIG_MWIFIEX=m + CONFIG_MWIFIEX_SDIO=m + CONFIG_WIMAX_I2400M_USB=m ++CONFIG_IEEE802154_AT86RF230=m ++CONFIG_IEEE802154_MRF24J40=m ++CONFIG_IEEE802154_CC2520=m + CONFIG_INPUT_POLLDEV=m + # CONFIG_INPUT_MOUSEDEV_PSAUX is not set + CONFIG_INPUT_JOYDEV=m + +From 097a8688c9aaa1b6f5c4c7eeb7a02dc86c27c6d1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 5 Oct 2015 10:47:45 +0100 +Subject: [PATCH 199/278] BCM270X_DT: Add at86rf233 overlay + +Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0. + +See: https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 21 +++++++-- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++ + 3 files changed, 72 insertions(+), 4 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 192bda7..6de04be 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y) + endif + + dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 4ab4c695..68b608b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -69,13 +69,14 @@ DT parameters: + + Parameters always have default values, although in some cases (e.g. "w1-gpio") + it is necessary to provided multiple overlays in order to get the desired +-behaviour. See the list of overlays below for a description of the parameters and their defaults. ++behaviour. See the list of overlays below for a description of the parameters ++and their defaults. + + The Overlay and Parameter Reference + =================================== + +-N.B. When editing this file, please preserve the indentation levels to make it simple to parse +-programmatically. NO HARD TABS. ++N.B. When editing this file, please preserve the indentation levels to make it ++simple to parse programmatically. NO HARD TABS. + + + Name: +@@ -149,7 +150,7 @@ Name: ads7846 + Info: ADS7846 Touch controller + Load: dtoverlay=ads7846,= + Params: cs SPI bus Chip Select (default 1) +- speed SPI bus speed (default 2Mhz, max 3.25MHz) ++ speed SPI bus speed (default 2MHz, max 3.25MHz) + penirq GPIO used for PENIRQ. REQUIRED + penirq_pull Set GPIO pull (default 0=none, 2=pullup) + swapxy Swap x and y axis +@@ -170,6 +171,18 @@ Params: cs SPI bus Chip Select (default 1) + www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt + + ++Name: at86rf233 ++Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, ++ connected to spi0.0 ++Load: dtoverlay=at86rf233,= ++Params: interrupt GPIO used for INT (default 23) ++ reset GPIO used for Reset (default 24) ++ sleep GPIO used for Sleep (default 25) ++ speed SPI bus speed in Hz (default 750000) ++ trim Fine tuning of the internal capacitance ++ arrays (0=+0pF, 15=+4.5pF, default 15) ++ ++ + Name: bmp085_i2c-sensor + Info: Configures the BMP085/BMP180 digital barometric pressure and temperature + sensors from Bosch Sensortec +diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +new file mode 100644 +index 0000000..70f50ea +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +@@ -0,0 +1,54 @@ ++/dts-v1/; ++/plugin/; ++ ++/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */ ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ lowpan0: at86rf233@0 { ++ compatible = "atmel,at86rf233"; ++ reg = <0>; ++ interrupt-parent = <&gpio>; ++ interrupts = <23 4>; /* active high */ ++ reset-gpio = <&gpio 24 1>; ++ sleep-gpio = <&gpio 25 1>; ++ spi-max-frequency = <7500000>; ++ xtal-trim = /bits/ 8 <0xf>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ lowpan0_pins: lowpan0_pins { ++ brcm,pins = <23 24 25>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ interrupt = <&lowpan0>, "interrupts:0", ++ <&lowpan0_pins>, "brcm,pins:0"; ++ reset = <&lowpan0>, "reset-gpio:4", ++ <&lowpan0_pins>, "brcm,pins:4"; ++ sleep = <&lowpan0>, "sleep-gpio:4", ++ <&lowpan0_pins>, "brcm,pins:8"; ++ speed = <&lowpan0>, "spi-max-frequency:0"; ++ trim = <&lowpan0>, "xtal-trim.0"; ++ }; ++}; + +From 429666c96ef139bd1b9f4668b60a824448a20d52 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 6 Oct 2015 10:16:58 +0100 +Subject: [PATCH 200/278] bcm2835-gpiomem: Fix for ARCH_BCM2835 builds + +Build on ARCH_BCM2835, and fail to probe if no IO resource. + +See: https://github.com/raspberrypi/linux/issues/1154 +--- + drivers/char/broadcom/bcm2835-gpiomem.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c +index 0085e13..911f5b7 100644 +--- a/drivers/char/broadcom/bcm2835-gpiomem.c ++++ b/drivers/char/broadcom/bcm2835-gpiomem.c +@@ -143,7 +143,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + int err; + void *ptr_err; + struct device *dev = &pdev->dev; +- struct device_node *node = dev->of_node; + struct resource *ioresource; + + /* Allocate buffers and instance data */ +@@ -157,6 +156,15 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + + inst->dev = dev; + ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (ioresource) { ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ dev_err(inst->dev, "failed to get IO resource"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ + /* Create character device entries */ + + err = alloc_chrdev_region(&bcm2835_gpiomem_devid, +@@ -187,20 +195,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + if (IS_ERR(ptr_err)) + goto failed_device_create; + +- /* Get address from device tree if available (*_resource() correctly +- converts the bus address in device tree to a physical address), +- or use hardcoded offset + BCM2708_PERI_BASE if not. +- (In spite of its name 2708 actually seems to have the correct +- mach-dependent value on 2709 etc, as it is defined in +- mach-bcm270x/platform.h) */ +- +- if (node) { +- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- inst->gpio_regs_phys = ioresource->start; +- } else { +- inst->gpio_regs_phys = GPIO_BASE; +- } +- + dev_info(inst->dev, "Initialised: Registers at 0x%08lx", + inst->gpio_regs_phys); + +@@ -214,6 +208,7 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) + failed_cdev_add: + unregister_chrdev_region(bcm2835_gpiomem_devid, 1); + failed_alloc_chrdev: ++failed_get_resource: + kfree(inst); + failed_inst_alloc: + dev_err(inst->dev, "could not load bcm2835_gpiomem"); + +From b21b82f99f3bd05b70800c2722ac254eaf707224 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 8 Oct 2015 13:33:28 +0100 +Subject: [PATCH 201/278] scripts/mkknlimg: Improve ARCH_BCM2835 detection + +The board support code contains sufficient strings to be able to +distinguish 2708 vs. 2835 builds, so remove the check for +bcm2835-pm-wdt which could exist in either. + +Also, since the canned configuration is no longer built in (it's +a module), remove the config string checking. + +See: https://github.com/raspberrypi/linux/issues/1157 +--- + scripts/mkknlimg | 41 +++++------------------------------------ + 1 file changed, 5 insertions(+), 36 deletions(-) + +diff --git a/scripts/mkknlimg b/scripts/mkknlimg +index 3dff948..3998d43 100755 +--- a/scripts/mkknlimg ++++ b/scripts/mkknlimg +@@ -50,12 +50,6 @@ if (! -r $kernel_file) + usage(); + } + +-my @wanted_config_lines = +-( +- 'CONFIG_BCM2708_DT', +- 'CONFIG_ARCH_BCM2835' +-); +- + my @wanted_strings = + ( + 'bcm2708_fb', +@@ -63,7 +57,8 @@ my @wanted_strings = + 'brcm,bcm2835-sdhost', + 'brcm,bcm2708-pinctrl', + 'brcm,bcm2835-gpio', +- 'brcm,bcm2835-pm-wdt' ++ 'brcm,bcm2835', ++ 'brcm,bcm2836' + ); + + my $res = try_extract($kernel_file, $tmpfile1); +@@ -98,12 +93,11 @@ if ($res) + config_bool($res, 'brcm,bcm2835-mmc') || + config_bool($res, 'brcm,bcm2835-sdhost')) + { +- $dtok ||= config_bool($res, 'CONFIG_BCM2708_DT'); +- $dtok ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); + $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl'); + $dtok ||= config_bool($res, 'brcm,bcm2835-gpio'); +- $is_283x ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); +- $is_283x ||= config_bool($res, 'brcm,bcm2835-pm-wdt'); ++ $is_283x ||= config_bool($res, 'brcm,bcm2835'); ++ $is_283x ||= config_bool($res, 'brcm,bcm2836'); ++ $dtok ||= $is_283x; + $append_trailer = 1; + } + else +@@ -205,31 +199,6 @@ sub try_extract + $res->{$match} = 1; + } + +- my $config_pattern = '^('.join('|', @wanted_config_lines).')=(.*)$'; +- my $cf1 = 'IKCFG_ST\037\213\010'; +- my $cf2 = '0123456789'; +- +- my $pos = `tr "$cf1\n$cf2" "\n$cf2=" < "$knl" | grep -abo "^$cf2"`; +- if ($pos) +- { +- $pos =~ s/:.*[\r\n]*$//s; +- $pos += 8; +- my $err = (system("tail -c+$pos \"$knl\" | zcat > $tmp 2> /dev/null") >> 8); +- if (($err == 0) || ($err == 2)) +- { +- if (open(my $fh, '<', $tmp)) +- { +- while (my $line = <$fh>) +- { +- chomp($line); +- $res->{$1} = $2 if ($line =~ /$config_pattern/); +- } +- +- close($fh); +- } +- } +- } +- + return $res; + } + + +From 8f7cf07cccdc8a867d3b413156038d15142fa8fa Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 9 Oct 2015 10:49:00 +0100 +Subject: [PATCH 202/278] BCM270X_DT: Make mmc overlay compatible with current + firmware + +The original DT overlay logic followed a merge-then-patch procedure, +i.e. parameters are applied to the loaded overlay before the overlay +is merged into the base DTB. This sequence has been changed to +patch-then-merge, in order to support parameterised node names, and +to protect against bad overlays. As a result, overrides (parameters) +must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB. + +mmc-overlay.dts (that switches back to the original mmc sdcard +driver) is the only overlay violating that rule, and this patch +fixes it. +--- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 0a37cf4..4579ff2 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -7,13 +7,13 @@ + fragment@0 { + target = <&mmc>; + +- __overlay__ { ++ frag0: __overlay__ { + brcm,overclock-50 = <0>; + }; + }; + + __overrides__ { +- overclock_50 = <&mmc>,"brcm,overclock-50:0"; +- force_pio = <&mmc>,"brcm,force-pio?"; ++ overclock_50 = <&frag0>,"brcm,overclock-50:0"; ++ force_pio = <&frag0>,"brcm,force-pio?"; + }; + }; + +From 2ff4df2d402e49fd86a179ec9a6145d35c6a9b1a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 12 Oct 2015 08:52:00 +0100 +Subject: [PATCH 203/278] BCM270X_DT: Reduce default at86rf233 SPI frequency + +The AT86RF233 has been found to be unreliable on a 7.5MHz SPI bus, +so reduce the default frequency to 6MHz. + +See: https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/README | 2 +- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 68b608b..970d37e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -178,7 +178,7 @@ Load: dtoverlay=at86rf233,= + Params: interrupt GPIO used for INT (default 23) + reset GPIO used for Reset (default 24) + sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 750000) ++ speed SPI bus speed in Hz (default 6000000) + trim Fine tuning of the internal capacitance + arrays (0=+0pF, 15=+4.5pF, default 15) + +diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +index 70f50ea..0460269 100644 +--- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts ++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +@@ -25,7 +25,7 @@ + interrupts = <23 4>; /* active high */ + reset-gpio = <&gpio 24 1>; + sleep-gpio = <&gpio 25 1>; +- spi-max-frequency = <7500000>; ++ spi-max-frequency = <6000000>; + xtal-trim = /bits/ 8 <0xf>; + }; + }; + +From 4842bf44119f87f6cff2bb0158b3d62b8fd3b4cc Mon Sep 17 00:00:00 2001 +From: mwilliams03 +Date: Sun, 18 Oct 2015 17:07:24 -0700 +Subject: [PATCH 204/278] New overlay for PiScreen2r + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 14 +++ + arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++ + 3 files changed, 115 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 6de04be..b36b8e3 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 970d37e..b605dc4e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -411,6 +411,20 @@ Params: speed Display SPI bus speed + xohms Touchpanel sensitivity (X-plate resistance) + + ++Name: piscreen2r ++Info: PiScreen 2 with resistive TP display by OzzMaker.com ++Load: dtoverlay=piscreen,= ++Params: speed Display SPI bus speed ++ ++ rotate Display rotation {0,90,180,270} ++ ++ fps Delay between frame updates ++ ++ debug Debug output level {0-7} ++ ++ xohms Touchpanel sensitivity (X-plate resistance) ++ ++ + Name: pitft28-resistive + Info: Adafruit PiTFT 2.8" resistive touch screen + Load: dtoverlay=pitft28-resistive,= +diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +new file mode 100644 +index 0000000..7c018e0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +@@ -0,0 +1,100 @@ ++ /* ++ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ piscreen2_pins: piscreen2_pins { ++ brcm,pins = <17 25 24 22>; ++ brcm,function = <0 1 1 1>; /* in out out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ piscreen2: piscreen2@0{ ++ compatible = "ilitek,ili9486"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&piscreen2_pins>; ++ bgr; ++ spi-max-frequency = <64000000>; ++ rotate = <90>; ++ fps = <30>; ++ buswidth = <8>; ++ regwidth = <16>; ++ txbuflen = <32768>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 22 1>; ++ debug = <0>; ++ ++ init = <0x10000b0 0x00 ++ 0x1000011 ++ 0x20000ff ++ 0x100003a 0x55 ++ 0x1000036 0x28 ++ 0x10000c0 0x11 0x09 ++ 0x10000c1 0x41 ++ 0x10000c5 0x00 0x00 0x00 0x00 ++ 0x10000b6 0x00 0x02 ++ 0x10000f7 0xa9 0x51 0x2c 0x2 ++ 0x10000be 0x00 0x04 ++ 0x10000e9 0x00 ++ 0x1000011 ++ 0x1000029>; ++ ++ }; ++ ++ piscreen2_ts: piscreen2-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,swap-xy; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&piscreen2>,"spi-max-frequency:0"; ++ rotate = <&piscreen2>,"rotate:0"; ++ fps = <&piscreen2>,"fps:0"; ++ debug = <&piscreen2>,"debug:0"; ++ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; ++ + +From 7316bdce9228750ba92627dfbb9836dba652c639 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 194/204] rpi_display: add backlight driver and overlay +Subject: [PATCH 205/278] 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 @@ -150272,10 +151438,10 @@ Signed-off-by: Gordon Hollingworth create mode 100644 drivers/video/backlight/rpi_backlight.c diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index 192bda7..2e82be5 100644 +index b36b8e3..f4b2817 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -38,6 +38,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb +@@ -40,6 +40,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb @@ -150284,10 +151450,10 @@ index 192bda7..2e82be5 100644 dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 4ab4c695..b57bd11 100644 +index b605dc4e..42a5876 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -463,6 +463,12 @@ Load: dtoverlay=raspidac3 +@@ -490,6 +490,12 @@ Load: dtoverlay=raspidac3 Params: @@ -150328,10 +151494,10 @@ index 0000000..c021d02 + }; +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 60f8357..6f4021b 100644 +index 630da1b..fb402e8 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -802,6 +802,7 @@ CONFIG_FB_BCM2708=y +@@ -808,6 +808,7 @@ CONFIG_FB_BCM2708=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m # CONFIG_BACKLIGHT_GENERIC is not set @@ -150340,10 +151506,10 @@ index 60f8357..6f4021b 100644 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 8ebc8d5..015540b 100644 +index df4cebc..eb81555e 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -795,6 +795,7 @@ CONFIG_FB_BCM2708=y +@@ -801,6 +801,7 @@ CONFIG_FB_BCM2708=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m # CONFIG_BACKLIGHT_GENERIC is not set @@ -150517,251 +151683,720 @@ index d3933af..ffb0f82 100644 RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, +From 8b9ee2dffa3104f41e9b9a6a956ca7e2151bd266 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Fri, 2 Oct 2015 11:30:11 -0700 +Subject: [PATCH 207/278] Input: add support for FocalTech FT6236 touchscreen + controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +This adds support for the FT6x06 and the FT6x36 family of capacitive touch +panel controllers, in particular the FT6236. -From ed66fe22cf07f1240e693bf6e7628ac9c42d36d4 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 6 Oct 2015 10:16:58 +0100 -Subject: [PATCH 196/204] bcm2835-gpiomem: Fix for ARCH_BCM2835 builds - -Build on ARCH_BCM2835, and fail to probe if no IO resource. - -See: https://github.com/raspberrypi/linux/issues/1154 +Signed-off-by: Noralf Trønnes +Signed-off-by: Dmitry Torokhov --- - drivers/char/broadcom/bcm2835-gpiomem.c | 25 ++++++++++--------------- - 1 file changed, 10 insertions(+), 15 deletions(-) + .../input/touchscreen/focaltech-ft6236.txt | 35 +++ + .../devicetree/bindings/vendor-prefixes.txt | 1 + + drivers/input/touchscreen/Kconfig | 13 + + drivers/input/touchscreen/Makefile | 1 + + drivers/input/touchscreen/ft6236.c | 327 +++++++++++++++++++++ + 5 files changed, 377 insertions(+) + create mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt + create mode 100644 drivers/input/touchscreen/ft6236.c -diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c -index 0085e13..911f5b7 100644 ---- a/drivers/char/broadcom/bcm2835-gpiomem.c -+++ b/drivers/char/broadcom/bcm2835-gpiomem.c -@@ -143,7 +143,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - int err; - void *ptr_err; - struct device *dev = &pdev->dev; -- struct device_node *node = dev->of_node; - struct resource *ioresource; +diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt +new file mode 100644 +index 0000000..777521d +--- /dev/null ++++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt +@@ -0,0 +1,35 @@ ++* FocalTech FT6236 I2C touchscreen controller ++ ++Required properties: ++ - compatible : "focaltech,ft6236" ++ - reg : I2C slave address of the chip (0x38) ++ - interrupt-parent : a phandle pointing to the interrupt controller ++ serving the interrupt for this chip ++ - interrupts : interrupt specification for the touch controller ++ interrupt ++ - reset-gpios : GPIO specification for the RSTN input ++ - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) ++ - touchscreen-size-y : vertical resolution of touchscreen (in pixels) ++ ++Optional properties: ++ - touchscreen-fuzz-x : horizontal noise value of the absolute input ++ device (in pixels) ++ - touchscreen-fuzz-y : vertical noise value of the absolute input ++ device (in pixels) ++ - touchscreen-inverted-x : X axis is inverted (boolean) ++ - touchscreen-inverted-y : Y axis is inverted (boolean) ++ - touchscreen-swapped-x-y: X and Y axis are swapped (boolean) ++ Swapping is done after inverting the axis ++ ++Example: ++ ++ ft6x06@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ interrupt-parent = <&gpio>; ++ interrupts = <23 2>; ++ touchscreen-size-x = <320>; ++ touchscreen-size-y = <480>; ++ touchscreen-inverted-x; ++ touchscreen-swapped-x-y; ++ }; +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 80339192..08490ef 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -76,6 +76,7 @@ everspin Everspin Technologies, Inc. + excito Excito + fcs Fairchild Semiconductor + firefly Firefly ++focaltech FocalTech Systems Co.,Ltd + fsl Freescale Semiconductor + GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. + gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index d7e74a1..6536cd2 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -295,6 +295,19 @@ config TOUCHSCREEN_EGALAX + To compile this driver as a module, choose M here: the + module will be called egalax_ts. - /* Allocate buffers and instance data */ -@@ -157,6 +156,15 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - - inst->dev = dev; - -+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (ioresource) { -+ inst->gpio_regs_phys = ioresource->start; -+ } else { -+ dev_err(inst->dev, "failed to get IO resource"); -+ err = -ENOENT; -+ goto failed_get_resource; ++config TOUCHSCREEN_FT6236 ++ tristate "FT6236 I2C touchscreen" ++ depends on I2C ++ depends on GPIOLIB || COMPILE_TEST ++ help ++ Say Y here to enable support for the I2C connected FT6x06 and ++ FT6x36 family of capacitive touchscreen drivers. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ft6236. ++ + config TOUCHSCREEN_FUJITSU + tristate "Fujitsu serial touchscreen" + select SERIO +diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile +index a1be09f..c867f82 100644 +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -36,6 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o + obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o + obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o ++obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o + obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +new file mode 100644 +index 0000000..cccae19 +--- /dev/null ++++ b/drivers/input/touchscreen/ft6236.c +@@ -0,0 +1,327 @@ ++/* ++ * FocalTech FT6236 TouchScreen driver. ++ * ++ * Copyright (c) 2010 Focal tech Ltd. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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 ++ ++#define FT6236_MAX_TOUCH_POINTS 2 ++ ++#define FT6236_REG_TH_GROUP 0x80 ++#define FT6236_REG_PERIODACTIVE 0x88 ++#define FT6236_REG_LIB_VER_H 0xa1 ++#define FT6236_REG_LIB_VER_L 0xa2 ++#define FT6236_REG_CIPHER 0xa3 ++#define FT6236_REG_FIRMID 0xa6 ++#define FT6236_REG_FOCALTECH_ID 0xa8 ++#define FT6236_REG_RELEASE_CODE_ID 0xaf ++ ++#define FT6236_EVENT_PRESS_DOWN 0 ++#define FT6236_EVENT_LIFT_UP 1 ++#define FT6236_EVENT_CONTACT 2 ++#define FT6236_EVENT_NO_EVENT 3 ++ ++struct ft6236_data { ++ struct i2c_client *client; ++ struct input_dev *input; ++ struct gpio_desc *reset_gpio; ++ u32 max_x; ++ u32 max_y; ++ bool invert_x; ++ bool invert_y; ++ bool swap_xy; ++}; ++ ++/* ++ * This struct is a touchpoint as stored in hardware. Note that the id, ++ * as well as the event, are stored in the upper nybble of the hi byte. ++ */ ++struct ft6236_touchpoint { ++ union { ++ u8 xhi; ++ u8 event; ++ }; ++ u8 xlo; ++ union { ++ u8 yhi; ++ u8 id; ++ }; ++ u8 ylo; ++ u8 weight; ++ u8 misc; ++} __packed; ++ ++/* This packet represents the register map as read from offset 0 */ ++struct ft6236_packet { ++ u8 dev_mode; ++ u8 gest_id; ++ u8 touches; ++ struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; ++} __packed; ++ ++static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) ++{ ++ int error; ++ ++ error = i2c_smbus_read_i2c_block_data(client, reg, len, data); ++ if (error < 0) ++ return error; ++ ++ if (error != len) ++ return -EIO; ++ ++ return 0; ++} ++ ++static irqreturn_t ft6236_interrupt(int irq, void *dev_id) ++{ ++ struct ft6236_data *ft6236 = dev_id; ++ struct device *dev = &ft6236->client->dev; ++ struct input_dev *input = ft6236->input; ++ struct ft6236_packet buf; ++ u8 touches; ++ int i, error; ++ ++ error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); ++ if (error) { ++ dev_err(dev, "read touchdata failed %d\n", error); ++ return IRQ_HANDLED; + } + - /* Create character device entries */ - - err = alloc_chrdev_region(&bcm2835_gpiomem_devid, -@@ -187,20 +195,6 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - if (IS_ERR(ptr_err)) - goto failed_device_create; - -- /* Get address from device tree if available (*_resource() correctly -- converts the bus address in device tree to a physical address), -- or use hardcoded offset + BCM2708_PERI_BASE if not. -- (In spite of its name 2708 actually seems to have the correct -- mach-dependent value on 2709 etc, as it is defined in -- mach-bcm270x/platform.h) */ -- -- if (node) { -- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- inst->gpio_regs_phys = ioresource->start; -- } else { -- inst->gpio_regs_phys = GPIO_BASE; -- } -- - dev_info(inst->dev, "Initialised: Registers at 0x%08lx", - inst->gpio_regs_phys); - -@@ -214,6 +208,7 @@ static int bcm2835_gpiomem_probe(struct platform_device *pdev) - failed_cdev_add: - unregister_chrdev_region(bcm2835_gpiomem_devid, 1); - failed_alloc_chrdev: -+failed_get_resource: - kfree(inst); - failed_inst_alloc: - dev_err(inst->dev, "could not load bcm2835_gpiomem"); ++ touches = buf.touches & 0xf; ++ if (touches > FT6236_MAX_TOUCH_POINTS) { ++ dev_dbg(dev, ++ "%d touch points reported, only %d are supported\n", ++ touches, FT6236_MAX_TOUCH_POINTS); ++ touches = FT6236_MAX_TOUCH_POINTS; ++ } ++ ++ for (i = 0; i < touches; i++) { ++ struct ft6236_touchpoint *point = &buf.points[i]; ++ u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; ++ u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; ++ u8 event = point->event >> 6; ++ u8 id = point->id >> 4; ++ bool act = (event == FT6236_EVENT_PRESS_DOWN || ++ event == FT6236_EVENT_CONTACT); ++ ++ input_mt_slot(input, id); ++ input_mt_report_slot_state(input, MT_TOOL_FINGER, act); ++ if (!act) ++ continue; ++ ++ if (ft6236->invert_x) ++ x = ft6236->max_x - x; ++ ++ if (ft6236->invert_y) ++ y = ft6236->max_y - y; ++ ++ if (ft6236->swap_xy) { ++ input_report_abs(input, ABS_MT_POSITION_X, y); ++ input_report_abs(input, ABS_MT_POSITION_Y, x); ++ } else { ++ input_report_abs(input, ABS_MT_POSITION_X, x); ++ input_report_abs(input, ABS_MT_POSITION_Y, y); ++ } ++ } ++ ++ input_mt_sync_frame(input); ++ input_sync(input); ++ ++ return IRQ_HANDLED; ++} ++ ++static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) ++{ ++ struct i2c_client *client = ft6236->client; ++ u8 val = 0; ++ int error; ++ ++ error = ft6236_read(client, reg, 1, &val); ++ if (error) ++ dev_dbg(&client->dev, ++ "error reading register 0x%02x: %d\n", reg, error); ++ ++ return val; ++} ++ ++static void ft6236_debug_info(struct ft6236_data *ft6236) ++{ ++ struct device *dev = &ft6236->client->dev; ++ ++ dev_dbg(dev, "Touch threshold is %d\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); ++ dev_dbg(dev, "Report rate is %dHz\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); ++ dev_dbg(dev, "Firmware library version 0x%02x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), ++ ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); ++ dev_dbg(dev, "Firmware version 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); ++ dev_dbg(dev, "Chip vendor ID 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); ++ dev_dbg(dev, "CTPM vendor ID 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); ++ dev_dbg(dev, "Release code version 0x%02x\n", ++ ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); ++} ++ ++static void ft6236_reset(struct ft6236_data *ft6236) ++{ ++ if (!ft6236->reset_gpio) ++ return; ++ ++ gpiod_set_value_cansleep(ft6236->reset_gpio, 1); ++ usleep_range(5000, 20000); ++ gpiod_set_value_cansleep(ft6236->reset_gpio, 0); ++ msleep(300); ++} ++ ++static int ft6236_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct ft6236_data *ft6236; ++ struct input_dev *input; ++ u32 fuzz_x = 0, fuzz_y = 0; ++ u8 val; ++ int error; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -ENXIO; ++ ++ if (!client->irq) { ++ dev_err(dev, "irq is missing\n"); ++ return -EINVAL; ++ } ++ ++ ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); ++ if (!ft6236) ++ return -ENOMEM; ++ ++ ft6236->client = client; ++ ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ft6236->reset_gpio)) { ++ error = PTR_ERR(ft6236->reset_gpio); ++ if (error != -EPROBE_DEFER) ++ dev_err(dev, "error getting reset gpio: %d\n", error); ++ return error; ++ } ++ ++ ft6236_reset(ft6236); ++ ++ /* verify that the controller is present */ ++ error = ft6236_read(client, 0x00, 1, &val); ++ if (error) { ++ dev_err(dev, "failed to read from controller: %d\n", error); ++ return error; ++ } ++ ++ ft6236_debug_info(ft6236); ++ ++ input = devm_input_allocate_device(dev); ++ if (!input) ++ return -ENOMEM; ++ ++ ft6236->input = input; ++ input->name = client->name; ++ input->id.bustype = BUS_I2C; ++ ++ if (device_property_read_u32(dev, "touchscreen-size-x", ++ &ft6236->max_x) || ++ device_property_read_u32(dev, "touchscreen-size-y", ++ &ft6236->max_y)) { ++ dev_err(dev, "touchscreen-size-x and/or -y missing\n"); ++ return -EINVAL; ++ } ++ ++ device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); ++ device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); ++ ft6236->invert_x = device_property_read_bool(dev, ++ "touchscreen-inverted-x"); ++ ft6236->invert_y = device_property_read_bool(dev, ++ "touchscreen-inverted-y"); ++ ft6236->swap_xy = device_property_read_bool(dev, ++ "touchscreen-swapped-x-y"); ++ ++ if (ft6236->swap_xy) { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, ++ ft6236->max_y, fuzz_y, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ++ ft6236->max_x, fuzz_x, 0); ++ } else { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, ++ ft6236->max_x, fuzz_x, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ++ ft6236->max_y, fuzz_y, 0); ++ } ++ ++ error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, ++ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); ++ if (error) ++ return error; ++ ++ error = devm_request_threaded_irq(dev, client->irq, NULL, ++ ft6236_interrupt, IRQF_ONESHOT, ++ client->name, ft6236); ++ if (error) { ++ dev_err(dev, "request irq %d failed: %d\n", client->irq, error); ++ return error; ++ } ++ ++ error = input_register_device(input); ++ if (error) { ++ dev_err(dev, "failed to register input device: %d\n", error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id ft6236_of_match[] = { ++ { .compatible = "focaltech,ft6236", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ft6236_of_match); ++#endif ++ ++static const struct i2c_device_id ft6236_id[] = { ++ { "ft6236", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ft6236_id); ++ ++static struct i2c_driver ft6236_driver = { ++ .driver = { ++ .name = "ft6236", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ft6236_of_match), ++ }, ++ .probe = ft6236_probe, ++ .id_table = ft6236_id, ++}; ++module_i2c_driver(ft6236_driver); ++ ++MODULE_AUTHOR("Sean Cross "); ++MODULE_AUTHOR("Noralf Trønnes "); ++MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); ++MODULE_LICENSE("GPL"); -From 9223ca1be3362490e689e00156fa792e04910284 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 5 Oct 2015 10:47:45 +0100 -Subject: [PATCH 197/204] BCM270X_DT: Add at86rf233 overlay +From dae7385cf2bf7503293d4af49bb713fbe8f2d62e Mon Sep 17 00:00:00 2001 +From: Fengguang Wu +Date: Tue, 6 Oct 2015 15:37:02 -0700 +Subject: [PATCH 208/278] Input: ft6236 - do not explicitly set driver's owner -Add an overlay to support the Atmel AT86RF233 WPAN transceiver on spi0.0. +There is no need to explicitly set .owner for the driver, the core will do +it for us. -See: https://github.com/raspberrypi/linux/issues/1151 +Signed-off-by: Fengguang Wu +Signed-off-by: Dmitry Torokhov --- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 21 +++++++-- - arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 54 ++++++++++++++++++++++++ - 3 files changed, 72 insertions(+), 4 deletions(-) - create mode 100644 arch/arm/boot/dts/overlays/at86rf233-overlay.dts + drivers/input/touchscreen/ft6236.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +index cccae19..a394cd4 100644 +--- a/drivers/input/touchscreen/ft6236.c ++++ b/drivers/input/touchscreen/ft6236.c +@@ -313,7 +313,6 @@ MODULE_DEVICE_TABLE(i2c, ft6236_id); + static struct i2c_driver ft6236_driver = { + .driver = { + .name = "ft6236", +- .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ft6236_of_match), + }, + .probe = ft6236_probe, + +From 12714b8017bece4a80e431ab321b8b346656e243 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Tue, 6 Oct 2015 17:00:36 -0700 +Subject: [PATCH 209/278] Input: ft6236 - change module license string to match + copyright notice + +The copyright/license notice says that the code is licensed under GPL v2 +only (not GPL v2+), so let's use proper string in MODULE_LICENSE(). + +Signed-off-by: Dmitry Torokhov +--- + drivers/input/touchscreen/ft6236.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c +index a394cd4..d240d2e 100644 +--- a/drivers/input/touchscreen/ft6236.c ++++ b/drivers/input/touchscreen/ft6236.c +@@ -323,4 +323,4 @@ module_i2c_driver(ft6236_driver); + MODULE_AUTHOR("Sean Cross "); + MODULE_AUTHOR("Noralf Trønnes "); + MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL v2"); + +From a48e386718a983c1b1bd6f7d1fa6002fad4d56c3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Mon, 26 Oct 2015 14:42:10 +0100 +Subject: [PATCH 210/278] config: Add TOUCHSCREEN_FT6236 + +--- + 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 fb402e8..130a30c0 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -551,6 +551,7 @@ CONFIG_JOYSTICK_RPISENSE=m + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m + CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_FT6236=m + CONFIG_TOUCHSCREEN_RPI_FT5406=m + CONFIG_TOUCHSCREEN_USB_COMPOSITE=m + CONFIG_TOUCHSCREEN_STMPE=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index eb81555e..fbdfa91 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -544,6 +544,7 @@ CONFIG_JOYSTICK_RPISENSE=m + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m + CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_FT6236=m + CONFIG_TOUCHSCREEN_RPI_FT5406=m + CONFIG_TOUCHSCREEN_USB_COMPOSITE=m + CONFIG_TOUCHSCREEN_STMPE=m + +From d321f1163cf92999b2b8a8fbcf88a8ee246312fa Mon Sep 17 00:00:00 2001 +From: Alistair Buxton +Date: Sun, 1 Nov 2015 22:27:56 +0000 +Subject: [PATCH 211/278] Build i2c_gpio module and add a device tree overlay + to configure it. + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 11 ++++++++++ + arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 28 +++++++++++++++++++++++++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + 5 files changed, 42 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index 2e82be5..b370eb0 100644 +index f4b2817..84c1566 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -13,6 +13,7 @@ ifeq ($(CONFIG_ARCH_BCM2835),y) - endif - - dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb -+dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb +@@ -25,6 +25,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += i2c-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += i2s-mmap-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index b57bd11..014675a 100644 +index 42a5876..46149ea 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -69,13 +69,14 @@ DT parameters: - - Parameters always have default values, although in some cases (e.g. "w1-gpio") - it is necessary to provided multiple overlays in order to get the desired --behaviour. See the list of overlays below for a description of the parameters and their defaults. -+behaviour. See the list of overlays below for a description of the parameters -+and their defaults. - - The Overlay and Parameter Reference - =================================== - --N.B. When editing this file, please preserve the indentation levels to make it simple to parse --programmatically. NO HARD TABS. -+N.B. When editing this file, please preserve the indentation levels to make it -+simple to parse programmatically. NO HARD TABS. +@@ -284,6 +284,17 @@ Params: speed Display SPI bus speed + ledgpio GPIO used to control backlight - Name: -@@ -149,7 +150,7 @@ Name: ads7846 - Info: ADS7846 Touch controller - Load: dtoverlay=ads7846,= - Params: cs SPI bus Chip Select (default 1) -- speed SPI bus speed (default 2Mhz, max 3.25MHz) -+ speed SPI bus speed (default 2MHz, max 3.25MHz) - penirq GPIO used for PENIRQ. REQUIRED - penirq_pull Set GPIO pull (default 0=none, 2=pullup) - swapxy Swap x and y axis -@@ -170,6 +171,18 @@ Params: cs SPI bus Chip Select (default 1) - www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt - - -+Name: at86rf233 -+Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, -+ connected to spi0.0 -+Load: dtoverlay=at86rf233,= -+Params: interrupt GPIO used for INT (default 23) -+ reset GPIO used for Reset (default 24) -+ sleep GPIO used for Sleep (default 25) -+ speed SPI bus speed in Hz (default 750000) -+ trim Fine tuning of the internal capacitance -+ arrays (0=+0pF, 15=+4.5pF, default 15) ++Name: i2c-gpio ++Info: Adds support for software i2c controller on gpio pins ++Load: dtoverlay=i2c-gpio, ++Params: i2c_gpio_sda GPIO used for I2C data (default "23") ++ ++ i2c_gpio_scl GPIO used for I2C clock (default "24") ++ ++ i2c_gpio_delay_us Clock delay in microseconds ++ (default "2" = ~100kHz) + + - Name: bmp085_i2c-sensor - Info: Configures the BMP085/BMP180 digital barometric pressure and temperature - sensors from Bosch Sensortec -diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices + Load: dtoverlay=i2c-rtc, +diff --git a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts new file mode 100644 -index 0000000..70f50ea +index 0000000..2a2dc98 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts -@@ -0,0 +1,54 @@ ++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts +@@ -0,0 +1,28 @@ ++// Overlay for i2c_gpio bitbanging host bus. +/dts-v1/; +/plugin/; + -+/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */ -+ +/ { -+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ compatible = "brcm,bcm2708"; + + fragment@0 { -+ target = <&spi0>; ++ target-path = "/"; + __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ lowpan0: at86rf233@0 { -+ compatible = "atmel,at86rf233"; -+ reg = <0>; -+ interrupt-parent = <&gpio>; -+ interrupts = <23 4>; /* active high */ -+ reset-gpio = <&gpio 24 1>; -+ sleep-gpio = <&gpio 25 1>; -+ spi-max-frequency = <7500000>; -+ xtal-trim = /bits/ 8 <0xf>; ++ i2c_gpio: i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&gpio 23 0 /* sda */ ++ &gpio 24 0 /* scl */ ++ >; ++ i2c-gpio,delay-us = <2>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; + }; + }; + }; -+ -+ fragment@1 { -+ target = <&gpio>; -+ __overlay__ { -+ lowpan0_pins: lowpan0_pins { -+ brcm,pins = <23 24 25>; -+ brcm,function = <0 1 1>; /* in out out */ -+ }; -+ }; -+ }; -+ + __overrides__ { -+ interrupt = <&lowpan0>, "interrupts:0", -+ <&lowpan0_pins>, "brcm,pins:0"; -+ reset = <&lowpan0>, "reset-gpio:4", -+ <&lowpan0_pins>, "brcm,pins:4"; -+ sleep = <&lowpan0>, "sleep-gpio:4", -+ <&lowpan0_pins>, "brcm,pins:8"; -+ speed = <&lowpan0>, "spi-max-frequency:0"; -+ trim = <&lowpan0>, "xtal-trim.0"; ++ i2c_gpio_sda = <&i2c_gpio>,"gpios:4"; ++ i2c_gpio_scl = <&i2c_gpio>,"gpios:16"; ++ i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0"; + }; +}; ++ +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 130a30c0..f87e8b6 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -595,6 +595,7 @@ CONFIG_BCM_VC_SM=y + CONFIG_I2C=y + CONFIG_I2C_CHARDEV=m + CONFIG_I2C_BCM2708=m ++CONFIG_I2C_GPIO=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index fbdfa91..214b9b6 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -588,6 +588,7 @@ CONFIG_BCM_VC_SM=y + CONFIG_I2C=y + CONFIG_I2C_CHARDEV=m + CONFIG_I2C_BCM2708=m ++CONFIG_I2C_GPIO=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m -From c089bd70a6d37cb4a05626d48eaebcdfcef0bf41 Mon Sep 17 00:00:00 2001 -From: mwilliams03 -Date: Sun, 18 Oct 2015 17:07:24 -0700 -Subject: [PATCH 198/204] New overlay for PiScreen2r +From 2ae0a4766fe7c891c3ce5be714a80787a227a274 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 5 Nov 2015 12:01:53 +0000 +Subject: [PATCH 212/278] config: Add MCP320X + +See: https://github.com/raspberrypi/linux/issues/1189 +--- + 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 f87e8b6..d789c51 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1106,6 +1106,7 @@ CONFIG_IIO=m + CONFIG_IIO_BUFFER=y + CONFIG_IIO_BUFFER_CB=y + CONFIG_IIO_KFIFO_BUF=m ++CONFIG_MCP320X=m + CONFIG_DHT11=m + CONFIG_PWM_BCM2835=m + CONFIG_RASPBERRYPI_FIRMWARE=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 214b9b6..d658aa7 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1099,6 +1099,7 @@ CONFIG_IIO=m + CONFIG_IIO_BUFFER=y + CONFIG_IIO_BUFFER_CB=y + CONFIG_IIO_KFIFO_BUF=m ++CONFIG_MCP320X=m + CONFIG_DHT11=m + CONFIG_PWM_BCM2835=m + CONFIG_RASPBERRYPI_FIRMWARE=y + +From 7fefb6e593bf0478edbcd0266cac3af9a6856610 Mon Sep 17 00:00:00 2001 +From: Ondrej Wisniewski +Date: Fri, 6 Nov 2015 15:01:28 +0100 +Subject: [PATCH 213/278] dts: Added overlay for Adafruit PiTFT 2.8" capacitive + touch screen --- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 14 +++ - arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 100 ++++++++++++++++++++++ - 3 files changed, 115 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 22 ++++++ + .../dts/overlays/pitft28-capacitive-overlay.dts | 88 ++++++++++++++++++++++ + 3 files changed, 111 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index b370eb0..f4b2817 100644 +index 84c1566..3df97bb 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -34,6 +34,7 @@ dtb-$(RPI_DT_OVERLAYS) += mcp2515-can1-overlay.dtb - dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb +@@ -36,6 +36,7 @@ dtb-$(RPI_DT_OVERLAYS) += mmc-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += mz61581-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb -+dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += piscreen2r-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += pitft28-capacitive-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 014675a..3276312 100644 +index 46149ea..db4a77b 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -411,6 +411,20 @@ Params: speed Display SPI bus speed +@@ -436,6 +436,28 @@ Params: speed Display SPI bus speed xohms Touchpanel sensitivity (X-plate resistance) -+Name: piscreen2r -+Info: PiScreen 2 with resistive TP display by OzzMaker.com -+Load: dtoverlay=piscreen,= ++Name: pitft28-capacitive ++Info: Adafruit PiTFT 2.8" capacitive touch screen ++Load: dtoverlay=pitft28-capacitive,= +Params: speed Display SPI bus speed + + rotate Display rotation {0,90,180,270} @@ -150770,20 +152405,28 @@ index 014675a..3276312 100644 + + debug Debug output level {0-7} + -+ xohms Touchpanel sensitivity (X-plate resistance) ++ touch-sizex Touchscreen size x (default 240) ++ ++ touch-sizey Touchscreen size y (default 320) ++ ++ touch-invx Touchscreen inverted x axis ++ ++ touch-invy Touchscreen inverted y axis ++ ++ touch-swapxy Touchscreen swapped x y axis + + Name: pitft28-resistive Info: Adafruit PiTFT 2.8" resistive touch screen Load: dtoverlay=pitft28-resistive,= -diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts new file mode 100644 -index 0000000..7c018e0 +index 0000000..48920e9 --- /dev/null -+++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts -@@ -0,0 +1,100 @@ -+ /* -+ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch by Ozzmaker.com ++++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts +@@ -0,0 +1,88 @@ ++/* ++ * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen + * + */ + @@ -150791,400 +152434,17955 @@ index 0000000..7c018e0 +/plugin/; + +/ { -+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ pitft_pins: pitft_pins { ++ brcm,pins = <24 25>; ++ brcm,function = <0 1>; /* in out */ ++ brcm,pull = <2 0>; /* pullup none */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pitft: pitft@0{ ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pitft_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <90>; ++ fps = <25>; ++ bgr; ++ buswidth = <8>; ++ dc-gpios = <&gpio 25 0>; ++ debug = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c1>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ft6236: ft6236@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ ++ interrupt-parent = <&gpio>; ++ interrupts = <24 2>; ++ touchscreen-size-x = <240>; ++ touchscreen-size-y = <320>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0"; ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ touch-sizex = <&ft6236>,"touchscreen-size-x?"; ++ touch-sizey = <&ft6236>,"touchscreen-size-y?"; ++ touch-invx = <&ft6236>,"touchscreen-inverted-x?"; ++ touch-invy = <&ft6236>,"touchscreen-inverted-y?"; ++ touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?"; ++ }; ++}; + +From be1f4be48573c6cda72ed1324a5fe97f8eda5dd9 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 6 Nov 2015 16:24:59 +0000 +Subject: [PATCH 214/278] rpi-ft5406: Use interruptible sleep to avoid high + load reported + +--- + drivers/input/touchscreen/rpi-ft5406.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/rpi-ft5406.c b/drivers/input/touchscreen/rpi-ft5406.c +index c08817e..b27dbee 100644 +--- a/drivers/input/touchscreen/rpi-ft5406.c ++++ b/drivers/input/touchscreen/rpi-ft5406.c +@@ -65,7 +65,7 @@ static int ft5406_thread(void *arg) + while(!kthread_should_stop()) + { + // 60fps polling +- msleep(17); ++ msleep_interruptible(17); + memcpy_fromio(®s, ts->regs, sizeof(*ts->regs)); + writel(99, &ts->regs->num_points); + // Do not output if theres no new information (num_points is 99) + +From fe07a10d55ea6f22ef183cb8469761d21fc02909 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 11 Nov 2015 12:55:53 +0000 +Subject: [PATCH 215/278] config: ADD CONFIG_FB_UDL module (USB displaylink) + +--- + 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 d789c51..2c32293 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -807,6 +807,7 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y ++CONFIG_FB_UDL=m + CONFIG_FB_SSD1307=m + CONFIG_FB_RPISENSE=m + # CONFIG_BACKLIGHT_GENERIC is not set +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index d658aa7..c2ff887 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -800,6 +800,7 @@ CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y ++CONFIG_FB_UDL=m + CONFIG_FB_SSD1307=m + CONFIG_FB_RPISENSE=m + # CONFIG_BACKLIGHT_GENERIC is not set + +From e6d2c7de9b7041eface31625868429f1386d44e6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson <6by9@users.noreply.github.com> +Date: Tue, 14 Jul 2015 22:57:57 +0100 +Subject: [PATCH 216/278] BCM2835-V4L2: Return buffers to videobuf2 on shutdown + +https://github.com/raspberrypi/linux/issues/817 +Fixes the kernel warning from videobuf2 as buffers +are now returned as they are being flushed on +stop_streaming. +--- + drivers/media/platform/bcm2835/bcm2835-camera.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c +index 04a1711..b49b6dc3 100644 +--- a/drivers/media/platform/bcm2835/bcm2835-camera.c ++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c +@@ -404,6 +404,7 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, + } + } else { + /* signal frame completion */ ++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + complete(&dev->capture.frame_cmplt); + } + } + +From 9bd52d710b4b7bfa1bcf5a805f316e10b02a8112 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 14 Nov 2015 12:24:59 +0000 +Subject: [PATCH 217/278] config: Add FB_TFT_ILI9163 module + +--- + 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 2c32293..d06b9c8 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1076,6 +1076,7 @@ CONFIG_FB_TFT_BD663474=m + CONFIG_FB_TFT_HX8340BN=m + CONFIG_FB_TFT_HX8347D=m + CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9163=m + CONFIG_FB_TFT_ILI9320=m + CONFIG_FB_TFT_ILI9325=m + CONFIG_FB_TFT_ILI9340=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index c2ff887..e04f122 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1069,6 +1069,7 @@ CONFIG_FB_TFT_BD663474=m + CONFIG_FB_TFT_HX8340BN=m + CONFIG_FB_TFT_HX8347D=m + CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9163=m + CONFIG_FB_TFT_ILI9320=m + CONFIG_FB_TFT_ILI9325=m + CONFIG_FB_TFT_ILI9340=m + +From 6137f86ef451567cf414b0330eadd60812bd5b6b Mon Sep 17 00:00:00 2001 +From: Holger Steinhaus +Date: Sat, 14 Nov 2015 18:37:43 +0100 +Subject: [PATCH 218/278] dts: Added overlay for gpio_ir_recv driver + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 16 +++++++++ + arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 45 ++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/gpio-ir-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 3df97bb..1a60e9c 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -17,6 +17,7 @@ dtb-$(RPI_DT_OVERLAYS) += at86rf233-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += gpio-ir-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index db4a77b..a2db163 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -209,6 +209,22 @@ Params: int_pin GPIO used for INT (default 25) + speed SPI bus speed (default 12000000) + + ++Name: gpio-ir ++Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core- ++ based gpio_ir_recv driver maps received keys directly to a ++ /dev/input/event* device, all decoding is done by the kernel - LIRC is ++ not required! The key mapping and other decoding parameters can be ++ configured by "ir-keytable" tool. ++Load: dtoverlay=gpio-ir,= ++Params: gpio_pin Input pin number. Default is 18. ++ ++ gpio_pull Desired pull-up/down state (off, down, up) ++ Default is "down". ++ ++ rc-map-name Default rc keymap (can also be changed by ++ ir-keytable), defaults to "rc-rc6-mce" ++ ++ + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot + Load: gpio-poweroff,= +diff --git a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts +new file mode 100644 +index 0000000..a2d6bc7 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts +@@ -0,0 +1,45 @@ ++// Definitions for ir-gpio module ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ gpio_ir: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ ++ // pin number, high or low ++ gpios = <&gpio 18 1>; ++ ++ // parameter for keymap name ++ linux,rc-map-name = "rc-rc6-mce"; ++ ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ gpio_ir_pins: gpio_ir_pins { ++ brcm,pins = <18>; // pin 18 ++ brcm,function = <0>; // in ++ brcm,pull = <1>; // down ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ // parameters ++ gpio_pin = <&gpio_ir>,"gpios:4", ++ <&gpio_ir_pins>,"brcm,pins:0", ++ <&gpio_ir_pins>,"brcm,pull:0"; // pin number ++ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state ++ ++ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map ++ }; ++}; + +From fc7249d583613c11bd5d75f2a71db14d79fae137 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 17 Nov 2015 10:07:08 +0000 +Subject: [PATCH 219/278] BCM270X_DT: Fix overlay README anomalies + +--- + arch/arm/boot/dts/overlays/README | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index a2db163..df5b3e6 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -227,7 +227,7 @@ Params: gpio_pin Input pin number. Default is 18. + + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot +-Load: gpio-poweroff,= ++Load: dtoverlay=gpio-poweroff,= + Params: gpiopin GPIO for signalling (default 26) + + active_low Set if the power control device requires a +@@ -302,7 +302,7 @@ Params: speed Display SPI bus speed + + Name: i2c-gpio + Info: Adds support for software i2c controller on gpio pins +-Load: dtoverlay=i2c-gpio, ++Load: dtoverlay=i2c-gpio,= + Params: i2c_gpio_sda GPIO used for I2C data (default "23") + + i2c_gpio_scl GPIO used for I2C clock (default "24") +@@ -313,7 +313,7 @@ Params: i2c_gpio_sda GPIO used for I2C data (default "23") + + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices +-Load: dtoverlay=i2c-rtc, ++Load: dtoverlay=i2c-rtc,= + Params: ds1307 Select the DS1307 device + + ds3231 Select the DS3231 device +@@ -348,7 +348,7 @@ Params: + Name: lirc-rpi + Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi) + Consult the module documentation for more details. +-Load: dtoverlay=lirc-rpi,=,... ++Load: dtoverlay=lirc-rpi,= + Params: gpio_out_pin GPIO for output (default "17") + + gpio_in_pin GPIO for input (default "18") +@@ -440,7 +440,7 @@ Params: speed Display SPI bus speed + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com +-Load: dtoverlay=piscreen,= ++Load: dtoverlay=piscreen2r,= + Params: speed Display SPI bus speed + + rotate Display rotation {0,90,180,270} +@@ -505,7 +505,6 @@ Info: Configures a single PWM channel + 3) So be careful mixing audio and PWM. + 4) Currently the clock must have been enabled and configured + by other means. +-Load: dtoverlay=pwm-2chan,= + Load: dtoverlay=pwm,= + Params: pin Output pin (default 18) - see table + func Pin function (default 2 = Alt5) - see above +@@ -708,7 +707,7 @@ Params: gpiopin GPIO for I/O (default "4") + Name: w1-gpio-pullup + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *do* need a GPIO to drive an external pullup. +-Load: dtoverlay=w1-gpio-pullup,=,... ++Load: dtoverlay=w1-gpio-pullup,= + Params: gpiopin GPIO for I/O (default "4") + + pullup Non-zero, "on", or "y" to enable the parasitic + +From e3c114e909ea3a42bcc84781d5cc63afcf7a9c8e Mon Sep 17 00:00:00 2001 +From: wuyuehang +Date: Tue, 17 Nov 2015 09:24:41 +0800 +Subject: [PATCH 220/278] bcm2709_fb: refine appropriate behaviors to + unsupported fb ioctls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +since fbturbo introduces and use FBUNSUPPORTED ioctl on copyarea +operations for unsupported dummy ioctl which is expected to return +failure. in such scenario, bcm2709 always prompts error log. + +in order not to bother users in kernel log, we change the dev_err to +dev_dbg and return a ENOTTY other than EINVAL to let userspace handles +the return value. + +Signed-off-by: wuyuehang +Reviewed-by: popcornmix +Reviewed-by: Phil Elwell +Reviewed-by: Noralf Trønnes +--- + drivers/video/fbdev/bcm2708_fb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c +index 0f62d76..a20539a 100644 +--- a/drivers/video/fbdev/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c +@@ -442,8 +442,8 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long a + &dummy, sizeof(dummy)); + break; + default: +- dev_err(info->device, "Unknown ioctl 0x%x\n", cmd); +- return -EINVAL; ++ dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd); ++ return -ENOTTY; + } + + if (ret) + +From e2fd14f8ca274c7da18b34db3298961d68c1d95b Mon Sep 17 00:00:00 2001 +From: Patrick Boettcher +Date: Fri, 20 Nov 2015 15:09:36 +0100 +Subject: [PATCH 221/278] SDIO-overlay: add poll_once-boolean parameter + +Add paramter to toggle sdio-device-polling +done every second or once at boot-time. + +Signed-off-by: Patrick Boettcher +--- + arch/arm/boot/dts/overlays/README | 3 +++ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 6 +++++- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index df5b3e6..019928d 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -610,6 +610,9 @@ Params: overclock_50 Clock (in MHz) to use when the MMC framework + + debug Enable debug output (default off) + ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) ++ + + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 164f269..6626a1d 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -7,7 +7,7 @@ + + fragment@3 { + target = <&mmc>; +- __overlay__ { ++ sdio_mmc: __overlay__ { + compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; +@@ -26,4 +26,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ poll_once = <&sdio_mmc>,"non-removable?"; ++ }; + }; + +From 744ebedb1283cd11649381155dca86821c76bfe6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 1 Dec 2015 16:52:13 +0000 +Subject: [PATCH 222/278] BCM270X_DT: Use clk_core for I2C interfaces + +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 43 +++++++++++++++-------------------- + 1 file changed, 18 insertions(+), 25 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 933711e..66f7165 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -147,7 +147,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -186,7 +186,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e804000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -199,7 +199,7 @@ + compatible = "brcm,bcm2708-i2c"; + reg = <0x7e805000 0x1000>; + interrupts = <2 21>; +- clocks = <&clk_i2c>; ++ clocks = <&clk_core>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -258,56 +258,49 @@ + #address-cells = <1>; + #size-cells = <0>; + +- clk_mmc: clock@0 { ++ clk_core: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; +- clock-output-names = "mmc"; ++ clock-output-names = "core"; + clock-frequency = <250000000>; + }; + +- clk_i2c: clock@1 { ++ clk_mmc: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; +- clock-output-names = "i2c"; ++ clock-output-names = "mmc"; + clock-frequency = <250000000>; + }; + +- clk_core: clock@2 { ++ clk_uart0: clock@2 { + compatible = "fixed-clock"; + reg = <2>; + #clock-cells = <0>; +- clock-output-names = "core"; +- clock-frequency = <250000000>; +- }; +- +- clk_uart0: clock@3 { +- compatible = "fixed-clock"; +- reg = <3>; +- #clock-cells = <0>; + clock-output-names = "uart0_pclk"; + clock-frequency = <3000000>; + }; + +- clk_apb_p: clock@4 { ++ clk_apb_p: clock@3 { + compatible = "fixed-clock"; +- reg = <4>; ++ reg = <3>; + #clock-cells = <0>; + clock-output-names = "apb_pclk"; + clock-frequency = <126000000>; + }; + +- clk_pwm: clock@5 { +- compatible = "fixed-clock"; +- reg = <3>; +- #clock-cells = <0>; +- clock-output-names = "pwm"; +- clock-frequency = <100000000>; ++ clk_pwm: clock@4 { ++ compatible = "fixed-clock"; ++ reg = <4>; ++ #clock-cells = <0>; ++ clock-output-names = "pwm"; ++ clock-frequency = <100000000>; + }; + +- clk_uart1: clock@6 { ++ clk_uart1: clock@5 { + compatible = "fixed-factor-clock"; ++ reg = <5>; + clocks = <&clk_core>; + #clock-cells = <0>; + clock-div = <1>; + +From 8a9b2d2b1c247942d0f57c23d780641e5eefed37 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 8 Dec 2015 16:23:33 +0000 +Subject: [PATCH 223/278] bcm270x_dt: Use the sdhost MMC controller by default + +The "mmc" overlay reverts to using the other controller. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 11 ++++-- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 11 ++++-- + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 14 ++++++-- + arch/arm/boot/dts/bcm2708_common.dtsi | 13 +++++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 11 ++++-- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 22 +++++++++++- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 49 ++++++--------------------- + arch/arm/boot/dts/overlays/sdio-overlay.dts | 1 - + 8 files changed, 84 insertions(+), 48 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index e3ae8e6..566f52e1 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 2adc248..5218ee9 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 713e5a2..91ec483c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,5 +1,12 @@ + /include/ "bcm2708.dtsi" + ++&gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++}; ++ + &leds { + act_led: act { + label = "led0"; +@@ -8,9 +15,12 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ non-removable; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 66f7165..463777e 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,6 +14,7 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; ++ sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -114,6 +115,18 @@ + status = "disabled"; + }; + ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,pio-limit = <1>; ++ status = "disabled"; ++ }; ++ + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 76d44a2..c703448 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 4579ff2..00a22be 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,9 +6,29 @@ + + fragment@0 { + target = <&mmc>; +- + frag0: __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc_pins>; ++ bus-width = <4>; + brcm,overclock-50 = <0>; + status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ spidev@1{ -+ status = "disabled"; -+ }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { -+ piscreen2_pins: piscreen2_pins { -+ brcm,pins = <17 25 24 22>; -+ brcm,function = <0 1 1 1>; /* in out out out */ ++ mmc_pins: mmc_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <7>; /* alt3 */ + }; + }; + }; + + fragment@2 { -+ target = <&spi0>; ++ target = <&sdhost>; + __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ piscreen2: piscreen2@0{ -+ compatible = "ilitek,ili9486"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&piscreen2_pins>; -+ bgr; -+ spi-max-frequency = <64000000>; -+ rotate = <90>; -+ fps = <30>; -+ buswidth = <8>; -+ regwidth = <16>; -+ txbuflen = <32768>; -+ reset-gpios = <&gpio 25 0>; -+ dc-gpios = <&gpio 24 0>; -+ led-gpios = <&gpio 22 1>; -+ debug = <0>; -+ -+ init = <0x10000b0 0x00 -+ 0x1000011 -+ 0x20000ff -+ 0x100003a 0x55 -+ 0x1000036 0x28 -+ 0x10000c0 0x11 0x09 -+ 0x10000c1 0x41 -+ 0x10000c5 0x00 0x00 0x00 0x00 -+ 0x10000b6 0x00 0x02 -+ 0x10000f7 0xa9 0x51 0x2c 0x2 -+ 0x10000be 0x00 0x04 -+ 0x10000e9 0x00 -+ 0x1000011 -+ 0x1000029>; -+ -+ }; -+ -+ piscreen2_ts: piscreen2-ts@1 { -+ compatible = "ti,ads7846"; -+ reg = <1>; -+ -+ spi-max-frequency = <2000000>; -+ interrupts = <17 2>; /* high-to-low edge triggered */ -+ interrupt-parent = <&gpio>; -+ pendown-gpio = <&gpio 17 0>; -+ ti,swap-xy; -+ ti,x-plate-ohms = /bits/ 16 <100>; -+ ti,pressure-max = /bits/ 16 <255>; -+ }; -+ }; -+ }; -+ __overrides__ { -+ speed = <&piscreen2>,"spi-max-frequency:0"; -+ rotate = <&piscreen2>,"rotate:0"; -+ fps = <&piscreen2>,"fps:0"; -+ debug = <&piscreen2>,"debug:0"; -+ xohms = <&piscreen2_ts>,"ti,x-plate-ohms;0"; -+ }; -+}; -+ - -From 30a73891df28c2922fcad40317f474914ccf4434 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 9 Oct 2015 10:49:00 +0100 -Subject: [PATCH 199/204] BCM270X_DT: Make mmc overlay compatible with current - firmware - -The original DT overlay logic followed a merge-then-patch procedure, -i.e. parameters are applied to the loaded overlay before the overlay -is merged into the base DTB. This sequence has been changed to -patch-then-merge, in order to support parameterised node names, and -to protect against bad overlays. As a result, overrides (parameters) -must only target labels in the overlay, but the overlay can obviously target nodes in the base DTB. - -mmc-overlay.dts (that switches back to the original mmc sdcard -driver) is the only overlay violating that rule, and this patch -fixes it. ---- - arch/arm/boot/dts/overlays/mmc-overlay.dts | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts -index 0a37cf4..4579ff2 100644 ---- a/arch/arm/boot/dts/overlays/mmc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts -@@ -7,13 +7,13 @@ - fragment@0 { - target = <&mmc>; ++ status = "disabled"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 2da14a4..85f0725 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -5,52 +5,25 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; ++ target = <&mmc>; + __overlay__ { +- #address-cells = <1>; +- #size-cells = <1>; +- +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,delay-after-stop = <0>; +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; +- }; ++ status = "disabled"; + }; + }; + + fragment@1 { +- target = <&gpio>; - __overlay__ { -+ frag0: __overlay__ { - brcm,overclock-50 = <0>; +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- }; +- }; +- +- fragment@2 { +- target = <&mmc>; +- __overlay__ { +- /* Find a way to disable the other driver */ +- compatible = ""; +- status = "disabled"; ++ target = <&sdhost>; ++ frag1: __overlay__ { ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; }; }; __overrides__ { -- overclock_50 = <&mmc>,"brcm,overclock-50:0"; -- force_pio = <&mmc>,"brcm,force-pio?"; -+ overclock_50 = <&frag0>,"brcm,overclock-50:0"; -+ force_pio = <&frag0>,"brcm,force-pio?"; +- overclock_50 = <&sdhost>,"brcm,overclock-50:0"; +- force_pio = <&sdhost>,"brcm,force-pio?"; +- pio_limit = <&sdhost>,"brcm,pio-limit:0"; +- debug = <&sdhost>,"brcm,debug?"; ++ overclock_50 = <&frag1>,"brcm,overclock-50:0"; ++ force_pio = <&frag1>,"brcm,force-pio?"; ++ pio_limit = <&frag1>,"brcm,pio-limit:0"; ++ debug = <&frag1>,"brcm,debug?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 6626a1d..afc8742 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -8,7 +8,6 @@ + fragment@3 { + target = <&mmc>; + sdio_mmc: __overlay__ { +- compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; + +From c0690a03d3127c7a33fd4c818792d386f0cd7dad Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 9 Dec 2015 11:38:15 +0000 +Subject: [PATCH 224/278] bcm2835-sdhost: Don't log timeout errors unless + debug=1 + +The MMC card-discovery process generates timeouts. This is +expected behaviour, so reporting it to the user serves no purpose. +Suppress the reporting of timeout errors unless the debug flag +is on. +--- + drivers/mmc/host/bcm2835-sdhost.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 84f645f..44d61c3 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -966,19 +966,15 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + mmc_hostname(host->mmc)); + } else { + if (sdhsts & SDHSTS_CMD_TIME_OUT) { +- switch (host->cmd->opcode) { +- case 5: case 52: case 53: +- /* Don't warn about SDIO commands */ +- break; +- default: +- pr_err("%s: command timeout\n", +- mmc_hostname(host->mmc)); +- break; +- } ++ if (host->debug) ++ pr_err("%s: command %d timeout\n", ++ mmc_hostname(host->mmc), ++ host->cmd->opcode); + host->cmd->error = -ETIMEDOUT; + } else { +- pr_err("%s: unexpected command error\n", +- mmc_hostname(host->mmc)); ++ pr_err("%s: unexpected command %d error\n", ++ mmc_hostname(host->mmc), ++ host->cmd->opcode); + bcm2835_sdhost_dumpregs(host); + host->cmd->error = -EIO; + } + +From aefc9a3a911fa6f514b648edfcfa6125b43f7d69 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 15 Dec 2015 16:42:29 +0000 +Subject: [PATCH 225/278] config: Switch CONFIG_PREEMPT to + CONFIG_PREEMPT_VOLUNTARY + +See discussion here: https://github.com/raspberrypi/linux/issues/1216 +--- + arch/arm/configs/bcm2709_defconfig | 3 +-- + arch/arm/configs/bcmrpi_defconfig | 3 +-- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index d06b9c8..5a61222 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -44,7 +44,7 @@ CONFIG_BCM2709_DT=y + CONFIG_SMP=y + CONFIG_HAVE_ARM_ARCH_TIMER=y + CONFIG_VMSPLIT_2G=y +-CONFIG_PREEMPT=y ++CONFIG_PREEMPT_VOLUNTARY=y + CONFIG_AEABI=y + CONFIG_OABI_COMPAT=y + CONFIG_CLEANCACHE=y +@@ -1230,7 +1230,6 @@ CONFIG_BOOT_PRINTK_DELAY=y + CONFIG_DEBUG_MEMORY_INIT=y + CONFIG_DETECT_HUNG_TASK=y + CONFIG_TIMER_STATS=y +-# CONFIG_DEBUG_PREEMPT is not set + CONFIG_IRQSOFF_TRACER=y + CONFIG_SCHED_TRACER=y + CONFIG_STACK_TRACER=y +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index e04f122..20a26f0 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -39,7 +39,7 @@ CONFIG_MAC_PARTITION=y + CONFIG_CFQ_GROUP_IOSCHED=y + CONFIG_ARCH_BCM2708=y + CONFIG_BCM2708_DT=y +-CONFIG_PREEMPT=y ++CONFIG_PREEMPT_VOLUNTARY=y + CONFIG_AEABI=y + CONFIG_OABI_COMPAT=y + CONFIG_CLEANCACHE=y +@@ -1223,7 +1223,6 @@ CONFIG_BOOT_PRINTK_DELAY=y + CONFIG_DEBUG_MEMORY_INIT=y + CONFIG_DETECT_HUNG_TASK=y + CONFIG_TIMER_STATS=y +-# CONFIG_DEBUG_PREEMPT is not set + CONFIG_LATENCYTOP=y + CONFIG_IRQSOFF_TRACER=y + CONFIG_SCHED_TRACER=y + +From b776573142576cb8c38690113d2446de16a4a4cd Mon Sep 17 00:00:00 2001 +From: Devon Fyson +Date: Wed, 30 Dec 2015 16:40:47 -0500 +Subject: [PATCH 226/278] Extend clock timeout, fix modprobe baudrate + parameter. + +Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.\n- Increase priority of baudrate parameter passed to modprobe (in /etc/modprobe.d/*.conf or command line). Currently custom baudrates don't work because they are overridden by clock-frequency in the platform_device passed to the function. +--- + drivers/i2c/busses/i2c-bcm2708.c | 45 ++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 16 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c +index 8b8762d..426bd4e 100644 +--- a/drivers/i2c/busses/i2c-bcm2708.c ++++ b/drivers/i2c/busses/i2c-bcm2708.c +@@ -71,7 +71,8 @@ + + #define DRV_NAME "bcm2708_i2c" + +-static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE; ++static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE; ++static unsigned int baudrate; + module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + MODULE_PARM_DESC(baudrate, "The I2C baudrate"); + +@@ -87,6 +88,7 @@ struct bcm2708_i2c { + int irq; + struct clk *clk; + u32 cdiv; ++ u32 clk_tout; + + struct completion done; + +@@ -154,7 +156,7 @@ static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi) + + static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi) + { +- u32 cdiv, s; ++ u32 cdiv, s, clk_tout; + u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1; + int wait_loops = I2C_WAIT_LOOP_COUNT; + +@@ -162,12 +164,14 @@ static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi) + * Use the value that we cached in the probe. + */ + cdiv = bi->cdiv; ++ clk_tout = bi->clk_tout; + + if (bi->msg->flags & I2C_M_RD) + c |= BSC_C_INTR | BSC_C_READ; + else + c |= BSC_C_INTT; + ++ bcm2708_wr(bi, BSC_CLKT, clk_tout); + bcm2708_wr(bi, BSC_DIV, cdiv); + bcm2708_wr(bi, BSC_A, bi->msg->addr); + bcm2708_wr(bi, BSC_DLEN, bi->msg->len); +@@ -340,21 +344,24 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + struct bcm2708_i2c *bi; + struct i2c_adapter *adap; + unsigned long bus_hz; +- u32 cdiv; +- +- if (pdev->dev.of_node) { +- u32 bus_clk_rate; +- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); +- if (pdev->id < 0) { +- dev_err(&pdev->dev, "alias is missing\n"); +- return -EINVAL; ++ u32 cdiv, clk_tout; ++ ++ if (!baudrate) { ++ baudrate = baudrate_default; ++ if (pdev->dev.of_node) { ++ u32 bus_clk_rate; ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); ++ if (pdev->id < 0) { ++ dev_err(&pdev->dev, "alias is missing\n"); ++ return -EINVAL; ++ } ++ if (!of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &bus_clk_rate)) ++ baudrate = bus_clk_rate; ++ else ++ dev_warn(&pdev->dev, ++ "Could not read clock-frequency property\n"); + } +- if (!of_property_read_u32(pdev->dev.of_node, +- "clock-frequency", &bus_clk_rate)) +- baudrate = bus_clk_rate; +- else +- dev_warn(&pdev->dev, +- "Could not read clock-frequency property\n"); + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -448,7 +455,13 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + cdiv = 0xffff; + baudrate = bus_hz / cdiv; + } ++ ++ clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs. ++ if (clk_tout > 0xffff) ++ clk_tout = 0xffff; ++ + bi->cdiv = cdiv; ++ bi->clk_tout = clk_tout; + + dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", + pdev->id, (unsigned long)regs->start, irq, baudrate); + +From f90e9b5dc99b32dd6eac0745f7c5101b4a646ff2 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 4 Jan 2016 14:42:58 +0000 +Subject: [PATCH 227/278] rpisense: Make globals static to allow non-module + build + +--- + drivers/input/joystick/rpisense-js.c | 4 ++-- + drivers/mfd/rpisense-core.c | 2 +- + drivers/video/fbdev/rpisense-fb.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/input/joystick/rpisense-js.c b/drivers/input/joystick/rpisense-js.c +index 9eca897..6a41676 100644 +--- a/drivers/input/joystick/rpisense-js.c ++++ b/drivers/input/joystick/rpisense-js.c +@@ -18,8 +18,8 @@ + #include + #include + +-struct rpisense *rpisense; +-unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; ++static struct rpisense *rpisense; ++static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; + + static void keys_work_fn(struct work_struct *work) + { +diff --git a/drivers/mfd/rpisense-core.c b/drivers/mfd/rpisense-core.c +index 7539547..eea9312 100644 +--- a/drivers/mfd/rpisense-core.c ++++ b/drivers/mfd/rpisense-core.c +@@ -23,7 +23,7 @@ + #include + #include + +-struct rpisense *rpisense; ++static struct rpisense *rpisense; + + static void rpisense_client_dev_register(struct rpisense *rpisense, + const char *name, +diff --git a/drivers/video/fbdev/rpisense-fb.c b/drivers/video/fbdev/rpisense-fb.c +index 90553fa..26432a5 100644 +--- a/drivers/video/fbdev/rpisense-fb.c ++++ b/drivers/video/fbdev/rpisense-fb.c +@@ -31,7 +31,7 @@ static bool lowlight; + module_param(lowlight, bool, 0); + MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third"); + +-struct rpisense *rpisense; ++static struct rpisense *rpisense; + + struct rpisense_fb_param { + char __iomem *vmem; + +From fd7fd0089a640d83e9a1afbf95b3a4d1a55656a7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 8 Jan 2016 13:42:06 +0000 +Subject: [PATCH 228/278] BCM270X_DT: Enable the HW RNG by default + +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++++ + arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++++ + arch/arm/boot/dts/bcm2708-rpi-cm.dts | 4 ++++ + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++++ + arch/arm/boot/dts/overlays/README | 2 +- + 5 files changed, 17 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 566f52e1..bb8c075 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 5218ee9..8030401 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +index bddc369..ec4bfef 100755 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +@@ -75,6 +75,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + / { + __overrides__ { + uart0 = <&uart0>,"status"; +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index c703448..747f859 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -92,6 +92,10 @@ + pinctrl-0 = <&i2s_pins>; + }; + ++&random { ++ status = "okay"; ++}; ++ + &leds { + act_led: act { + label = "led0"; +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 019928d..9c50cffe 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -110,7 +110,7 @@ Params: + (default "off") + + random Set to "on" to enable the hardware random +- number generator (default "off") ++ number generator (default "on") + + uart0 Set to "off" to disable uart0 (default "on") + + +From 55e957414c492e8e0d5fb7b06e951c3003ac4ef5 Mon Sep 17 00:00:00 2001 +From: Andrew Litt +Date: Mon, 11 Jan 2016 07:54:21 +0000 +Subject: [PATCH 229/278] bcm2835-mmc: Don't override bus width capabilities + from devicetree + +Take out the force setting of the MMC_CAP_4_BIT_DATA host capability +so that the result read from devicetree via mmc_of_parse() is +preserved. +--- + drivers/mmc/host/bcm2835-mmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c +index 164bfad..db6617d 100644 +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -1329,7 +1329,7 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host) + /* host controller capabilities */ + mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | + MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | +- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_4_BIT_DATA; ++ MMC_CAP_MMC_HIGHSPEED; + + host->flags = SDHCI_AUTO_CMD23; + + +From e3871bd4dc21145963017eddbaed4f06bb2e3b89 Mon Sep 17 00:00:00 2001 +From: Andrew Litt +Date: Mon, 11 Jan 2016 07:55:54 +0000 +Subject: [PATCH 230/278] SDIO-overlay: add bus_width parameter + +Allow setting of the SDIO bus width capability of the bcm2835-mmc +host. This is helpful when only a 1 bit wide bus is connected +between host and device but both host and device advertise 4 bit +mode. +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 9c50cffe..cb7c359 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -613,6 +613,8 @@ Params: overclock_50 Clock (in MHz) to use when the MMC framework + poll_once Disable SDIO-device polling every second + (default on: polling once at boot-time) + ++ bus_width Set the SDIO host bus width (default 4 bits) ++ + + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index afc8742..7935e7a 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -11,6 +11,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; ++ bus-width = <4>; + status = "okay"; + }; + }; +@@ -28,5 +29,6 @@ + + __overrides__ { + poll_once = <&sdio_mmc>,"non-removable?"; ++ bus_width = <&sdio_mmc>,"bus-width:0"; }; }; -From 25dc64a6491a98e8df7b387e54dfe1d2be1ea5e8 Mon Sep 17 00:00:00 2001 +From 08c1794148a2a38fd46856ee991948988b7cd0dc Mon Sep 17 00:00:00 2001 From: Phil Elwell -Date: Mon, 12 Oct 2015 08:52:00 +0100 -Subject: [PATCH 200/204] BCM270X_DT: Reduce default at86rf233 SPI frequency +Date: Tue, 19 Jan 2016 16:28:05 +0000 +Subject: [PATCH 231/278] FIXUP i2c_bcm2708: Don't change module baudrate + parameter -The AT86RF233 has been found to be unreliable on a 7.5MHz SPI bus, -so reduce the default frequency to 6MHz. +Overwriting the baudrate module parameter creates an apparent +forced baudrate for i2c busses after the first. Not only does this +override the baudrate from DT it also prevents the bus ID from +being initialised. -See: https://github.com/raspberrypi/linux/issues/1151 +Also fix whitespace errors. --- - arch/arm/boot/dts/overlays/README | 2 +- - arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + drivers/i2c/busses/i2c-bcm2708.c | 50 +++++++++++++++++++++------------------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c +index 426bd4e..4c0c729 100644 +--- a/drivers/i2c/busses/i2c-bcm2708.c ++++ b/drivers/i2c/busses/i2c-bcm2708.c +@@ -71,7 +71,6 @@ + + #define DRV_NAME "bcm2708_i2c" + +-static unsigned int baudrate_default = CONFIG_I2C_BCM2708_BAUDRATE; + static unsigned int baudrate; + module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + MODULE_PARM_DESC(baudrate, "The I2C baudrate"); +@@ -345,25 +344,28 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + struct i2c_adapter *adap; + unsigned long bus_hz; + u32 cdiv, clk_tout; +- +- if (!baudrate) { +- baudrate = baudrate_default; +- if (pdev->dev.of_node) { +- u32 bus_clk_rate; +- pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); +- if (pdev->id < 0) { +- dev_err(&pdev->dev, "alias is missing\n"); +- return -EINVAL; +- } +- if (!of_property_read_u32(pdev->dev.of_node, +- "clock-frequency", &bus_clk_rate)) +- baudrate = bus_clk_rate; +- else +- dev_warn(&pdev->dev, +- "Could not read clock-frequency property\n"); ++ u32 baud; ++ ++ baud = CONFIG_I2C_BCM2708_BAUDRATE; ++ ++ if (pdev->dev.of_node) { ++ u32 bus_clk_rate; ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c"); ++ if (pdev->id < 0) { ++ dev_err(&pdev->dev, "alias is missing\n"); ++ return -EINVAL; + } ++ if (!of_property_read_u32(pdev->dev.of_node, ++ "clock-frequency", &bus_clk_rate)) ++ baud = bus_clk_rate; ++ else ++ dev_warn(&pdev->dev, ++ "Could not read clock-frequency property\n"); + } + ++ if (baudrate) ++ baud = baudrate; ++ + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "could not get IO memory\n"); +@@ -450,21 +452,21 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) + } + + bus_hz = clk_get_rate(bi->clk); +- cdiv = bus_hz / baudrate; ++ cdiv = bus_hz / baud; + if (cdiv > 0xffff) { + cdiv = 0xffff; +- baudrate = bus_hz / cdiv; ++ baud = bus_hz / cdiv; + } +- +- clk_tout = 35/1000*baudrate; //35ms timeout as per SMBus specs. +- if (clk_tout > 0xffff) ++ ++ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs. ++ if (clk_tout > 0xffff) + clk_tout = 0xffff; +- ++ + bi->cdiv = cdiv; + bi->clk_tout = clk_tout; + + dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", +- pdev->id, (unsigned long)regs->start, irq, baudrate); ++ pdev->id, (unsigned long)regs->start, irq, baud); + + return 0; + + +From bd24a11eeac81a9d0383de572c685c917375dbe5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 20 Jul 2015 12:33:04 -0700 +Subject: [PATCH 232/278] clk: bcm2835: Drop the fixed sys_pclk. + +Nothing uses it, and I can't find any evidence that anything ever has. +Its role is now filled by the core clock in the firmware driver. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Signed-off-by: Michael Turquette +(cherry picked from commit d24d2ec60f7b52c0eca1c52f821777329e5ffac1) +--- + drivers/clk/clk-bcm2835.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c +index 6b950ca..dd295e4 100644 +--- a/drivers/clk/clk-bcm2835.c ++++ b/drivers/clk/clk-bcm2835.c +@@ -32,11 +32,6 @@ void __init bcm2835_init_clocks(void) + struct clk *clk; + int ret; + +- clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT, +- 250000000); +- if (IS_ERR(clk)) +- pr_err("sys_pclk not registered\n"); +- + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, + 126000000); + if (IS_ERR(clk)) + +From c05754e73dc4b70deccaf7edde67fa92bf430bbe Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 28 Sep 2015 14:22:02 -0700 +Subject: [PATCH 233/278] clk: bcm2835: Move under bcm/ with other Broadcom SoC + clk drivers. + +clk-bcm2835.c predates the drivers under bcm/, but all the new BCM +drivers are going in there so let's follow them. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Signed-off-by: Stephen Boyd +(cherry picked from commit 4f61d8e220c110de90a02736ceb55e1e398d6be7) +--- + drivers/clk/Makefile | 1 - + drivers/clk/bcm/Makefile | 1 + + drivers/clk/bcm/clk-bcm2835.c | 55 +++++++++++++++++++++++++++++++++++++++++++ + drivers/clk/clk-bcm2835.c | 55 ------------------------------------------- + 4 files changed, 56 insertions(+), 56 deletions(-) + create mode 100644 drivers/clk/bcm/clk-bcm2835.c + delete mode 100644 drivers/clk/clk-bcm2835.c + +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index f949266..4178cd7 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -19,7 +19,6 @@ endif + obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o + obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o + obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o +-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o + obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o + obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o + obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile +index 6297d05..72e245e 100644 +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o ++obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +new file mode 100644 +index 0000000..dd295e4 +--- /dev/null ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2010 Broadcom ++ * Copyright (C) 2012 Stephen Warren ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * These are fixed clocks. They're probably not all root clocks and it may ++ * be possible to turn them on and off but until this is mapped out better ++ * it's the only way they can be used. ++ */ ++void __init bcm2835_init_clocks(void) ++{ ++ struct clk *clk; ++ int ret; ++ ++ clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, ++ 126000000); ++ if (IS_ERR(clk)) ++ pr_err("apb_pclk not registered\n"); ++ ++ clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, ++ 3000000); ++ if (IS_ERR(clk)) ++ pr_err("uart0_pclk not registered\n"); ++ ret = clk_register_clkdev(clk, NULL, "20201000.uart"); ++ if (ret) ++ pr_err("uart0_pclk alias not registered\n"); ++ ++ clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, ++ 125000000); ++ if (IS_ERR(clk)) ++ pr_err("uart1_pclk not registered\n"); ++ ret = clk_register_clkdev(clk, NULL, "20215000.uart"); ++ if (ret) ++ pr_err("uart1_pclk alias not registered\n"); ++} +diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c +deleted file mode 100644 +index dd295e4..0000000 +--- a/drivers/clk/clk-bcm2835.c ++++ /dev/null +@@ -1,55 +0,0 @@ +-/* +- * Copyright (C) 2010 Broadcom +- * Copyright (C) 2012 Stephen Warren +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * 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, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +-#include +-#include +-#include +-#include +- +-/* +- * These are fixed clocks. They're probably not all root clocks and it may +- * be possible to turn them on and off but until this is mapped out better +- * it's the only way they can be used. +- */ +-void __init bcm2835_init_clocks(void) +-{ +- struct clk *clk; +- int ret; +- +- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, +- 126000000); +- if (IS_ERR(clk)) +- pr_err("apb_pclk not registered\n"); +- +- clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, +- 3000000); +- if (IS_ERR(clk)) +- pr_err("uart0_pclk not registered\n"); +- ret = clk_register_clkdev(clk, NULL, "20201000.uart"); +- if (ret) +- pr_err("uart0_pclk alias not registered\n"); +- +- clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, +- 125000000); +- if (IS_ERR(clk)) +- pr_err("uart1_pclk not registered\n"); +- ret = clk_register_clkdev(clk, NULL, "20215000.uart"); +- if (ret) +- pr_err("uart1_pclk alias not registered\n"); +-} + +From 5fc3660811e8ca66fea484858bb9555db0f87dce Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 28 Sep 2015 14:22:03 -0700 +Subject: [PATCH 234/278] clk: bcm2835: Add binding docs for the new platform + clock driver. + +Previously we've only supported a few fixed clocks based on +assumptions about how the firmware sets up the clocks, but this +binding will let us control the actual (audio power domain) clock +manager. + +Signed-off-by: Eric Anholt +Acked-by: Stephen Warren +Acked-by: Lee Jones +Signed-off-by: Stephen Boyd +(cherry picked from commit 2c74b5399de730e3155dc3d5a8ad041fba5e93f4) +--- + .../bindings/clock/brcm,bcm2835-cprman.txt | 45 +++++++++++++++++++++ + include/dt-bindings/clock/bcm2835.h | 47 ++++++++++++++++++++++ + 2 files changed, 92 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt + create mode 100644 include/dt-bindings/clock/bcm2835.h + +diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +new file mode 100644 +index 0000000..e56a1df +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt +@@ -0,0 +1,45 @@ ++Broadcom BCM2835 CPRMAN clocks ++ ++This binding uses the common clock binding: ++ Documentation/devicetree/bindings/clock/clock-bindings.txt ++ ++The CPRMAN clock controller generates clocks in the audio power domain ++of the BCM2835. There is a level of PLLs deriving from an external ++oscillator, a level of PLL dividers that produce channels off of the ++few PLLs, and a level of mostly-generic clock generators sourcing from ++the PLL channels. Most other hardware components source from the ++clock generators, but a few (like the ARM or HDMI) will source from ++the PLL dividers directly. ++ ++Required properties: ++- compatible: Should be "brcm,bcm2835-cprman" ++- #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 ++ ++Example: ++ ++ clk_osc: clock@3 { ++ compatible = "fixed-clock"; ++ reg = <3>; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <19200000>; ++ }; ++ ++ clocks: cprman@7e101000 { ++ compatible = "brcm,bcm2835-cprman"; ++ #clock-cells = <1>; ++ reg = <0x7e101000 0x2000>; ++ clocks = <&clk_osc>; ++ }; ++ ++ i2c0: i2c@7e205000 { ++ compatible = "brcm,bcm2835-i2c"; ++ reg = <0x7e205000 0x1000>; ++ interrupts = <2 21>; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; +diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h +new file mode 100644 +index 0000000..d323efa +--- /dev/null ++++ b/include/dt-bindings/clock/bcm2835.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2015 Broadcom Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#define BCM2835_PLLA 0 ++#define BCM2835_PLLB 1 ++#define BCM2835_PLLC 2 ++#define BCM2835_PLLD 3 ++#define BCM2835_PLLH 4 ++ ++#define BCM2835_PLLA_CORE 5 ++#define BCM2835_PLLA_PER 6 ++#define BCM2835_PLLB_ARM 7 ++#define BCM2835_PLLC_CORE0 8 ++#define BCM2835_PLLC_CORE1 9 ++#define BCM2835_PLLC_CORE2 10 ++#define BCM2835_PLLC_PER 11 ++#define BCM2835_PLLD_CORE 12 ++#define BCM2835_PLLD_PER 13 ++#define BCM2835_PLLH_RCAL 14 ++#define BCM2835_PLLH_AUX 15 ++#define BCM2835_PLLH_PIX 16 ++ ++#define BCM2835_CLOCK_TIMER 17 ++#define BCM2835_CLOCK_OTP 18 ++#define BCM2835_CLOCK_UART 19 ++#define BCM2835_CLOCK_VPU 20 ++#define BCM2835_CLOCK_V3D 21 ++#define BCM2835_CLOCK_ISP 22 ++#define BCM2835_CLOCK_H264 23 ++#define BCM2835_CLOCK_VEC 24 ++#define BCM2835_CLOCK_HSM 25 ++#define BCM2835_CLOCK_SDRAM 26 ++#define BCM2835_CLOCK_TSENS 27 ++#define BCM2835_CLOCK_EMMC 28 ++#define BCM2835_CLOCK_PERI_IMAGE 29 ++ ++#define BCM2835_CLOCK_COUNT 30 + +From 5e9322dc0a21cdc378336d47ae869a6fc139e439 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 8 Oct 2015 18:37:24 -0700 +Subject: [PATCH 235/278] clk: bcm2835: Add support for programming the audio + domain clocks + +This adds support for enabling, disabling, and setting the rate of the +audio domain clocks. It will be necessary for setting the pixel clock +for HDMI in the VC4 driver and let us write a cpufreq driver. It will +also improve compatibility with user changes to the firmware's +config.txt, since our previous fixed clocks are unaware of it. + +The firmware also has support for configuring the clocks through the +mailbox channel, but the pixel clock setup by the firmware doesn't +work, and it's Raspberry Pi specific anyway. The only conflicts we +should have with the firmware would be if we made firmware calls that +result in clock management (like opening firmware V3D or ISP access, +which we don't support in upstream), or on hardware over-thermal or +under-voltage (when the firmware would rewrite PLLB to take the ARM +out of overclock). If that happens, our cached .recalc_rate() results +would be incorrect, but that's no worse than our current state where +we used fixed clocks. + +The existing fixed clocks in the code are left in place to provide +backwards compatibility with old device tree files. + +Signed-off-by: Eric Anholt +Tested-by: Martin Sperl +Acked-by: Stephen Warren +Signed-off-by: Stephen Boyd +(cherry picked from commit 41691b8862e2a32080306f17a723efc4b6ca86ab) +--- + drivers/clk/bcm/clk-bcm2835.c | 1528 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 1527 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index dd295e4..6c9b2e8 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2010 Broadcom ++ * Copyright (C) 2010,2015 Broadcom + * Copyright (C) 2012 Stephen Warren + * + * This program is free software; you can redistribute it and/or modify +@@ -17,10 +17,295 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++/** ++ * DOC: BCM2835 CPRMAN (clock manager for the "audio" domain) ++ * ++ * The clock tree on the 2835 has several levels. There's a root ++ * oscillator running at 19.2Mhz. After the oscillator there are 5 ++ * PLLs, roughly divided as "camera", "ARM", "core", "DSI displays", ++ * and "HDMI displays". Those 5 PLLs each can divide their output to ++ * produce up to 4 channels. Finally, there is the level of clocks to ++ * be consumed by other hardware components (like "H264" or "HDMI ++ * state machine"), which divide off of some subset of the PLL ++ * channels. ++ * ++ * All of the clocks in the tree are exposed in the DT, because the DT ++ * may want to make assignments of the final layer of clocks to the ++ * PLL channels, and some components of the hardware will actually ++ * skip layers of the tree (for example, the pixel clock comes ++ * directly from the PLLH PIX channel without using a CM_*CTL clock ++ * generator). ++ */ ++ + #include + #include + #include ++#include + #include ++#include ++#include ++#include ++ ++#define CM_PASSWORD 0x5a000000 ++ ++#define CM_GNRICCTL 0x000 ++#define CM_GNRICDIV 0x004 ++# define CM_DIV_FRAC_BITS 12 ++ ++#define CM_VPUCTL 0x008 ++#define CM_VPUDIV 0x00c ++#define CM_SYSCTL 0x010 ++#define CM_SYSDIV 0x014 ++#define CM_PERIACTL 0x018 ++#define CM_PERIADIV 0x01c ++#define CM_PERIICTL 0x020 ++#define CM_PERIIDIV 0x024 ++#define CM_H264CTL 0x028 ++#define CM_H264DIV 0x02c ++#define CM_ISPCTL 0x030 ++#define CM_ISPDIV 0x034 ++#define CM_V3DCTL 0x038 ++#define CM_V3DDIV 0x03c ++#define CM_CAM0CTL 0x040 ++#define CM_CAM0DIV 0x044 ++#define CM_CAM1CTL 0x048 ++#define CM_CAM1DIV 0x04c ++#define CM_CCP2CTL 0x050 ++#define CM_CCP2DIV 0x054 ++#define CM_DSI0ECTL 0x058 ++#define CM_DSI0EDIV 0x05c ++#define CM_DSI0PCTL 0x060 ++#define CM_DSI0PDIV 0x064 ++#define CM_DPICTL 0x068 ++#define CM_DPIDIV 0x06c ++#define CM_GP0CTL 0x070 ++#define CM_GP0DIV 0x074 ++#define CM_GP1CTL 0x078 ++#define CM_GP1DIV 0x07c ++#define CM_GP2CTL 0x080 ++#define CM_GP2DIV 0x084 ++#define CM_HSMCTL 0x088 ++#define CM_HSMDIV 0x08c ++#define CM_OTPCTL 0x090 ++#define CM_OTPDIV 0x094 ++#define CM_PWMCTL 0x0a0 ++#define CM_PWMDIV 0x0a4 ++#define CM_SMICTL 0x0b0 ++#define CM_SMIDIV 0x0b4 ++#define CM_TSENSCTL 0x0e0 ++#define CM_TSENSDIV 0x0e4 ++#define CM_TIMERCTL 0x0e8 ++#define CM_TIMERDIV 0x0ec ++#define CM_UARTCTL 0x0f0 ++#define CM_UARTDIV 0x0f4 ++#define CM_VECCTL 0x0f8 ++#define CM_VECDIV 0x0fc ++#define CM_PULSECTL 0x190 ++#define CM_PULSEDIV 0x194 ++#define CM_SDCCTL 0x1a8 ++#define CM_SDCDIV 0x1ac ++#define CM_ARMCTL 0x1b0 ++#define CM_EMMCCTL 0x1c0 ++#define CM_EMMCDIV 0x1c4 ++ ++/* General bits for the CM_*CTL regs */ ++# define CM_ENABLE BIT(4) ++# define CM_KILL BIT(5) ++# define CM_GATE_BIT 6 ++# define CM_GATE BIT(CM_GATE_BIT) ++# define CM_BUSY BIT(7) ++# define CM_BUSYD BIT(8) ++# define CM_SRC_SHIFT 0 ++# define CM_SRC_BITS 4 ++# define CM_SRC_MASK 0xf ++# define CM_SRC_GND 0 ++# define CM_SRC_OSC 1 ++# define CM_SRC_TESTDEBUG0 2 ++# define CM_SRC_TESTDEBUG1 3 ++# define CM_SRC_PLLA_CORE 4 ++# define CM_SRC_PLLA_PER 4 ++# define CM_SRC_PLLC_CORE0 5 ++# define CM_SRC_PLLC_PER 5 ++# define CM_SRC_PLLC_CORE1 8 ++# define CM_SRC_PLLD_CORE 6 ++# define CM_SRC_PLLD_PER 6 ++# define CM_SRC_PLLH_AUX 7 ++# define CM_SRC_PLLC_CORE1 8 ++# define CM_SRC_PLLC_CORE2 9 ++ ++#define CM_OSCCOUNT 0x100 ++ ++#define CM_PLLA 0x104 ++# define CM_PLL_ANARST BIT(8) ++# define CM_PLLA_HOLDPER BIT(7) ++# define CM_PLLA_LOADPER BIT(6) ++# define CM_PLLA_HOLDCORE BIT(5) ++# define CM_PLLA_LOADCORE BIT(4) ++# define CM_PLLA_HOLDCCP2 BIT(3) ++# define CM_PLLA_LOADCCP2 BIT(2) ++# define CM_PLLA_HOLDDSI0 BIT(1) ++# define CM_PLLA_LOADDSI0 BIT(0) ++ ++#define CM_PLLC 0x108 ++# define CM_PLLC_HOLDPER BIT(7) ++# define CM_PLLC_LOADPER BIT(6) ++# define CM_PLLC_HOLDCORE2 BIT(5) ++# define CM_PLLC_LOADCORE2 BIT(4) ++# define CM_PLLC_HOLDCORE1 BIT(3) ++# define CM_PLLC_LOADCORE1 BIT(2) ++# define CM_PLLC_HOLDCORE0 BIT(1) ++# define CM_PLLC_LOADCORE0 BIT(0) ++ ++#define CM_PLLD 0x10c ++# define CM_PLLD_HOLDPER BIT(7) ++# define CM_PLLD_LOADPER BIT(6) ++# define CM_PLLD_HOLDCORE BIT(5) ++# define CM_PLLD_LOADCORE BIT(4) ++# define CM_PLLD_HOLDDSI1 BIT(3) ++# define CM_PLLD_LOADDSI1 BIT(2) ++# define CM_PLLD_HOLDDSI0 BIT(1) ++# define CM_PLLD_LOADDSI0 BIT(0) ++ ++#define CM_PLLH 0x110 ++# define CM_PLLH_LOADRCAL BIT(2) ++# define CM_PLLH_LOADAUX BIT(1) ++# define CM_PLLH_LOADPIX BIT(0) ++ ++#define CM_LOCK 0x114 ++# define CM_LOCK_FLOCKH BIT(12) ++# define CM_LOCK_FLOCKD BIT(11) ++# define CM_LOCK_FLOCKC BIT(10) ++# define CM_LOCK_FLOCKB BIT(9) ++# define CM_LOCK_FLOCKA BIT(8) ++ ++#define CM_EVENT 0x118 ++#define CM_DSI1ECTL 0x158 ++#define CM_DSI1EDIV 0x15c ++#define CM_DSI1PCTL 0x160 ++#define CM_DSI1PDIV 0x164 ++#define CM_DFTCTL 0x168 ++#define CM_DFTDIV 0x16c ++ ++#define CM_PLLB 0x170 ++# define CM_PLLB_HOLDARM BIT(1) ++# define CM_PLLB_LOADARM BIT(0) ++ ++#define A2W_PLLA_CTRL 0x1100 ++#define A2W_PLLC_CTRL 0x1120 ++#define A2W_PLLD_CTRL 0x1140 ++#define A2W_PLLH_CTRL 0x1160 ++#define A2W_PLLB_CTRL 0x11e0 ++# define A2W_PLL_CTRL_PRST_DISABLE BIT(17) ++# define A2W_PLL_CTRL_PWRDN BIT(16) ++# define A2W_PLL_CTRL_PDIV_MASK 0x000007000 ++# define A2W_PLL_CTRL_PDIV_SHIFT 12 ++# define A2W_PLL_CTRL_NDIV_MASK 0x0000003ff ++# define A2W_PLL_CTRL_NDIV_SHIFT 0 ++ ++#define A2W_PLLA_ANA0 0x1010 ++#define A2W_PLLC_ANA0 0x1030 ++#define A2W_PLLD_ANA0 0x1050 ++#define A2W_PLLH_ANA0 0x1070 ++#define A2W_PLLB_ANA0 0x10f0 ++ ++#define A2W_PLL_KA_SHIFT 7 ++#define A2W_PLL_KA_MASK GENMASK(9, 7) ++#define A2W_PLL_KI_SHIFT 19 ++#define A2W_PLL_KI_MASK GENMASK(21, 19) ++#define A2W_PLL_KP_SHIFT 15 ++#define A2W_PLL_KP_MASK GENMASK(18, 15) ++ ++#define A2W_PLLH_KA_SHIFT 19 ++#define A2W_PLLH_KA_MASK GENMASK(21, 19) ++#define A2W_PLLH_KI_LOW_SHIFT 22 ++#define A2W_PLLH_KI_LOW_MASK GENMASK(23, 22) ++#define A2W_PLLH_KI_HIGH_SHIFT 0 ++#define A2W_PLLH_KI_HIGH_MASK GENMASK(0, 0) ++#define A2W_PLLH_KP_SHIFT 1 ++#define A2W_PLLH_KP_MASK GENMASK(4, 1) ++ ++#define A2W_XOSC_CTRL 0x1190 ++# define A2W_XOSC_CTRL_PLLB_ENABLE BIT(7) ++# define A2W_XOSC_CTRL_PLLA_ENABLE BIT(6) ++# define A2W_XOSC_CTRL_PLLD_ENABLE BIT(5) ++# define A2W_XOSC_CTRL_DDR_ENABLE BIT(4) ++# define A2W_XOSC_CTRL_CPR1_ENABLE BIT(3) ++# define A2W_XOSC_CTRL_USB_ENABLE BIT(2) ++# define A2W_XOSC_CTRL_HDMI_ENABLE BIT(1) ++# define A2W_XOSC_CTRL_PLLC_ENABLE BIT(0) ++ ++#define A2W_PLLA_FRAC 0x1200 ++#define A2W_PLLC_FRAC 0x1220 ++#define A2W_PLLD_FRAC 0x1240 ++#define A2W_PLLH_FRAC 0x1260 ++#define A2W_PLLB_FRAC 0x12e0 ++# define A2W_PLL_FRAC_MASK ((1 << A2W_PLL_FRAC_BITS) - 1) ++# define A2W_PLL_FRAC_BITS 20 ++ ++#define A2W_PLL_CHANNEL_DISABLE BIT(8) ++#define A2W_PLL_DIV_BITS 8 ++#define A2W_PLL_DIV_SHIFT 0 ++ ++#define A2W_PLLA_DSI0 0x1300 ++#define A2W_PLLA_CORE 0x1400 ++#define A2W_PLLA_PER 0x1500 ++#define A2W_PLLA_CCP2 0x1600 ++ ++#define A2W_PLLC_CORE2 0x1320 ++#define A2W_PLLC_CORE1 0x1420 ++#define A2W_PLLC_PER 0x1520 ++#define A2W_PLLC_CORE0 0x1620 ++ ++#define A2W_PLLD_DSI0 0x1340 ++#define A2W_PLLD_CORE 0x1440 ++#define A2W_PLLD_PER 0x1540 ++#define A2W_PLLD_DSI1 0x1640 ++ ++#define A2W_PLLH_AUX 0x1360 ++#define A2W_PLLH_RCAL 0x1460 ++#define A2W_PLLH_PIX 0x1560 ++#define A2W_PLLH_STS 0x1660 ++ ++#define A2W_PLLH_CTRLR 0x1960 ++#define A2W_PLLH_FRACR 0x1a60 ++#define A2W_PLLH_AUXR 0x1b60 ++#define A2W_PLLH_RCALR 0x1c60 ++#define A2W_PLLH_PIXR 0x1d60 ++#define A2W_PLLH_STSR 0x1e60 ++ ++#define A2W_PLLB_ARM 0x13e0 ++#define A2W_PLLB_SP0 0x14e0 ++#define A2W_PLLB_SP1 0x15e0 ++#define A2W_PLLB_SP2 0x16e0 ++ ++#define LOCK_TIMEOUT_NS 100000000 ++#define BCM2835_MAX_FB_RATE 1750000000u ++ ++struct bcm2835_cprman { ++ struct device *dev; ++ void __iomem *regs; ++ spinlock_t regs_lock; ++ const char *osc_name; ++ ++ struct clk_onecell_data onecell; ++ struct clk *clks[BCM2835_CLOCK_COUNT]; ++}; ++ ++/* Backport for 4.1's clk core, see . */ ++static inline const char *clk_hw_get_name(struct clk_hw *hw) ++{ ++ return __clk_get_name(hw->clk); ++} ++ ++static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val) ++{ ++ writel(CM_PASSWORD | val, cprman->regs + reg); ++} ++ ++static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) ++{ ++ return readl(cprman->regs + reg); ++} + + /* + * These are fixed clocks. They're probably not all root clocks and it may +@@ -53,3 +338,1244 @@ void __init bcm2835_init_clocks(void) + if (ret) + pr_err("uart1_pclk alias not registered\n"); + } ++ ++struct bcm2835_pll_data { ++ const char *name; ++ u32 cm_ctrl_reg; ++ u32 a2w_ctrl_reg; ++ u32 frac_reg; ++ u32 ana_reg_base; ++ u32 reference_enable_mask; ++ /* Bit in CM_LOCK to indicate when the PLL has locked. */ ++ u32 lock_mask; ++ ++ const struct bcm2835_pll_ana_bits *ana; ++ ++ unsigned long min_rate; ++ unsigned long max_rate; ++ /* ++ * Highest rate for the VCO before we have to use the ++ * pre-divide-by-2. ++ */ ++ unsigned long max_fb_rate; ++}; ++ ++struct bcm2835_pll_ana_bits { ++ u32 mask0; ++ u32 set0; ++ u32 mask1; ++ u32 set1; ++ u32 mask3; ++ u32 set3; ++ u32 fb_prediv_mask; ++}; ++ ++static const struct bcm2835_pll_ana_bits bcm2835_ana_default = { ++ .mask0 = 0, ++ .set0 = 0, ++ .mask1 = ~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK), ++ .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), ++ .mask3 = ~A2W_PLL_KA_MASK, ++ .set3 = (2 << A2W_PLL_KA_SHIFT), ++ .fb_prediv_mask = BIT(14), ++}; ++ ++static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { ++ .mask0 = ~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK), ++ .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), ++ .mask1 = ~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK), ++ .set1 = (6 << A2W_PLLH_KP_SHIFT), ++ .mask3 = 0, ++ .set3 = 0, ++ .fb_prediv_mask = BIT(11), ++}; ++ ++/* ++ * PLLA is the auxiliary PLL, used to drive the CCP2 (Compact Camera ++ * Port 2) transmitter clock. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++ */ ++static const struct bcm2835_pll_data bcm2835_plla_data = { ++ .name = "plla", ++ .cm_ctrl_reg = CM_PLLA, ++ .a2w_ctrl_reg = A2W_PLLA_CTRL, ++ .frac_reg = A2W_PLLA_FRAC, ++ .ana_reg_base = A2W_PLLA_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKA, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 2400000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* PLLB is used for the ARM's clock. */ ++static const struct bcm2835_pll_data bcm2835_pllb_data = { ++ .name = "pllb", ++ .cm_ctrl_reg = CM_PLLB, ++ .a2w_ctrl_reg = A2W_PLLB_CTRL, ++ .frac_reg = A2W_PLLB_FRAC, ++ .ana_reg_base = A2W_PLLB_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKB, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLC is the core PLL, used to drive the core VPU clock. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++*/ ++static const struct bcm2835_pll_data bcm2835_pllc_data = { ++ .name = "pllc", ++ .cm_ctrl_reg = CM_PLLC, ++ .a2w_ctrl_reg = A2W_PLLC_CTRL, ++ .frac_reg = A2W_PLLC_FRAC, ++ .ana_reg_base = A2W_PLLC_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKC, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLD is the display PLL, used to drive DSI display panels. ++ * ++ * It is in the PX LDO power domain, which is on when the AUDIO domain ++ * is on. ++ */ ++static const struct bcm2835_pll_data bcm2835_plld_data = { ++ .name = "plld", ++ .cm_ctrl_reg = CM_PLLD, ++ .a2w_ctrl_reg = A2W_PLLD_CTRL, ++ .frac_reg = A2W_PLLD_FRAC, ++ .ana_reg_base = A2W_PLLD_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKD, ++ ++ .ana = &bcm2835_ana_default, ++ ++ .min_rate = 600000000u, ++ .max_rate = 2400000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++/* ++ * PLLH is used to supply the pixel clock or the AUX clock for the TV ++ * encoder. ++ * ++ * It is in the HDMI power domain. ++ */ ++static const struct bcm2835_pll_data bcm2835_pllh_data = { ++ "pllh", ++ .cm_ctrl_reg = CM_PLLH, ++ .a2w_ctrl_reg = A2W_PLLH_CTRL, ++ .frac_reg = A2W_PLLH_FRAC, ++ .ana_reg_base = A2W_PLLH_ANA0, ++ .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, ++ .lock_mask = CM_LOCK_FLOCKH, ++ ++ .ana = &bcm2835_ana_pllh, ++ ++ .min_rate = 600000000u, ++ .max_rate = 3000000000u, ++ .max_fb_rate = BCM2835_MAX_FB_RATE, ++}; ++ ++struct bcm2835_pll_divider_data { ++ const char *name; ++ const struct bcm2835_pll_data *source_pll; ++ u32 cm_reg; ++ u32 a2w_reg; ++ ++ u32 load_mask; ++ u32 hold_mask; ++ u32 fixed_divider; ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plla_core_data = { ++ .name = "plla_core", ++ .source_pll = &bcm2835_plla_data, ++ .cm_reg = CM_PLLA, ++ .a2w_reg = A2W_PLLA_CORE, ++ .load_mask = CM_PLLA_LOADCORE, ++ .hold_mask = CM_PLLA_HOLDCORE, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plla_per_data = { ++ .name = "plla_per", ++ .source_pll = &bcm2835_plla_data, ++ .cm_reg = CM_PLLA, ++ .a2w_reg = A2W_PLLA_PER, ++ .load_mask = CM_PLLA_LOADPER, ++ .hold_mask = CM_PLLA_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllb_arm_data = { ++ .name = "pllb_arm", ++ .source_pll = &bcm2835_pllb_data, ++ .cm_reg = CM_PLLB, ++ .a2w_reg = A2W_PLLB_ARM, ++ .load_mask = CM_PLLB_LOADARM, ++ .hold_mask = CM_PLLB_HOLDARM, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core0_data = { ++ .name = "pllc_core0", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_CORE0, ++ .load_mask = CM_PLLC_LOADCORE0, ++ .hold_mask = CM_PLLC_HOLDCORE0, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core1_data = { ++ .name = "pllc_core1", .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, A2W_PLLC_CORE1, ++ .load_mask = CM_PLLC_LOADCORE1, ++ .hold_mask = CM_PLLC_HOLDCORE1, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_core2_data = { ++ .name = "pllc_core2", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_CORE2, ++ .load_mask = CM_PLLC_LOADCORE2, ++ .hold_mask = CM_PLLC_HOLDCORE2, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllc_per_data = { ++ .name = "pllc_per", ++ .source_pll = &bcm2835_pllc_data, ++ .cm_reg = CM_PLLC, ++ .a2w_reg = A2W_PLLC_PER, ++ .load_mask = CM_PLLC_LOADPER, ++ .hold_mask = CM_PLLC_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plld_core_data = { ++ .name = "plld_core", ++ .source_pll = &bcm2835_plld_data, ++ .cm_reg = CM_PLLD, ++ .a2w_reg = A2W_PLLD_CORE, ++ .load_mask = CM_PLLD_LOADCORE, ++ .hold_mask = CM_PLLD_HOLDCORE, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_plld_per_data = { ++ .name = "plld_per", ++ .source_pll = &bcm2835_plld_data, ++ .cm_reg = CM_PLLD, ++ .a2w_reg = A2W_PLLD_PER, ++ .load_mask = CM_PLLD_LOADPER, ++ .hold_mask = CM_PLLD_HOLDPER, ++ .fixed_divider = 1, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_rcal_data = { ++ .name = "pllh_rcal", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_RCAL, ++ .load_mask = CM_PLLH_LOADRCAL, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_aux_data = { ++ .name = "pllh_aux", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_AUX, ++ .load_mask = CM_PLLH_LOADAUX, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++static const struct bcm2835_pll_divider_data bcm2835_pllh_pix_data = { ++ .name = "pllh_pix", ++ .source_pll = &bcm2835_pllh_data, ++ .cm_reg = CM_PLLH, ++ .a2w_reg = A2W_PLLH_PIX, ++ .load_mask = CM_PLLH_LOADPIX, ++ .hold_mask = 0, ++ .fixed_divider = 10, ++}; ++ ++struct bcm2835_clock_data { ++ const char *name; ++ ++ const char *const *parents; ++ int num_mux_parents; ++ ++ u32 ctl_reg; ++ u32 div_reg; ++ ++ /* Number of integer bits in the divider */ ++ u32 int_bits; ++ /* Number of fractional bits in the divider */ ++ u32 frac_bits; ++ ++ bool is_vpu_clock; ++}; ++ ++static const char *const bcm2835_clock_per_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "plla_per", ++ "pllc_per", ++ "plld_per", ++ "pllh_aux", ++}; ++ ++static const char *const bcm2835_clock_vpu_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1", ++ "plla_core", ++ "pllc_core0", ++ "plld_core", ++ "pllh_aux", ++ "pllc_core1", ++ "pllc_core2", ++}; ++ ++static const char *const bcm2835_clock_osc_parents[] = { ++ "gnd", ++ "xosc", ++ "testdebug0", ++ "testdebug1" ++}; ++ ++/* ++ * Used for a 1Mhz clock for the system clocksource, and also used by ++ * the watchdog timer and the camera pulse generator. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_timer_data = { ++ .name = "timer", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_TIMERCTL, ++ .div_reg = CM_TIMERDIV, ++ .int_bits = 6, ++ .frac_bits = 12, ++}; ++ ++/* One Time Programmable Memory clock. Maximum 10Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_otp_data = { ++ .name = "otp", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_OTPCTL, ++ .div_reg = CM_OTPDIV, ++ .int_bits = 4, ++ .frac_bits = 0, ++}; ++ ++/* ++ * 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 to be ++ * gated for rate changes. It is also known as "clk_audio" in various ++ * hardware documentation. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_vpu_data = { ++ .name = "vpu", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_VPUCTL, ++ .div_reg = CM_VPUDIV, ++ .int_bits = 12, ++ .frac_bits = 8, ++ .is_vpu_clock = true, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_v3d_data = { ++ .name = "v3d", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_V3DCTL, ++ .div_reg = CM_V3DDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_isp_data = { ++ .name = "isp", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_ISPCTL, ++ .div_reg = CM_ISPDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_h264_data = { ++ .name = "h264", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_H264CTL, ++ .div_reg = CM_H264DIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++/* TV encoder clock. Only operating frequency is 108Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_vec_data = { ++ .name = "vec", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_VECCTL, ++ .div_reg = CM_VECDIV, ++ .int_bits = 4, ++ .frac_bits = 0, ++}; ++ ++static const struct bcm2835_clock_data bcm2835_clock_uart_data = { ++ .name = "uart", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_UARTCTL, ++ .div_reg = CM_UARTDIV, ++ .int_bits = 10, ++ .frac_bits = 12, ++}; ++ ++/* HDMI state machine */ ++static const struct bcm2835_clock_data bcm2835_clock_hsm_data = { ++ .name = "hsm", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_HSMCTL, ++ .div_reg = CM_HSMDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++/* ++ * Secondary SDRAM clock. Used for low-voltage modes when the PLL in ++ * the SDRAM controller can't be used. ++ */ ++static const struct bcm2835_clock_data bcm2835_clock_sdram_data = { ++ .name = "sdram", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), ++ .parents = bcm2835_clock_vpu_parents, ++ .ctl_reg = CM_SDCCTL, ++ .div_reg = CM_SDCDIV, ++ .int_bits = 6, ++ .frac_bits = 0, ++}; ++ ++/* Clock for the temperature sensor. Generally run at 2Mhz, max 5Mhz. */ ++static const struct bcm2835_clock_data bcm2835_clock_tsens_data = { ++ .name = "tsens", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), ++ .parents = bcm2835_clock_osc_parents, ++ .ctl_reg = CM_TSENSCTL, ++ .div_reg = CM_TSENSDIV, ++ .int_bits = 5, ++ .frac_bits = 0, ++}; ++ ++/* Arasan EMMC clock */ ++static const struct bcm2835_clock_data bcm2835_clock_emmc_data = { ++ .name = "emmc", ++ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), ++ .parents = bcm2835_clock_per_parents, ++ .ctl_reg = CM_EMMCCTL, ++ .div_reg = CM_EMMCDIV, ++ .int_bits = 4, ++ .frac_bits = 8, ++}; ++ ++struct bcm2835_pll { ++ struct clk_hw hw; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_pll_data *data; ++}; ++ ++static int bcm2835_pll_is_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ++ return cprman_read(cprman, data->a2w_ctrl_reg) & ++ A2W_PLL_CTRL_PRST_DISABLE; ++} ++ ++static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate, ++ unsigned long parent_rate, ++ u32 *ndiv, u32 *fdiv) ++{ ++ u64 div; ++ ++ div = (u64)rate << A2W_PLL_FRAC_BITS; ++ do_div(div, parent_rate); ++ ++ *ndiv = div >> A2W_PLL_FRAC_BITS; ++ *fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1); ++} ++ ++static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate, ++ u32 ndiv, u32 fdiv, u32 pdiv) ++{ ++ u64 rate; ++ ++ if (pdiv == 0) ++ return 0; ++ ++ rate = (u64)parent_rate * ((ndiv << A2W_PLL_FRAC_BITS) + fdiv); ++ do_div(rate, pdiv); ++ return rate >> A2W_PLL_FRAC_BITS; ++} ++ ++static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ u32 ndiv, fdiv; ++ ++ bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); ++ ++ return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); ++} ++ ++static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ u32 a2wctrl = cprman_read(cprman, data->a2w_ctrl_reg); ++ u32 ndiv, pdiv, fdiv; ++ bool using_prediv; ++ ++ if (parent_rate == 0) ++ return 0; ++ ++ fdiv = cprman_read(cprman, data->frac_reg) & A2W_PLL_FRAC_MASK; ++ ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; ++ pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; ++ using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & ++ data->ana->fb_prediv_mask; ++ ++ if (using_prediv) ++ ndiv *= 2; ++ ++ return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); ++} ++ ++static void bcm2835_pll_off(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ++ cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); ++ cprman_write(cprman, data->a2w_ctrl_reg, A2W_PLL_CTRL_PWRDN); ++} ++ ++static int bcm2835_pll_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ ktime_t timeout; ++ ++ /* Take the PLL out of reset. */ ++ cprman_write(cprman, data->cm_ctrl_reg, ++ cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); ++ ++ /* Wait for the PLL to lock. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "%s: couldn't lock PLL\n", ++ clk_hw_get_name(hw)); ++ return -ETIMEDOUT; ++ } ++ ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++ ++static void ++bcm2835_pll_write_ana(struct bcm2835_cprman *cprman, u32 ana_reg_base, u32 *ana) ++{ ++ int i; ++ ++ /* ++ * ANA register setup is done as a series of writes to ++ * ANA3-ANA0, in that order. This lets us write all 4 ++ * registers as a single cycle of the serdes interface (taking ++ * 100 xosc clocks), whereas if we were to update ana0, 1, and ++ * 3 individually through their partial-write registers, each ++ * would be their own serdes cycle. ++ */ ++ for (i = 3; i >= 0; i--) ++ cprman_write(cprman, ana_reg_base + i * 4, ana[i]); ++} ++ ++static int bcm2835_pll_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); ++ struct bcm2835_cprman *cprman = pll->cprman; ++ const struct bcm2835_pll_data *data = pll->data; ++ bool was_using_prediv, use_fb_prediv, do_ana_setup_first; ++ u32 ndiv, fdiv, a2w_ctl; ++ u32 ana[4]; ++ int i; ++ ++ if (rate < data->min_rate || rate > data->max_rate) { ++ dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n", ++ clk_hw_get_name(hw), rate, ++ data->min_rate, data->max_rate); ++ return -EINVAL; ++ } ++ ++ if (rate > data->max_fb_rate) { ++ use_fb_prediv = true; ++ rate /= 2; ++ } else { ++ use_fb_prediv = false; ++ } ++ ++ bcm2835_pll_choose_ndiv_and_fdiv(rate, parent_rate, &ndiv, &fdiv); ++ ++ for (i = 3; i >= 0; i--) ++ ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); ++ ++ was_using_prediv = ana[1] & data->ana->fb_prediv_mask; ++ ++ ana[0] &= ~data->ana->mask0; ++ ana[0] |= data->ana->set0; ++ ana[1] &= ~data->ana->mask1; ++ ana[1] |= data->ana->set1; ++ ana[3] &= ~data->ana->mask3; ++ ana[3] |= data->ana->set3; ++ ++ if (was_using_prediv && !use_fb_prediv) { ++ ana[1] &= ~data->ana->fb_prediv_mask; ++ do_ana_setup_first = true; ++ } else if (!was_using_prediv && use_fb_prediv) { ++ ana[1] |= data->ana->fb_prediv_mask; ++ do_ana_setup_first = false; ++ } else { ++ do_ana_setup_first = true; ++ } ++ ++ /* Unmask the reference clock from the oscillator. */ ++ cprman_write(cprman, A2W_XOSC_CTRL, ++ cprman_read(cprman, A2W_XOSC_CTRL) | ++ data->reference_enable_mask); ++ ++ if (do_ana_setup_first) ++ bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); ++ ++ /* Set the PLL multiplier from the oscillator. */ ++ cprman_write(cprman, data->frac_reg, fdiv); ++ ++ a2w_ctl = cprman_read(cprman, data->a2w_ctrl_reg); ++ a2w_ctl &= ~A2W_PLL_CTRL_NDIV_MASK; ++ a2w_ctl |= ndiv << A2W_PLL_CTRL_NDIV_SHIFT; ++ a2w_ctl &= ~A2W_PLL_CTRL_PDIV_MASK; ++ a2w_ctl |= 1 << A2W_PLL_CTRL_PDIV_SHIFT; ++ cprman_write(cprman, data->a2w_ctrl_reg, a2w_ctl); ++ ++ if (!do_ana_setup_first) ++ bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_pll_clk_ops = { ++ .is_prepared = bcm2835_pll_is_on, ++ .prepare = bcm2835_pll_on, ++ .unprepare = bcm2835_pll_off, ++ .recalc_rate = bcm2835_pll_get_rate, ++ .set_rate = bcm2835_pll_set_rate, ++ .round_rate = bcm2835_pll_round_rate, ++}; ++ ++struct bcm2835_pll_divider { ++ struct clk_divider div; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_pll_divider_data *data; ++}; ++ ++static struct bcm2835_pll_divider * ++bcm2835_pll_divider_from_hw(struct clk_hw *hw) ++{ ++ return container_of(hw, struct bcm2835_pll_divider, div.hw); ++} ++ ++static int bcm2835_pll_divider_is_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ return !(cprman_read(cprman, data->a2w_reg) & A2W_PLL_CHANNEL_DISABLE); ++} ++ ++static long bcm2835_pll_divider_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, parent_rate); ++} ++ ++static unsigned long bcm2835_pll_divider_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ u32 div = cprman_read(cprman, data->a2w_reg); ++ ++ div &= (1 << A2W_PLL_DIV_BITS) - 1; ++ if (div == 0) ++ div = 256; ++ ++ return parent_rate / div; ++} ++ ++static void bcm2835_pll_divider_off(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ cprman_write(cprman, data->cm_reg, ++ (cprman_read(cprman, data->cm_reg) & ++ ~data->load_mask) | data->hold_mask); ++ cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE); ++} ++ ++static int bcm2835_pll_divider_on(struct clk_hw *hw) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ ++ cprman_write(cprman, data->a2w_reg, ++ cprman_read(cprman, data->a2w_reg) & ++ ~A2W_PLL_CHANNEL_DISABLE); ++ ++ cprman_write(cprman, data->cm_reg, ++ cprman_read(cprman, data->cm_reg) & ~data->hold_mask); ++ ++ return 0; ++} ++ ++static int bcm2835_pll_divider_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); ++ struct bcm2835_cprman *cprman = divider->cprman; ++ const struct bcm2835_pll_divider_data *data = divider->data; ++ u32 cm; ++ int ret; ++ ++ ret = clk_divider_ops.set_rate(hw, rate, parent_rate); ++ if (ret) ++ return ret; ++ ++ cm = cprman_read(cprman, data->cm_reg); ++ cprman_write(cprman, data->cm_reg, cm | data->load_mask); ++ cprman_write(cprman, data->cm_reg, cm & ~data->load_mask); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_pll_divider_clk_ops = { ++ .is_prepared = bcm2835_pll_divider_is_on, ++ .prepare = bcm2835_pll_divider_on, ++ .unprepare = bcm2835_pll_divider_off, ++ .recalc_rate = bcm2835_pll_divider_get_rate, ++ .set_rate = bcm2835_pll_divider_set_rate, ++ .round_rate = bcm2835_pll_divider_round_rate, ++}; ++ ++/* ++ * The CM dividers do fixed-point division, so we can't use the ++ * generic integer divider code like the PLL dividers do (and we can't ++ * fake it by having some fixed shifts preceding it in the clock tree, ++ * because we'd run out of bits in a 32-bit unsigned long). ++ */ ++struct bcm2835_clock { ++ struct clk_hw hw; ++ struct bcm2835_cprman *cprman; ++ const struct bcm2835_clock_data *data; ++}; ++ ++static struct bcm2835_clock *bcm2835_clock_from_hw(struct clk_hw *hw) ++{ ++ return container_of(hw, struct bcm2835_clock, hw); ++} ++ ++static int bcm2835_clock_is_on(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; ++ ++ return (cprman_read(cprman, data->ctl_reg) & CM_ENABLE) != 0; ++} ++ ++static u32 bcm2835_clock_choose_div(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ const struct bcm2835_clock_data *data = clock->data; ++ u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0); ++ u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS; ++ u32 div; ++ ++ do_div(temp, rate); ++ div = temp; ++ ++ /* Round and mask off the unused bits */ ++ if (unused_frac_mask != 0) { ++ div += unused_frac_mask >> 1; ++ div &= ~unused_frac_mask; ++ } ++ ++ /* Clamp to the limits. */ ++ div = max(div, unused_frac_mask + 1); ++ div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, ++ CM_DIV_FRAC_BITS - data->frac_bits)); ++ ++ return div; ++} ++ ++static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, ++ unsigned long parent_rate, ++ u32 div) ++{ ++ const struct bcm2835_clock_data *data = clock->data; ++ u64 temp; ++ ++ /* ++ * The divisor is a 12.12 fixed point field, but only some of ++ * the bits are populated in any given clock. ++ */ ++ div >>= CM_DIV_FRAC_BITS - data->frac_bits; ++ div &= (1 << (data->int_bits + data->frac_bits)) - 1; ++ ++ if (div == 0) ++ return 0; ++ ++ temp = (u64)parent_rate << data->frac_bits; ++ ++ do_div(temp, div); ++ ++ return temp; ++} ++ ++static long bcm2835_clock_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate); ++ ++ return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div); ++} ++ ++static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ 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); ++ ++ return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); ++} ++ ++static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) ++{ ++ struct bcm2835_cprman *cprman = clock->cprman; ++ const struct bcm2835_clock_data *data = clock->data; ++ ktime_t timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ ++ while (cprman_read(cprman, data->ctl_reg) & CM_BUSY) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "%s: couldn't lock PLL\n", ++ clk_hw_get_name(&clock->hw)); ++ return; ++ } ++ cpu_relax(); ++ } ++} ++ ++static void bcm2835_clock_off(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; ++ ++ spin_lock(&cprman->regs_lock); ++ cprman_write(cprman, data->ctl_reg, ++ cprman_read(cprman, data->ctl_reg) & ~CM_ENABLE); ++ spin_unlock(&cprman->regs_lock); ++ ++ /* BUSY will remain high until the divider completes its cycle. */ ++ bcm2835_clock_wait_busy(clock); ++} ++ ++static int bcm2835_clock_on(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; ++ ++ spin_lock(&cprman->regs_lock); ++ cprman_write(cprman, data->ctl_reg, ++ cprman_read(cprman, data->ctl_reg) | ++ CM_ENABLE | ++ CM_GATE); ++ spin_unlock(&cprman->regs_lock); ++ ++ return 0; ++} ++ ++static int bcm2835_clock_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ 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 = bcm2835_clock_choose_div(hw, rate, parent_rate); ++ ++ cprman_write(cprman, data->div_reg, div); ++ ++ return 0; ++} ++ ++static const struct clk_ops bcm2835_clock_clk_ops = { ++ .is_prepared = bcm2835_clock_is_on, ++ .prepare = bcm2835_clock_on, ++ .unprepare = bcm2835_clock_off, ++ .recalc_rate = bcm2835_clock_get_rate, ++ .set_rate = bcm2835_clock_set_rate, ++ .round_rate = bcm2835_clock_round_rate, ++}; ++ ++static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) ++{ ++ return true; ++} ++ ++/* ++ * The VPU clock can never be disabled (it doesn't have an ENABLE ++ * bit), so it gets its own set of clock ops. ++ */ ++static const struct clk_ops bcm2835_vpu_clock_clk_ops = { ++ .is_prepared = bcm2835_vpu_clock_is_on, ++ .recalc_rate = bcm2835_clock_get_rate, ++ .set_rate = bcm2835_clock_set_rate, ++ .round_rate = bcm2835_clock_round_rate, ++}; ++ ++static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, ++ const struct bcm2835_pll_data *data) ++{ ++ struct bcm2835_pll *pll; ++ struct clk_init_data init; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLLs derive from the external oscillator. */ ++ init.parent_names = &cprman->osc_name; ++ init.num_parents = 1; ++ init.name = data->name; ++ init.ops = &bcm2835_pll_clk_ops; ++ init.flags = CLK_IGNORE_UNUSED; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return NULL; ++ ++ pll->cprman = cprman; ++ pll->data = data; ++ pll->hw.init = &init; ++ ++ return devm_clk_register(cprman->dev, &pll->hw); ++} ++ ++static struct clk * ++bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, ++ const struct bcm2835_pll_divider_data *data) ++{ ++ struct bcm2835_pll_divider *divider; ++ struct clk_init_data init; ++ struct clk *clk; ++ const char *divider_name; ++ ++ if (data->fixed_divider != 1) { ++ divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL, ++ "%s_prediv", data->name); ++ if (!divider_name) ++ return NULL; ++ } else { ++ divider_name = data->name; ++ } ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = &data->source_pll->name; ++ init.num_parents = 1; ++ init.name = divider_name; ++ init.ops = &bcm2835_pll_divider_clk_ops; ++ init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; ++ ++ divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); ++ if (!divider) ++ return NULL; ++ ++ divider->div.reg = cprman->regs + data->a2w_reg; ++ divider->div.shift = A2W_PLL_DIV_SHIFT; ++ divider->div.width = A2W_PLL_DIV_BITS; ++ divider->div.flags = 0; ++ divider->div.lock = &cprman->regs_lock; ++ divider->div.hw.init = &init; ++ divider->div.table = NULL; ++ ++ divider->cprman = cprman; ++ divider->data = data; ++ ++ clk = devm_clk_register(cprman->dev, ÷r->div.hw); ++ if (IS_ERR(clk)) ++ return clk; ++ ++ /* ++ * PLLH's channels have a fixed divide by 10 afterwards, which ++ * is what our consumers are actually using. ++ */ ++ if (data->fixed_divider != 1) { ++ return clk_register_fixed_factor(cprman->dev, data->name, ++ divider_name, ++ CLK_SET_RATE_PARENT, ++ 1, ++ data->fixed_divider); ++ } ++ ++ return clk; ++} ++ ++static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, ++ const struct bcm2835_clock_data *data) ++{ ++ struct bcm2835_clock *clock; ++ struct clk_init_data init; ++ const char *parent; ++ ++ /* ++ * Most of the clock generators have a mux field, so we ++ * instantiate a generic mux as our parent to handle it. ++ */ ++ if (data->num_mux_parents) { ++ const char *parents[1 << CM_SRC_BITS]; ++ int i; ++ ++ parent = devm_kasprintf(cprman->dev, GFP_KERNEL, ++ "mux_%s", data->name); ++ if (!parent) ++ return NULL; ++ ++ /* ++ * Replace our "xosc" references with the oscillator's ++ * actual name. ++ */ ++ 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]; ++ } ++ ++ clk_register_mux(cprman->dev, parent, ++ parents, data->num_mux_parents, ++ CLK_SET_RATE_PARENT, ++ cprman->regs + data->ctl_reg, ++ CM_SRC_SHIFT, CM_SRC_BITS, ++ 0, &cprman->regs_lock); ++ } else { ++ parent = data->parents[0]; ++ } ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &parent; ++ init.num_parents = 1; ++ init.name = data->name; ++ init.flags = CLK_IGNORE_UNUSED; ++ ++ if (data->is_vpu_clock) { ++ init.ops = &bcm2835_vpu_clock_clk_ops; ++ } else { ++ init.ops = &bcm2835_clock_clk_ops; ++ init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; ++ } ++ ++ clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->cprman = cprman; ++ clock->data = data; ++ clock->hw.init = &init; ++ ++ return devm_clk_register(cprman->dev, &clock->hw); ++} ++ ++static int bcm2835_clk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct clk **clks; ++ struct bcm2835_cprman *cprman; ++ struct resource *res; ++ ++ cprman = devm_kzalloc(dev, sizeof(*cprman), GFP_KERNEL); ++ if (!cprman) ++ return -ENOMEM; ++ ++ spin_lock_init(&cprman->regs_lock); ++ cprman->dev = dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ cprman->regs = devm_ioremap_resource(dev, res); ++ 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) ++ return -ENODEV; ++ ++ platform_set_drvdata(pdev, cprman); ++ ++ cprman->onecell.clk_num = BCM2835_CLOCK_COUNT; ++ cprman->onecell.clks = cprman->clks; ++ clks = cprman->clks; ++ ++ clks[BCM2835_PLLA] = bcm2835_register_pll(cprman, &bcm2835_plla_data); ++ clks[BCM2835_PLLB] = bcm2835_register_pll(cprman, &bcm2835_pllb_data); ++ clks[BCM2835_PLLC] = bcm2835_register_pll(cprman, &bcm2835_pllc_data); ++ clks[BCM2835_PLLD] = bcm2835_register_pll(cprman, &bcm2835_plld_data); ++ clks[BCM2835_PLLH] = bcm2835_register_pll(cprman, &bcm2835_pllh_data); ++ ++ clks[BCM2835_PLLA_CORE] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plla_core_data); ++ clks[BCM2835_PLLA_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plla_per_data); ++ clks[BCM2835_PLLC_CORE0] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core0_data); ++ clks[BCM2835_PLLC_CORE1] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core1_data); ++ clks[BCM2835_PLLC_CORE2] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_core2_data); ++ clks[BCM2835_PLLC_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllc_per_data); ++ clks[BCM2835_PLLD_CORE] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plld_core_data); ++ clks[BCM2835_PLLD_PER] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_plld_per_data); ++ clks[BCM2835_PLLH_RCAL] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_rcal_data); ++ clks[BCM2835_PLLH_AUX] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_aux_data); ++ clks[BCM2835_PLLH_PIX] = ++ bcm2835_register_pll_divider(cprman, &bcm2835_pllh_pix_data); ++ ++ clks[BCM2835_CLOCK_TIMER] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_timer_data); ++ clks[BCM2835_CLOCK_OTP] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_otp_data); ++ clks[BCM2835_CLOCK_TSENS] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_tsens_data); ++ clks[BCM2835_CLOCK_VPU] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_vpu_data); ++ clks[BCM2835_CLOCK_V3D] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); ++ clks[BCM2835_CLOCK_ISP] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_isp_data); ++ clks[BCM2835_CLOCK_H264] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_h264_data); ++ clks[BCM2835_CLOCK_V3D] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_v3d_data); ++ clks[BCM2835_CLOCK_SDRAM] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_sdram_data); ++ clks[BCM2835_CLOCK_UART] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_uart_data); ++ clks[BCM2835_CLOCK_VEC] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_vec_data); ++ clks[BCM2835_CLOCK_HSM] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_hsm_data); ++ clks[BCM2835_CLOCK_EMMC] = ++ bcm2835_register_clock(cprman, &bcm2835_clock_emmc_data); ++ ++ /* ++ * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if ++ * you have the debug bit set in the power manager, which we ++ * don't bother exposing) are individual gates off of the ++ * non-stop vpu clock. ++ */ ++ clks[BCM2835_CLOCK_PERI_IMAGE] = ++ clk_register_gate(dev, "peri_image", "vpu", ++ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, ++ cprman->regs + CM_PERIICTL, CM_GATE_BIT, ++ 0, &cprman->regs_lock); ++ ++ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, ++ &cprman->onecell); ++} ++ ++static const struct of_device_id bcm2835_clk_of_match[] = { ++ { .compatible = "brcm,bcm2835-cprman", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match); ++ ++static struct platform_driver bcm2835_clk_driver = { ++ .driver = { ++ .name = "bcm2835-clk", ++ .of_match_table = bcm2835_clk_of_match, ++ }, ++ .probe = bcm2835_clk_probe, ++}; ++ ++module_platform_driver(bcm2835_clk_driver); ++ ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_DESCRIPTION("BCM2835 clock driver"); ++MODULE_LICENSE("GPL v2"); + +From 792857badec33b5a0a1f16c9d83588c524662c14 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 12 Oct 2015 11:23:34 -0700 +Subject: [PATCH 236/278] clk: bcm2835: Also build the driver for downstream + kernels. + +Signed-off-by: Eric Anholt +(cherry picked from commit fc0a178addf1cae65245e129e9bbe4a5daeb2cfd) +--- + drivers/clk/Makefile | 2 +- + drivers/clk/bcm/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 4178cd7..d7031a2 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -45,7 +45,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o + obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o + obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o + obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +-obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ ++obj-y += bcm/ + obj-$(CONFIG_ARCH_BERLIN) += berlin/ + obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ + obj-$(CONFIG_ARCH_HIP04) += hisilicon/ +diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile +index 72e245e..7f6dedf 100644 +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -2,4 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o ++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += clk-bcm2835.o + +From 918ccefee165eefdb7d68e61f25e4d1ad24ee40b Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 18 Jan 2016 10:01:11 -0800 +Subject: [PATCH 237/278] bcm2708: Add disabled-by-default cprman to the dtsi. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 463777e..0425419 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -86,6 +86,18 @@ + status = "disabled"; + }; + ++ cprman: cprman@7e101000 { ++ compatible = "brcm,bcm2835-cprman"; ++ #clock-cells = <1>; ++ reg = <0x7e101000 0x2000>; ++ ++ /* CPRMAN derives everything from the platform's ++ * oscillator. ++ */ ++ clocks = <&clk_osc>; ++ status = "disabled"; ++ }; ++ + random: rng@7e104000 { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; +@@ -319,6 +331,14 @@ + clock-div = <1>; + clock-mult = <2>; + }; ++ ++ clk_osc: clock@6 { ++ compatible = "fixed-clock"; ++ reg = <6>; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <19200000>; ++ }; + }; + + __overrides__ { + +From 2430a4bb8e3bb9ed9ff13842195745c151856085 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 18 Dec 2014 16:07:15 -0800 +Subject: [PATCH 238/278] mm: Remove the PFN busy warning + +See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is +expected sometimes when using CMA. However, that commit still spams +my kernel log with these warnings. + +Signed-off-by: Eric Anholt +--- + mm/page_alloc.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 18490f3..23076ed 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -6485,8 +6485,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, + + /* Make sure the range is really isolated. */ + if (test_pages_isolated(outer_start, end, false)) { +- pr_info("%s: [%lx, %lx) PFNs busy\n", +- __func__, outer_start, end); + ret = -EBUSY; + goto done; + } + +From 87f2b93bd74c772dbf4988ef18f0933c2dd682be Mon Sep 17 00:00:00 2001 +From: Ander Conselvan de Oliveira +Date: Tue, 21 Apr 2015 17:13:18 +0300 +Subject: [PATCH 239/278] drm/atomic: Make mode_fixup() optional for + check_modeset() + +So the i915 driver can use the same logic for setting mode and active +changed flags, without having to implement encoder helpers and the +mode_fixup() callback. + +Cc: dri-devel@lists.freedestkop.org +Signed-off-by: Ander Conselvan de Oliveira +Reviewed-by: Maarten Lankhorst +Acked-by: Dave Airlie +Signed-off-by: Daniel Vetter +(cherry picked from commit 840bfe953384a134c8639f2964d9b74bfa671e16) +--- + drivers/gpu/drm/drm_atomic_helper.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 1d2ca52..91011be 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -280,6 +280,8 @@ mode_fixup(struct drm_atomic_state *state) + */ + encoder = conn_state->best_encoder; + funcs = encoder->helper_private; ++ if (!funcs) ++ continue; + + if (encoder->bridge && encoder->bridge->funcs->mode_fixup) { + ret = encoder->bridge->funcs->mode_fixup( +@@ -317,6 +319,9 @@ mode_fixup(struct drm_atomic_state *state) + continue; + + funcs = crtc->helper_private; ++ if (!funcs->mode_fixup) ++ continue; ++ + ret = funcs->mode_fixup(crtc, &crtc_state->mode, + &crtc_state->adjusted_mode); + if (!ret) { + +From ebfe14332d7b3c92f3c2044ed5e103bf7bef3afe Mon Sep 17 00:00:00 2001 +From: Inki Dae +Date: Tue, 11 Aug 2015 21:23:49 +0900 +Subject: [PATCH 240/278] drm/atomic: fix null pointer access to mode_fixup + callback + +This patch fixes null pointer access incurred when +encoder driver didn't set its own mode_fixup callback. + +mode_fixup callback shoudn't be called if the callback +of drm_encoder_helper_funcs is NULL. + +Changelog v2: +- change it to else if + +Signed-off-by: Inki Dae +Reviewed-by: Maarten Lankhorst +Signed-off-by: Daniel Vetter +(cherry picked from commit 845249172a363c2217af5926fac17f58c7228aa4) +--- + drivers/gpu/drm/drm_atomic_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 91011be..03dc131 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -301,7 +301,7 @@ mode_fixup(struct drm_atomic_state *state) + encoder->base.id, encoder->name); + return ret; + } +- } else { ++ } else if (funcs->mode_fixup) { + ret = funcs->mode_fixup(encoder, &crtc_state->mode, + &crtc_state->adjusted_mode); + if (!ret) { + +From c95c2b9d03690c22cb99662c071545a13e29962c Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Thu, 9 Jul 2015 23:44:25 +0200 +Subject: [PATCH 241/278] drm: Add modeset object iterators + +And roll them out across drm_* files. The point here isn't code +prettification (it helps with that too) but that some of these lists +aren't static any more. And having macros will gives us a convenient +place to put locking checks into. + +I didn't add an iterator for props since that's only used by a +list_for_each_entry_safe in the driver teardown code. + +Search&replace was done with the below cocci spatch. Note that there's +a bunch more places that didn't match and which would need some manual +changes, but I've intentially left these out for this mostly automated +patch. + +iterator name drm_for_each_crtc; +struct drm_crtc *crtc; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc (crtc, dev) { +... +} + +@@ +iterator name drm_for_each_encoder; +struct drm_encoder *encoder; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder (encoder, dev) { +... +} + +@@ +iterator name drm_for_each_fb; +struct drm_framebuffer *fb; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(fb, &dev->mode_config.fb_list, head) { ++ drm_for_each_fb (fb, dev) { +... +} + +@@ +iterator name drm_for_each_connector; +struct drm_connector *connector; +struct drm_device *dev; +expression head; +@@ +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector (connector, dev) { +... +} + +Reviewed-by: Maarten Lankhorst +Signed-off-by: Daniel Vetter +(cherry picked from commit 6295d607ad34ee4e43aab3f20714c2ef7a6adea1) +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++----------- + drivers/gpu/drm/drm_crtc_helper.c | 34 +++++++++++++++--------------- + drivers/gpu/drm/drm_fb_helper.c | 10 ++++----- + drivers/gpu/drm/drm_of.c | 2 +- + drivers/gpu/drm/drm_probe_helper.c | 6 +++--- + include/drm/drm_crtc.h | 15 +++++++++++++ + 6 files changed, 72 insertions(+), 38 deletions(-) + +diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c +index 800a025..f8e2659 100644 +--- a/drivers/gpu/drm/drm_crtc.c ++++ b/drivers/gpu/drm/drm_crtc.c +@@ -613,7 +613,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) + if (atomic_read(&fb->refcount.refcount) > 1) { + drm_modeset_lock_all(dev); + /* remove from any CRTC */ +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + memset(&set, 0, sizeof(struct drm_mode_set)); +@@ -625,7 +625,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) + } + } + +- list_for_each_entry(plane, &dev->mode_config.plane_list, head) { ++ drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } +@@ -1289,6 +1289,29 @@ unsigned int drm_plane_index(struct drm_plane *plane) + EXPORT_SYMBOL(drm_plane_index); + + /** ++ * drm_plane_from_index - find the registered plane at an index ++ * @dev: DRM device ++ * @idx: index of registered plane to find for ++ * ++ * Given a plane index, return the registered plane from DRM device's ++ * list of planes with matching index. ++ */ ++struct drm_plane * ++drm_plane_from_index(struct drm_device *dev, int idx) ++{ ++ struct drm_plane *plane; ++ unsigned int i = 0; ++ ++ drm_for_each_plane(plane, dev) { ++ if (i == idx) ++ return plane; ++ i++; ++ } ++ return NULL; ++} ++EXPORT_SYMBOL(drm_plane_from_index); ++ ++/** + * drm_plane_force_disable - Forcibly disable a plane + * @plane: plane to disable + * +@@ -1881,8 +1904,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; + if (!mode_group) { +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, +- head) { ++ drm_for_each_crtc(crtc, dev) { + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; +@@ -1908,9 +1930,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; + if (!mode_group) { +- list_for_each_entry(encoder, +- &dev->mode_config.encoder_list, +- head) { ++ drm_for_each_encoder(encoder, dev) { + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, + encoder->name); + if (put_user(encoder->base.id, encoder_id + +@@ -1939,9 +1959,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, + copied = 0; + connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; + if (!mode_group) { +- list_for_each_entry(connector, +- &dev->mode_config.connector_list, +- head) { ++ drm_for_each_connector(connector, dev) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); +@@ -2230,7 +2248,7 @@ static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) + + /* For atomic drivers only state objects are synchronously updated and + * protected by modeset locks, so check those first. */ +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (!connector->state) + continue; + +@@ -5051,9 +5069,10 @@ void drm_mode_config_reset(struct drm_device *dev) + if (encoder->funcs->reset) + encoder->funcs->reset(encoder); + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) ++ drm_for_each_connector(connector, dev) { + if (connector->funcs->reset) + connector->funcs->reset(connector); ++ } + } + EXPORT_SYMBOL(drm_mode_config_reset); + +diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c +index ab00286..cc1871b 100644 +--- a/drivers/gpu/drm/drm_crtc_helper.c ++++ b/drivers/gpu/drm/drm_crtc_helper.c +@@ -182,7 +182,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) + + drm_warn_on_modeset_not_all_locked(dev); + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + if (!drm_helper_encoder_in_use(encoder)) { + drm_encoder_disable(encoder); + /* disconnect encoder from any connector */ +@@ -190,7 +190,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) + } + } + +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) { +@@ -232,7 +232,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev) + const struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_encoder *encoder; + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) +@@ -307,7 +307,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -338,7 +338,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + crtc->hwmode = *adjusted_mode; + + /* Prepare the encoders and CRTCs before setting the mode. */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -365,7 +365,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + if (!ret) + goto done; + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -384,7 +384,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ + crtc_funcs->commit(crtc); + +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if (encoder->crtc != crtc) + continue; +@@ -428,11 +428,11 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) + struct drm_encoder *encoder; + + /* Decouple all encoders and their attached connectors from this crtc */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + if (encoder->crtc != crtc) + continue; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (connector->encoder != encoder) + continue; + +@@ -529,12 +529,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + * restored, not the drivers personal bookkeeping. + */ + count = 0; +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + save_encoders[count++] = *encoder; + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + save_connectors[count++] = *connector; + } + +@@ -572,7 +572,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + + /* a) traverse passed in connector list and get encoders for them */ + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + const struct drm_connector_helper_funcs *connector_funcs = + connector->helper_private; + new_encoder = connector->encoder; +@@ -612,7 +612,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (!connector->encoder) + continue; + +@@ -695,12 +695,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) + fail: + /* Restore all previous data. */ + count = 0; +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + *encoder = save_encoders[count++]; + } + + count = 0; +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + *connector = save_connectors[count++]; + } + +@@ -876,7 +876,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) + bool ret; + + drm_modeset_lock_all(dev); +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + + if (!crtc->enabled) + continue; +@@ -890,7 +890,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) + + /* Turn off outputs that were already powered off */ + if (drm_helper_choose_crtc_dpms(crtc)) { +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ drm_for_each_encoder(encoder, dev) { + + if(encoder->crtc != crtc) + continue; +diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c +index cac4229..3630d92 100644 +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -98,7 +98,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) + struct drm_connector *connector; + int i; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + struct drm_fb_helper_connector *fb_helper_connector; + + fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); +@@ -269,7 +269,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) + struct drm_device *dev = crtc->dev; + struct drm_crtc *c; + +- list_for_each_entry(c, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(c, dev) { + if (crtc->base.id == c->base.id) + return c->primary->fb; + } +@@ -321,7 +321,7 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) + + drm_warn_on_modeset_not_all_locked(dev); + +- list_for_each_entry(plane, &dev->mode_config.plane_list, head) { ++ drm_for_each_plane(plane, dev) { + if (plane->type != DRM_PLANE_TYPE_PRIMARY) + drm_plane_force_disable(plane); + +@@ -458,7 +458,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) + if (dev->primary->master) + return false; + +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb) + crtcs_bound++; + if (crtc->primary->fb == fb_helper->fb) +@@ -655,7 +655,7 @@ int drm_fb_helper_init(struct drm_device *dev, + } + + i = 0; +- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(crtc, dev) { + fb_helper->crtc_info[i].mode_set.crtc = crtc; + i++; + } +diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c +index aaa1307..be38840 100644 +--- a/drivers/gpu/drm/drm_of.c ++++ b/drivers/gpu/drm/drm_of.c +@@ -19,7 +19,7 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, + unsigned int index = 0; + struct drm_crtc *tmp; + +- list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { ++ drm_for_each_crtc(tmp, dev) { + if (tmp->port == port) + return 1 << index; + +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 0d75e75..1bca49c 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -313,7 +313,7 @@ static void output_poll_execute(struct work_struct *work) + goto out; + + mutex_lock(&dev->mode_config.mutex); +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + + /* Ignore forced connectors. */ + if (connector->force) +@@ -414,7 +414,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) + if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) + return; + +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT)) + poll = true; +@@ -496,7 +496,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + return false; + + mutex_lock(&dev->mode_config.mutex); +- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ drm_for_each_connector(connector, dev) { + + /* Only handle HPD capable connectors. */ + if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) +diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h +index ca71c031..e48d53f 100644 +--- a/include/drm/drm_crtc.h ++++ b/include/drm/drm_crtc.h +@@ -1538,4 +1538,19 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id) + list_for_each_entry(plane, planelist, head) \ + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + ++#define drm_for_each_plane(plane, dev) \ ++ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) ++ ++#define drm_for_each_crtc(crtc, dev) \ ++ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) ++ ++#define drm_for_each_connector(connector, dev) \ ++ list_for_each_entry(connector, &(dev)->mode_config.connector_list, head) ++ ++#define drm_for_each_encoder(encoder, dev) \ ++ list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) ++ ++#define drm_for_each_fb(fb, dev) \ ++ list_for_each_entry(fb, &(dev)->mode_config.fb_list, head) ++ + #endif /* __DRM_CRTC_H__ */ + +From 0934ad7155dcc1f91fd001071ccfb6968aeb74af Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 30 Nov 2015 10:55:13 -0800 +Subject: [PATCH 242/278] drm: Create a driver hook for allocating GEM object + structs. + +The CMA helpers had no way for a driver to extend the struct with its +own fields. Since the CMA helpers are mostly "Allocate a +drm_gem_cma_object, then fill in a few fields", it's hard to write as +pure helpers without passing in a driver callback for the allocate +step. + +Signed-off-by: Eric Anholt +Reviewed-by: Daniel Vetter +(cherry picked from commit 10028c5ab107d3765c7fc282b6c45324d1602155) +--- + drivers/gpu/drm/drm_gem_cma_helper.c | 10 ++++++---- + include/drm/drmP.h | 7 +++++++ + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c +index e419eed..a2f13aa 100644 +--- a/drivers/gpu/drm/drm_gem_cma_helper.c ++++ b/drivers/gpu/drm/drm_gem_cma_helper.c +@@ -59,11 +59,13 @@ __drm_gem_cma_create(struct drm_device *drm, size_t size) + struct drm_gem_object *gem_obj; + int ret; + +- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); +- if (!cma_obj) ++ if (drm->driver->gem_create_object) ++ gem_obj = drm->driver->gem_create_object(drm, size); ++ else ++ gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); ++ if (!gem_obj) + return ERR_PTR(-ENOMEM); +- +- gem_obj = &cma_obj->base; ++ cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base); + + ret = drm_gem_object_init(drm, gem_obj, size); + if (ret) +diff --git a/include/drm/drmP.h b/include/drm/drmP.h +index 62c40777..2cadcb8 100644 +--- a/include/drm/drmP.h ++++ b/include/drm/drmP.h +@@ -567,6 +567,13 @@ struct drm_driver { + int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); + void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + ++ /** ++ * Hook for allocating the GEM object struct, for use by core ++ * helpers. ++ */ ++ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, ++ size_t size); ++ + /* prime: */ + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, + +From e5971ca2847e8949fd1032ea5e59300667c127c5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 18 Jan 2016 09:28:46 -0800 +Subject: [PATCH 243/278] drm/vc4: Import driver from rpi-4.4.y. + +There are minor backports involved (atomic_flush, enable_vblank, +disable_vblank, drm_atomic_helper_commit_planes arguments). + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/Kconfig | 2 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/vc4/Kconfig | 14 + + drivers/gpu/drm/vc4/Makefile | 26 + + drivers/gpu/drm/vc4/vc4_bo.c | 574 ++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_crtc.c | 769 ++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_debugfs.c | 42 ++ + drivers/gpu/drm/vc4/vc4_drv.c | 331 +++++++++++ + drivers/gpu/drm/vc4/vc4_drv.h | 462 +++++++++++++++ + drivers/gpu/drm/vc4/vc4_gem.c | 867 +++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi.c | 592 +++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hvs.c | 163 ++++++ + drivers/gpu/drm/vc4/vc4_irq.c | 210 +++++++ + drivers/gpu/drm/vc4/vc4_kms.c | 214 +++++++ + drivers/gpu/drm/vc4/vc4_packet.h | 399 +++++++++++++ + drivers/gpu/drm/vc4/vc4_plane.c | 386 +++++++++++++ + drivers/gpu/drm/vc4/vc4_qpu_defines.h | 264 +++++++++ + drivers/gpu/drm/vc4/vc4_regs.h | 570 ++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_render_cl.c | 634 ++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_trace.h | 63 ++ + drivers/gpu/drm/vc4/vc4_trace_points.c | 14 + + drivers/gpu/drm/vc4/vc4_v3d.c | 270 +++++++++ + drivers/gpu/drm/vc4/vc4_validate.c | 900 +++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 513 ++++++++++++++++ + include/uapi/drm/vc4_drm.h | 279 +++++++++ + 25 files changed, 8559 insertions(+) + create mode 100644 drivers/gpu/drm/vc4/Kconfig + create mode 100644 drivers/gpu/drm/vc4/Makefile + create mode 100644 drivers/gpu/drm/vc4/vc4_bo.c + create mode 100644 drivers/gpu/drm/vc4/vc4_crtc.c + create mode 100644 drivers/gpu/drm/vc4/vc4_debugfs.c + create mode 100644 drivers/gpu/drm/vc4/vc4_drv.c + create mode 100644 drivers/gpu/drm/vc4/vc4_drv.h + create mode 100644 drivers/gpu/drm/vc4/vc4_gem.c + create mode 100644 drivers/gpu/drm/vc4/vc4_hdmi.c + create mode 100644 drivers/gpu/drm/vc4/vc4_hvs.c + create mode 100644 drivers/gpu/drm/vc4/vc4_irq.c + create mode 100644 drivers/gpu/drm/vc4/vc4_kms.c + create mode 100644 drivers/gpu/drm/vc4/vc4_packet.h + create mode 100644 drivers/gpu/drm/vc4/vc4_plane.c + create mode 100644 drivers/gpu/drm/vc4/vc4_qpu_defines.h + create mode 100644 drivers/gpu/drm/vc4/vc4_regs.h + create mode 100644 drivers/gpu/drm/vc4/vc4_render_cl.c + create mode 100644 drivers/gpu/drm/vc4/vc4_trace.h + create mode 100644 drivers/gpu/drm/vc4/vc4_trace_points.c + create mode 100644 drivers/gpu/drm/vc4/vc4_v3d.c + create mode 100644 drivers/gpu/drm/vc4/vc4_validate.c + create mode 100644 drivers/gpu/drm/vc4/vc4_validate_shaders.c + create mode 100644 include/uapi/drm/vc4_drm.h + +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index 47f2ce8..3151dc8 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -217,3 +217,5 @@ source "drivers/gpu/drm/sti/Kconfig" + source "drivers/gpu/drm/amd/amdkfd/Kconfig" + + source "drivers/gpu/drm/imx/Kconfig" ++ ++source "drivers/gpu/drm/vc4/Kconfig" +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 7d4944e..c6417cf 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_DRM_MGAG200) += mgag200/ + obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ + obj-$(CONFIG_DRM_SIS) += sis/ + obj-$(CONFIG_DRM_SAVAGE)+= savage/ ++obj-$(CONFIG_DRM_VC4)+= vc4/ + obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ + obj-$(CONFIG_DRM_VIA) +=via/ + obj-$(CONFIG_DRM_VGEM) += vgem/ +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +new file mode 100644 +index 0000000..71f019f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -0,0 +1,14 @@ ++config DRM_VC4 ++ tristate "Broadcom VC4 Graphics" ++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST ++ depends on DRM && HAVE_DMA_ATTRS ++ select DRM_KMS_HELPER ++ select DRM_KMS_CMA_HELPER ++ select DRM_GEM_CMA_HELPER ++ help ++ Choose this option if you have a system that has a Broadcom ++ VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. ++ ++ This driver requires that "avoid_warnings=2" be present in ++ the config.txt for the firmware, to keep it from smashing ++ our display setup. +diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile +new file mode 100644 +index 0000000..4c6a99f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -0,0 +1,26 @@ ++ccflags-y := -Iinclude/drm ++ ++# Please keep these build lists sorted! ++ ++# core driver code ++vc4-y := \ ++ vc4_bo.o \ ++ vc4_crtc.o \ ++ vc4_drv.o \ ++ vc4_kms.o \ ++ vc4_gem.o \ ++ vc4_hdmi.o \ ++ vc4_hvs.o \ ++ vc4_irq.o \ ++ vc4_plane.o \ ++ vc4_render_cl.o \ ++ vc4_trace_points.o \ ++ vc4_v3d.o \ ++ vc4_validate.o \ ++ vc4_validate_shaders.o ++ ++vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o ++ ++obj-$(CONFIG_DRM_VC4) += vc4.o ++ ++CFLAGS_vc4_trace_points.o := -I$(src) +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +new file mode 100644 +index 0000000..6247ff8 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -0,0 +1,574 @@ ++/* ++ * Copyright © 2015 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. ++ */ ++ ++/* DOC: VC4 GEM BO management support. ++ * ++ * The VC4 GPU architecture (both scanout and rendering) has direct ++ * access to system memory with no MMU in between. To support it, we ++ * use the GEM CMA helper functions to allocate contiguous ranges of ++ * physical memory for our BOs. ++ * ++ * Since the CMA allocator is very slow, we keep a cache of recently ++ * freed BOs around so that the kernel's allocation of objects for 3D ++ * rendering can return quickly. ++ */ ++ ++#include "vc4_drv.h" ++#include "uapi/drm/vc4_drm.h" ++ ++static void vc4_bo_stats_dump(struct vc4_dev *vc4) ++{ ++ DRM_INFO("num bos allocated: %d\n", ++ vc4->bo_stats.num_allocated); ++ DRM_INFO("size bos allocated: %dkb\n", ++ vc4->bo_stats.size_allocated / 1024); ++ DRM_INFO("num bos used: %d\n", ++ vc4->bo_stats.num_allocated - vc4->bo_stats.num_cached); ++ DRM_INFO("size bos used: %dkb\n", ++ (vc4->bo_stats.size_allocated - ++ vc4->bo_stats.size_cached) / 1024); ++ DRM_INFO("num bos cached: %d\n", ++ vc4->bo_stats.num_cached); ++ DRM_INFO("size bos cached: %dkb\n", ++ vc4->bo_stats.size_cached / 1024); ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_bo_stats_debugfs(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_bo_stats stats; ++ ++ /* Take a snapshot of the current stats with the lock held. */ ++ mutex_lock(&vc4->bo_lock); ++ stats = vc4->bo_stats; ++ mutex_unlock(&vc4->bo_lock); ++ ++ seq_printf(m, "num bos allocated: %d\n", ++ stats.num_allocated); ++ seq_printf(m, "size bos allocated: %dkb\n", ++ stats.size_allocated / 1024); ++ seq_printf(m, "num bos used: %d\n", ++ stats.num_allocated - stats.num_cached); ++ seq_printf(m, "size bos used: %dkb\n", ++ (stats.size_allocated - stats.size_cached) / 1024); ++ seq_printf(m, "num bos cached: %d\n", ++ stats.num_cached); ++ seq_printf(m, "size bos cached: %dkb\n", ++ stats.size_cached / 1024); ++ ++ return 0; ++} ++#endif ++ ++static uint32_t bo_page_index(size_t size) ++{ ++ return (size / PAGE_SIZE) - 1; ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_destroy(struct vc4_bo *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev); ++ ++ if (bo->validated_shader) { ++ kfree(bo->validated_shader->texture_samples); ++ kfree(bo->validated_shader); ++ bo->validated_shader = NULL; ++ } ++ ++ vc4->bo_stats.num_allocated--; ++ vc4->bo_stats.size_allocated -= obj->size; ++ drm_gem_cma_free_object(obj); ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_remove_from_cache(struct vc4_bo *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct vc4_dev *vc4 = to_vc4_dev(obj->dev); ++ ++ vc4->bo_stats.num_cached--; ++ vc4->bo_stats.size_cached -= obj->size; ++ ++ list_del(&bo->unref_head); ++ list_del(&bo->size_head); ++} ++ ++static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev, ++ size_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t page_index = bo_page_index(size); ++ ++ if (vc4->bo_cache.size_list_size <= page_index) { ++ uint32_t new_size = max(vc4->bo_cache.size_list_size * 2, ++ page_index + 1); ++ struct list_head *new_list; ++ uint32_t i; ++ ++ new_list = kmalloc_array(new_size, sizeof(struct list_head), ++ GFP_KERNEL); ++ if (!new_list) ++ return NULL; ++ ++ /* Rebase the old cached BO lists to their new list ++ * head locations. ++ */ ++ for (i = 0; i < vc4->bo_cache.size_list_size; i++) { ++ struct list_head *old_list = ++ &vc4->bo_cache.size_list[i]; ++ ++ if (list_empty(old_list)) ++ INIT_LIST_HEAD(&new_list[i]); ++ else ++ list_replace(old_list, &new_list[i]); ++ } ++ /* And initialize the brand new BO list heads. */ ++ for (i = vc4->bo_cache.size_list_size; i < new_size; i++) ++ INIT_LIST_HEAD(&new_list[i]); ++ ++ kfree(vc4->bo_cache.size_list); ++ vc4->bo_cache.size_list = new_list; ++ vc4->bo_cache.size_list_size = new_size; ++ } ++ ++ return &vc4->bo_cache.size_list[page_index]; ++} ++ ++void vc4_bo_cache_purge(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mutex_lock(&vc4->bo_lock); ++ while (!list_empty(&vc4->bo_cache.time_list)) { ++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, ++ struct vc4_bo, unref_head); ++ vc4_bo_remove_from_cache(bo); ++ vc4_bo_destroy(bo); ++ } ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev, ++ uint32_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t page_index = bo_page_index(size); ++ struct vc4_bo *bo = NULL; ++ ++ size = roundup(size, PAGE_SIZE); ++ ++ mutex_lock(&vc4->bo_lock); ++ if (page_index >= vc4->bo_cache.size_list_size) ++ goto out; ++ ++ if (list_empty(&vc4->bo_cache.size_list[page_index])) ++ goto out; ++ ++ bo = list_first_entry(&vc4->bo_cache.size_list[page_index], ++ struct vc4_bo, size_head); ++ vc4_bo_remove_from_cache(bo); ++ kref_init(&bo->base.base.refcount); ++ ++out: ++ mutex_unlock(&vc4->bo_lock); ++ return bo; ++} ++ ++/** ++ * vc4_gem_create_object - Implementation of driver->gem_create_object. ++ * ++ * This lets the CMA helpers allocate object structs for us, and keep ++ * our BO stats correct. ++ */ ++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_bo *bo; ++ ++ bo = kzalloc(sizeof(*bo), GFP_KERNEL); ++ if (!bo) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_lock(&vc4->bo_lock); ++ vc4->bo_stats.num_allocated++; ++ vc4->bo_stats.size_allocated += size; ++ mutex_unlock(&vc4->bo_lock); ++ ++ return &bo->base.base; ++} ++ ++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, ++ bool from_cache) ++{ ++ size_t size = roundup(unaligned_size, PAGE_SIZE); ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_gem_cma_object *cma_obj; ++ int pass; ++ ++ if (size == 0) ++ return NULL; ++ ++ /* 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; ++ } ++ ++ /* Otherwise, make a new BO. */ ++ for (pass = 0; ; pass++) { ++ cma_obj = drm_gem_cma_create(dev, size); ++ if (!IS_ERR(cma_obj)) ++ break; ++ ++ switch (pass) { ++ case 0: ++ /* ++ * If we've run out of CMA memory, kill the cache of ++ * CMA allocations we've got laying around and try again. ++ */ ++ vc4_bo_cache_purge(dev); ++ break; ++ case 1: ++ /* ++ * Getting desperate, so try to wait for any ++ * previous rendering to finish, free its ++ * unreferenced BOs to the cache, and then ++ * free the cache. ++ */ ++ vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true); ++ vc4_job_handle_completed(vc4); ++ vc4_bo_cache_purge(dev); ++ break; ++ case 3: ++ DRM_ERROR("Failed to allocate from CMA:\n"); ++ vc4_bo_stats_dump(vc4); ++ return NULL; ++ } ++ } ++ ++ return to_vc4_bo(&cma_obj->base); ++} ++ ++int vc4_dumb_create(struct drm_file *file_priv, ++ struct drm_device *dev, ++ struct drm_mode_create_dumb *args) ++{ ++ int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ if (args->pitch < min_pitch) ++ args->pitch = min_pitch; ++ ++ if (args->size < args->pitch * args->height) ++ args->size = args->pitch * args->height; ++ ++ bo = vc4_bo_create(dev, args->size, false); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++/* Must be called with bo_lock held. */ ++static void vc4_bo_cache_free_old(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long expire_time = jiffies - msecs_to_jiffies(1000); ++ ++ while (!list_empty(&vc4->bo_cache.time_list)) { ++ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, ++ struct vc4_bo, unref_head); ++ if (time_before(expire_time, bo->free_time)) { ++ mod_timer(&vc4->bo_cache.time_timer, ++ round_jiffies_up(jiffies + ++ msecs_to_jiffies(1000))); ++ return; ++ } ++ ++ vc4_bo_remove_from_cache(bo); ++ vc4_bo_destroy(bo); ++ } ++} ++ ++/* Called on the last userspace/kernel unreference of the BO. Returns ++ * it to the BO cache if possible, otherwise frees it. ++ * ++ * Note that this is called with the struct_mutex held. ++ */ ++void vc4_free_object(struct drm_gem_object *gem_bo) ++{ ++ struct drm_device *dev = gem_bo->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_bo *bo = to_vc4_bo(gem_bo); ++ struct list_head *cache_list; ++ ++ mutex_lock(&vc4->bo_lock); ++ /* If the object references someone else's memory, we can't cache it. ++ */ ++ if (gem_bo->import_attach) { ++ vc4_bo_destroy(bo); ++ goto out; ++ } ++ ++ /* Don't cache if it was publicly named. */ ++ if (gem_bo->name) { ++ 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); ++ goto out; ++ } ++ ++ if (bo->validated_shader) { ++ kfree(bo->validated_shader->texture_samples); ++ kfree(bo->validated_shader); ++ bo->validated_shader = NULL; ++ } ++ ++ bo->free_time = jiffies; ++ list_add(&bo->size_head, cache_list); ++ list_add(&bo->unref_head, &vc4->bo_cache.time_list); ++ ++ vc4->bo_stats.num_cached++; ++ vc4->bo_stats.size_cached += gem_bo->size; ++ ++ vc4_bo_cache_free_old(dev); ++ ++out: ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static void vc4_bo_cache_time_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, bo_cache.time_work); ++ struct drm_device *dev = vc4->dev; ++ ++ mutex_lock(&vc4->bo_lock); ++ vc4_bo_cache_free_old(dev); ++ mutex_unlock(&vc4->bo_lock); ++} ++ ++static void vc4_bo_cache_time_timer(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ schedule_work(&vc4->bo_cache.time_work); ++} ++ ++struct dma_buf * ++vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("Attempting to export shader BO\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return drm_gem_prime_export(dev, obj, flags); ++} ++ ++int vc4_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct drm_gem_object *gem_obj; ++ struct vc4_bo *bo; ++ int ret; ++ ++ ret = drm_gem_mmap(filp, vma); ++ if (ret) ++ return ret; ++ ++ gem_obj = vma->vm_private_data; ++ bo = to_vc4_bo(gem_obj); ++ ++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { ++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the ++ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map ++ * the whole buffer. ++ */ ++ vma->vm_flags &= ~VM_PFNMAP; ++ vma->vm_pgoff = 0; ++ ++ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma, ++ bo->base.vaddr, bo->base.paddr, ++ vma->vm_end - vma->vm_start); ++ if (ret) ++ drm_gem_vm_close(vma); ++ ++ return ret; ++} ++ ++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { ++ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n"); ++ return -EINVAL; ++ } ++ ++ return drm_gem_cma_prime_mmap(obj, vma); ++} ++ ++void *vc4_prime_vmap(struct drm_gem_object *obj) ++{ ++ struct vc4_bo *bo = to_vc4_bo(obj); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("mmaping of shader BOs not allowed.\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return drm_gem_cma_prime_vmap(obj); ++} ++ ++int vc4_create_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_create_bo *args = data; ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ /* ++ * We can't allocate from the BO cache, because the BOs don't ++ * get zeroed, and that might leak data between users. ++ */ ++ bo = vc4_bo_create(dev, args->size, false); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_mmap_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ ++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); ++ return -EINVAL; ++ } ++ ++ /* The mmap offset was set up at BO allocation time. */ ++ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); ++ ++ drm_gem_object_unreference_unlocked(gem_obj); ++ return 0; ++} ++ ++int ++vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_create_shader_bo *args = data; ++ struct vc4_bo *bo = NULL; ++ int ret; ++ ++ if (args->size == 0) ++ return -EINVAL; ++ ++ if (args->size % sizeof(u64) != 0) ++ return -EINVAL; ++ ++ if (args->flags != 0) { ++ DRM_INFO("Unknown flags set: 0x%08x\n", args->flags); ++ return -EINVAL; ++ } ++ ++ if (args->pad != 0) { ++ DRM_INFO("Pad set: 0x%08x\n", args->pad); ++ return -EINVAL; ++ } ++ ++ bo = vc4_bo_create(dev, args->size, true); ++ if (!bo) ++ return -ENOMEM; ++ ++ ret = copy_from_user(bo->base.vaddr, ++ (void __user *)(uintptr_t)args->data, ++ args->size); ++ if (ret != 0) ++ goto fail; ++ /* Clear the rest of the memory from allocating from the BO ++ * cache. ++ */ ++ memset(bo->base.vaddr + args->size, 0, ++ bo->base.base.size - args->size); ++ ++ bo->validated_shader = vc4_validate_shader(&bo->base); ++ if (!bo->validated_shader) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ /* We have to create the handle after validation, to avoid ++ * races for users to do doing things like mmap the shader BO. ++ */ ++ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); ++ ++ fail: ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ ++ return ret; ++} ++ ++void vc4_bo_cache_init(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mutex_init(&vc4->bo_lock); ++ ++ INIT_LIST_HEAD(&vc4->bo_cache.time_list); ++ ++ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work); ++ setup_timer(&vc4->bo_cache.time_timer, ++ vc4_bo_cache_time_timer, ++ (unsigned long)dev); ++} ++ ++void vc4_bo_cache_destroy(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ del_timer(&vc4->bo_cache.time_timer); ++ cancel_work_sync(&vc4->bo_cache.time_work); ++ ++ vc4_bo_cache_purge(dev); ++ ++ if (vc4->bo_stats.num_allocated) { ++ DRM_ERROR("Destroying BO cache while BOs still allocated:\n"); ++ vc4_bo_stats_dump(vc4); ++ } ++} +diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c +new file mode 100644 +index 0000000..c28090b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 CRTC module ++ * ++ * In VC4, the Pixel Valve is what most closely corresponds to the ++ * DRM's concept of a CRTC. The PV generates video timings from the ++ * output's clock plus its configuration. It pulls scaled pixels from ++ * the HVS at that timing, and feeds it to the encoder. ++ * ++ * However, the DRM CRTC also collects the configuration of all the ++ * DRM planes attached to it. As a result, this file also manages ++ * setup of the VC4 HVS's display elements on the CRTC. ++ * ++ * The 2835 has 3 different pixel valves. pv0 in the audio power ++ * domain feeds DSI0 or DPI, while pv1 feeds DS1 or SMI. pv2 in the ++ * image domain can feed either HDMI or the SDTV controller. The ++ * pixel valve chooses from the CPRMAN clocks (HSM for HDMI, VEC for ++ * SDTV, etc.) according to which output type is chosen in the mux. ++ * ++ * For power management, the pixel valve's registers are all clocked ++ * by the AXI clock, while the timings and FIFOs make use of the ++ * output-specific clock. Since the encoders also directly consume ++ * the CPRMAN clocks, and know what timings they need, they are the ++ * ones that set the clock. ++ */ ++ ++#include "drm_atomic.h" ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "linux/clk.h" ++#include "drm_fb_cma_helper.h" ++#include "linux/component.h" ++#include "linux/of_device.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++struct vc4_crtc { ++ struct drm_crtc base; ++ const struct vc4_crtc_data *data; ++ void __iomem *regs; ++ ++ /* Which HVS channel we're using for our CRTC. */ ++ int channel; ++ ++ /* Pointer to the actual hardware display list memory for the ++ * crtc. ++ */ ++ u32 __iomem *dlist; ++ ++ u32 dlist_size; /* in dwords */ ++ ++ struct drm_pending_vblank_event *event; ++}; ++ ++static inline struct vc4_crtc * ++to_vc4_crtc(struct drm_crtc *crtc) ++{ ++ return (struct vc4_crtc *)crtc; ++} ++ ++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; ++}; ++ ++#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) ++#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) ++ ++#define CRTC_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} crtc_regs[] = { ++ CRTC_REG(PV_CONTROL), ++ CRTC_REG(PV_V_CONTROL), ++ CRTC_REG(PV_VSYNCD), ++ CRTC_REG(PV_HORZA), ++ CRTC_REG(PV_HORZB), ++ CRTC_REG(PV_VERTA), ++ CRTC_REG(PV_VERTB), ++ CRTC_REG(PV_VERTA_EVEN), ++ CRTC_REG(PV_VERTB_EVEN), ++ CRTC_REG(PV_INTEN), ++ CRTC_REG(PV_INTSTAT), ++ CRTC_REG(PV_STAT), ++ CRTC_REG(PV_HACT_ACT), ++}; ++ ++static void vc4_crtc_dump_regs(struct vc4_crtc *vc4_crtc) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ crtc_regs[i].reg, crtc_regs[i].name, ++ CRTC_READ(crtc_regs[i].reg)); ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_crtc_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; ++ int crtc_index = (uintptr_t)node->info_ent->data; ++ struct drm_crtc *crtc; ++ struct vc4_crtc *vc4_crtc; ++ int i; ++ ++ i = 0; ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ if (i == crtc_index) ++ break; ++ i++; ++ } ++ if (!crtc) ++ return 0; ++ vc4_crtc = to_vc4_crtc(crtc); ++ ++ for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ crtc_regs[i].name, crtc_regs[i].reg, ++ CRTC_READ(crtc_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void vc4_crtc_destroy(struct drm_crtc *crtc) ++{ ++ drm_crtc_cleanup(crtc); ++} ++ ++static u32 vc4_get_fifo_full_level(u32 format) ++{ ++ static const u32 fifo_len_bytes = 64; ++ static const u32 hvs_latency_pix = 6; ++ ++ switch (format) { ++ case PV_CONTROL_FORMAT_DSIV_16: ++ case PV_CONTROL_FORMAT_DSIC_16: ++ return fifo_len_bytes - 2 * hvs_latency_pix; ++ case PV_CONTROL_FORMAT_DSIV_18: ++ return fifo_len_bytes - 14; ++ case PV_CONTROL_FORMAT_24: ++ case PV_CONTROL_FORMAT_DSIV_24: ++ default: ++ return fifo_len_bytes - 3 * hvs_latency_pix; ++ } ++} ++ ++/* ++ * Returns the clock select bit for the connector attached to the ++ * CRTC. ++ */ ++static int vc4_get_clock_select(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 -1; ++} ++ ++static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) ++{ ++ 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 vactive = (mode->vdisplay >> (interlace ? 1 : 0)); ++ u32 format = 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)); ++ vc4_crtc_dump_regs(vc4_crtc); ++ } ++ ++ /* Reset the PV fifo. */ ++ CRTC_WRITE(PV_CONTROL, 0); ++ CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); ++ CRTC_WRITE(PV_CONTROL, 0); ++ ++ CRTC_WRITE(PV_HORZA, ++ VC4_SET_FIELD(mode->htotal - mode->hsync_end, ++ PV_HORZA_HBP) | ++ VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, ++ PV_HORZA_HSYNC)); ++ CRTC_WRITE(PV_HORZB, ++ VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, ++ PV_HORZB_HFP) | ++ VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); ++ ++ if (interlace) { ++ CRTC_WRITE(PV_VERTA_EVEN, ++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, ++ PV_VERTA_VBP) | ++ VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, ++ PV_VERTA_VSYNC)); ++ CRTC_WRITE(PV_VERTB_EVEN, ++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, ++ PV_VERTB_VFP) | ++ VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); ++ } ++ ++ CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); ++ ++ CRTC_WRITE(PV_V_CONTROL, ++ PV_VCONTROL_CONTINUOUS | ++ (interlace ? PV_VCONTROL_INTERLACE : 0)); ++ ++ CRTC_WRITE(PV_CONTROL, ++ VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | ++ VC4_SET_FIELD(vc4_get_fifo_full_level(format), ++ PV_CONTROL_FIFO_LEVEL) | ++ PV_CONTROL_CLR_AT_START | ++ PV_CONTROL_TRIGGER_UNDERFLOW | ++ PV_CONTROL_WAIT_HSTART | ++ VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | ++ PV_CONTROL_FIFO_CLR | ++ PV_CONTROL_EN); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc)); ++ vc4_crtc_dump_regs(vc4_crtc); ++ } ++} ++ ++static void require_hvs_enabled(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) != ++ SCALER_DISPCTRL_ENABLE); ++} ++ ++static void vc4_crtc_disable(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ u32 chan = vc4_crtc->channel; ++ int ret; ++ require_hvs_enabled(dev); ++ ++ CRTC_WRITE(PV_V_CONTROL, ++ CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN); ++ ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); ++ WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n"); ++ ++ if (HVS_READ(SCALER_DISPCTRLX(chan)) & ++ SCALER_DISPCTRLX_ENABLE) { ++ HVS_WRITE(SCALER_DISPCTRLX(chan), ++ SCALER_DISPCTRLX_RESET); ++ ++ /* While the docs say that reset is self-clearing, it ++ * seems it doesn't actually. ++ */ ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); ++ } ++ ++ /* Once we leave, the scaler should be disabled and its fifo empty. */ ++ ++ WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); ++ ++ WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), ++ SCALER_DISPSTATX_MODE) != ++ SCALER_DISPSTATX_MODE_DISABLED); ++ ++ WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & ++ (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != ++ SCALER_DISPSTATX_EMPTY); ++} ++ ++static void vc4_crtc_enable(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_crtc_state *state = crtc->state; ++ struct drm_display_mode *mode = &state->adjusted_mode; ++ ++ require_hvs_enabled(dev); ++ ++ /* Turn on the scaler, which will wait for vstart to start ++ * compositing. ++ */ ++ HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), ++ VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | ++ SCALER_DISPCTRLX_ENABLE); ++ ++ /* Turn on the pixel valve, which will emit the vstart signal. */ ++ CRTC_WRITE(PV_V_CONTROL, ++ CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); ++} ++ ++static int vc4_crtc_atomic_check(struct drm_crtc *crtc, ++ struct drm_crtc_state *state) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane; ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ u32 dlist_count = 0; ++ ++ /* The pixelvalve can only feed one encoder (and encoders are ++ * 1:1 with connectors.) ++ */ ++ if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1) ++ return -EINVAL; ++ ++ drm_atomic_crtc_state_for_each_plane(plane, state) { ++ struct drm_plane_state *plane_state = ++ state->state->plane_states[drm_plane_index(plane)]; ++ ++ /* plane might not have changed, in which case take ++ * current state: ++ */ ++ if (!plane_state) ++ plane_state = plane->state; ++ ++ dlist_count += vc4_plane_dlist_size(plane_state); ++ } ++ ++ dlist_count++; /* Account for SCALER_CTL0_END. */ ++ ++ if (!vc4_crtc->dlist || dlist_count > vc4_crtc->dlist_size) { ++ vc4_crtc->dlist = ((u32 __iomem *)vc4->hvs->dlist + ++ HVS_BOOTLOADER_DLIST_END); ++ vc4_crtc->dlist_size = ((SCALER_DLIST_SIZE >> 2) - ++ HVS_BOOTLOADER_DLIST_END); ++ ++ if (dlist_count > vc4_crtc->dlist_size) { ++ DRM_DEBUG_KMS("dlist too large for CRTC (%d > %d).\n", ++ dlist_count, vc4_crtc->dlist_size); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static void vc4_crtc_atomic_flush(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_plane *plane; ++ bool debug_dump_regs = false; ++ u32 __iomem *dlist_next = vc4_crtc->dlist; ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); ++ vc4_hvs_dump_state(dev); ++ } ++ ++ /* Copy all the active planes' dlist contents to the hardware dlist. ++ * ++ * XXX: If the new display list was large enough that it ++ * overlapped a currently-read display list, we need to do ++ * something like disable scanout before putting in the new ++ * list. For now, we're safe because we only have the two ++ * planes. ++ */ ++ drm_atomic_crtc_for_each_plane(plane, crtc) { ++ dlist_next += vc4_plane_write_dlist(plane, dlist_next); ++ } ++ ++ if (dlist_next == vc4_crtc->dlist) { ++ /* If no planes were enabled, use the SCALER_CTL0_END ++ * at the start of the display list memory (in the ++ * bootloader section). We'll rewrite that ++ * SCALER_CTL0_END, just in case, though. ++ */ ++ writel(SCALER_CTL0_END, vc4->hvs->dlist); ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), 0); ++ } else { ++ writel(SCALER_CTL0_END, dlist_next); ++ dlist_next++; ++ ++ HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ (u32 __iomem *)vc4_crtc->dlist - ++ (u32 __iomem *)vc4->hvs->dlist); ++ ++ /* Make the next display list start after ours. */ ++ vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist); ++ vc4_crtc->dlist = dlist_next; ++ } ++ ++ if (debug_dump_regs) { ++ DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); ++ vc4_hvs_dump_state(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; ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ crtc->state->event = NULL; ++ } ++} ++ ++int vc4_enable_vblank(struct drm_device *dev, int crtc_id) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; ++ ++ CRTC_WRITE(PV_INTEN, PV_INT_VFP_START); ++ ++ return 0; ++} ++ ++void vc4_disable_vblank(struct drm_device *dev, int crtc_id) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; ++ ++ CRTC_WRITE(PV_INTEN, 0); ++} ++ ++static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) ++{ ++ struct drm_crtc *crtc = &vc4_crtc->base; ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ if (vc4_crtc->event) { ++ drm_crtc_send_vblank_event(crtc, vc4_crtc->event); ++ vc4_crtc->event = NULL; ++ } ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++} ++ ++static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) ++{ ++ struct vc4_crtc *vc4_crtc = data; ++ u32 stat = CRTC_READ(PV_INTSTAT); ++ irqreturn_t ret = IRQ_NONE; ++ ++ if (stat & PV_INT_VFP_START) { ++ CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); ++ drm_crtc_handle_vblank(&vc4_crtc->base); ++ vc4_crtc_handle_page_flip(vc4_crtc); ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++struct vc4_async_flip_state { ++ struct drm_crtc *crtc; ++ struct drm_framebuffer *fb; ++ struct drm_pending_vblank_event *event; ++ ++ struct vc4_seqno_cb cb; ++}; ++ ++/* Called when the V3D execution for the BO being flipped to is done, so that ++ * we can actually update the plane's address to point to it. ++ */ ++static void ++vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) ++{ ++ struct vc4_async_flip_state *flip_state = ++ container_of(cb, struct vc4_async_flip_state, cb); ++ struct drm_crtc *crtc = flip_state->crtc; ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane = crtc->primary; ++ ++ vc4_plane_async_set_fb(plane, flip_state->fb); ++ if (flip_state->event) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, flip_state->event); ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } ++ ++ drm_framebuffer_unreference(flip_state->fb); ++ kfree(flip_state); ++ ++ up(&vc4->async_modeset); ++} ++ ++/* Implements async (non-vblank-synced) page flips. ++ * ++ * The page flip ioctl needs to return immediately, so we grab the ++ * modeset semaphore on the pipe, and queue the address update for ++ * when V3D is done with the BO being flipped to. ++ */ ++static int vc4_async_page_flip(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, ++ struct drm_pending_vblank_event *event, ++ uint32_t flags) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_plane *plane = crtc->primary; ++ int ret = 0; ++ struct vc4_async_flip_state *flip_state; ++ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); ++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); ++ ++ flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL); ++ if (!flip_state) ++ return -ENOMEM; ++ ++ drm_framebuffer_reference(fb); ++ flip_state->fb = fb; ++ flip_state->crtc = crtc; ++ flip_state->event = event; ++ ++ /* Make sure all other async modesetes have landed. */ ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(flip_state); ++ return ret; ++ } ++ ++ /* Immediately update the plane's legacy fb pointer, so that later ++ * modeset prep sees the state that will be present when the semaphore ++ * is released. ++ */ ++ drm_atomic_set_fb_for_plane(plane->state, fb); ++ plane->fb = fb; ++ ++ vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, ++ vc4_async_page_flip_complete); ++ ++ /* Driver takes ownership of state on successful async commit. */ ++ return 0; ++} ++ ++static int vc4_page_flip(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, ++ struct drm_pending_vblank_event *event, ++ uint32_t flags) ++{ ++ if (flags & DRM_MODE_PAGE_FLIP_ASYNC) ++ return vc4_async_page_flip(crtc, fb, event, flags); ++ else ++ return drm_atomic_helper_page_flip(crtc, fb, event, flags); ++} ++ ++static const struct drm_crtc_funcs vc4_crtc_funcs = { ++ .set_config = drm_atomic_helper_set_config, ++ .destroy = vc4_crtc_destroy, ++ .page_flip = vc4_page_flip, ++ .set_property = NULL, ++ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ ++ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */ ++ .reset = drm_atomic_helper_crtc_reset, ++ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, ++}; ++ ++static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { ++ .mode_set_nofb = vc4_crtc_mode_set_nofb, ++ .disable = vc4_crtc_disable, ++ .enable = vc4_crtc_enable, ++ .atomic_check = vc4_crtc_atomic_check, ++ .atomic_flush = vc4_crtc_atomic_flush, ++}; ++ ++/* Frees the page flip event when the DRM device is closed with the ++ * event still outstanding. ++ */ ++void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ ++ if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) { ++ vc4_crtc->event->base.destroy(&vc4_crtc->event->base); ++ drm_crtc_vblank_put(crtc); ++ vc4_crtc->event = NULL; ++ } ++ ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++} ++ ++static const struct vc4_crtc_data pv0_data = { ++ .hvs_channel = 0, ++ .encoder0_type = VC4_ENCODER_TYPE_DSI0, ++ .encoder1_type = 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, ++}; ++ ++static const struct vc4_crtc_data pv2_data = { ++ .hvs_channel = 1, ++ .encoder0_type = VC4_ENCODER_TYPE_VEC, ++ .encoder1_type = VC4_ENCODER_TYPE_HDMI, ++}; ++ ++static const struct of_device_id vc4_crtc_dt_match[] = { ++ { .compatible = "brcm,bcm2835-pixelvalve0", .data = &pv0_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve1", .data = &pv1_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve2", .data = &pv2_data }, ++ {} ++}; ++ ++static void vc4_set_crtc_possible_masks(struct drm_device *drm, ++ struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ 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); ++ } ++ } ++} ++ ++static int vc4_crtc_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_crtc *vc4_crtc; ++ struct drm_crtc *crtc; ++ struct drm_plane *primary_plane, *cursor_plane; ++ const struct of_device_id *match; ++ int ret; ++ ++ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); ++ if (!vc4_crtc) ++ return -ENOMEM; ++ crtc = &vc4_crtc->base; ++ ++ match = of_match_device(vc4_crtc_dt_match, dev); ++ if (!match) ++ return -ENODEV; ++ vc4_crtc->data = match->data; ++ ++ vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(vc4_crtc->regs)) ++ return PTR_ERR(vc4_crtc->regs); ++ ++ /* For now, we create just the primary and the legacy cursor ++ * planes. We should be able to stack more planes on easily, ++ * but to do that we would need to compute the bandwidth ++ * requirement of the plane configuration, and reject ones ++ * that will take too much. ++ */ ++ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); ++ if (IS_ERR(primary_plane)) { ++ dev_err(dev, "failed to construct primary plane\n"); ++ ret = PTR_ERR(primary_plane); ++ goto err; ++ } ++ ++ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); ++ if (IS_ERR(cursor_plane)) { ++ dev_err(dev, "failed to construct cursor plane\n"); ++ ret = PTR_ERR(cursor_plane); ++ goto err_primary; ++ } ++ ++ drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane, ++ &vc4_crtc_funcs); ++ drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); ++ primary_plane->crtc = crtc; ++ cursor_plane->crtc = crtc; ++ vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc; ++ vc4_crtc->channel = vc4_crtc->data->hvs_channel; ++ ++ CRTC_WRITE(PV_INTEN, 0); ++ CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc); ++ if (ret) ++ goto err_cursor; ++ ++ vc4_set_crtc_possible_masks(drm, crtc); ++ ++ platform_set_drvdata(pdev, vc4_crtc); ++ ++ return 0; ++ ++err_cursor: ++ cursor_plane->funcs->destroy(cursor_plane); ++err_primary: ++ primary_plane->funcs->destroy(primary_plane); ++err: ++ return ret; ++} ++ ++static void vc4_crtc_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); ++ ++ vc4_crtc_destroy(&vc4_crtc->base); ++ ++ CRTC_WRITE(PV_INTEN, 0); ++ ++ platform_set_drvdata(pdev, NULL); ++} ++ ++static const struct component_ops vc4_crtc_ops = { ++ .bind = vc4_crtc_bind, ++ .unbind = vc4_crtc_unbind, ++}; ++ ++static int vc4_crtc_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_crtc_ops); ++} ++ ++static int vc4_crtc_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_crtc_ops); ++ return 0; ++} ++ ++struct platform_driver vc4_crtc_driver = { ++ .probe = vc4_crtc_dev_probe, ++ .remove = vc4_crtc_dev_remove, ++ .driver = { ++ .name = "vc4_crtc", ++ .of_match_table = vc4_crtc_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +new file mode 100644 +index 0000000..d76ad10 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -0,0 +1,42 @@ ++/* ++ * Copyright © 2014 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++static const struct drm_info_list vc4_debugfs_list[] = { ++ {"bo_stats", vc4_bo_stats_debugfs, 0}, ++ {"hdmi_regs", vc4_hdmi_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}, ++ {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2}, ++ {"v3d_ident", vc4_v3d_debugfs_ident, 0}, ++ {"v3d_regs", vc4_v3d_debugfs_regs, 0}, ++}; ++ ++#define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list) ++ ++int ++vc4_debugfs_init(struct drm_minor *minor) ++{ ++ return drm_debugfs_create_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, ++ minor->debugfs_root, minor); ++} ++ ++void ++vc4_debugfs_cleanup(struct drm_minor *minor) ++{ ++ drm_debugfs_remove_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c +new file mode 100644 +index 0000000..22061ae +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -0,0 +1,331 @@ ++/* ++ * Copyright (C) 2014-2015 Broadcom ++ * Copyright (C) 2013 Red Hat ++ * ++ * 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 ++#include "drm_fb_cma_helper.h" ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define DRIVER_NAME "vc4" ++#define DRIVER_DESC "Broadcom VC4 graphics" ++#define DRIVER_DATE "20140616" ++#define DRIVER_MAJOR 0 ++#define DRIVER_MINOR 0 ++#define DRIVER_PATCHLEVEL 0 ++ ++/* Helper function for mapping the regs on a platform device. */ ++void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index) ++{ ++ struct resource *res; ++ void __iomem *map; ++ ++ res = platform_get_resource(dev, IORESOURCE_MEM, index); ++ map = devm_ioremap_resource(&dev->dev, res); ++ if (IS_ERR(map)) { ++ DRM_ERROR("Failed to map registers: %ld\n", PTR_ERR(map)); ++ return map; ++ } ++ ++ return map; ++} ++ ++static void vc4_drm_preclose(struct drm_device *dev, struct drm_file *file) ++{ ++ struct drm_crtc *crtc; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) ++ vc4_cancel_page_flip(crtc, file); ++} ++ ++static void vc4_lastclose(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_restore_mode(vc4->fbdev); ++} ++ ++static const struct file_operations vc4_drm_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .unlocked_ioctl = drm_ioctl, ++ .mmap = vc4_mmap, ++ .poll = drm_poll, ++ .read = drm_read, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = drm_compat_ioctl, ++#endif ++ .llseek = noop_llseek, ++}; ++ ++static const struct drm_ioctl_desc vc4_drm_ioctls[] = { ++ DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0), ++ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl, ++ DRM_ROOT_ONLY), ++}; ++ ++static struct drm_driver vc4_drm_driver = { ++ .driver_features = (DRIVER_MODESET | ++ DRIVER_ATOMIC | ++ DRIVER_GEM | ++ DRIVER_HAVE_IRQ | ++ DRIVER_PRIME), ++ .lastclose = vc4_lastclose, ++ .preclose = vc4_drm_preclose, ++ ++ .irq_handler = vc4_irq, ++ .irq_preinstall = vc4_irq_preinstall, ++ .irq_postinstall = vc4_irq_postinstall, ++ .irq_uninstall = vc4_irq_uninstall, ++ ++ .enable_vblank = vc4_enable_vblank, ++ .disable_vblank = vc4_disable_vblank, ++ .get_vblank_counter = drm_vblank_count, ++ ++#if defined(CONFIG_DEBUG_FS) ++ .debugfs_init = vc4_debugfs_init, ++ .debugfs_cleanup = vc4_debugfs_cleanup, ++#endif ++ ++ .gem_create_object = vc4_create_object, ++ .gem_free_object = vc4_free_object, ++ .gem_vm_ops = &drm_gem_cma_vm_ops, ++ ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import = drm_gem_prime_import, ++ .gem_prime_export = vc4_prime_export, ++ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, ++ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, ++ .gem_prime_vmap = vc4_prime_vmap, ++ .gem_prime_vunmap = drm_gem_cma_prime_vunmap, ++ .gem_prime_mmap = vc4_prime_mmap, ++ ++ .dumb_create = vc4_dumb_create, ++ .dumb_map_offset = drm_gem_cma_dumb_map_offset, ++ .dumb_destroy = drm_gem_dumb_destroy, ++ ++ .ioctls = vc4_drm_ioctls, ++ .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), ++ .fops = &vc4_drm_fops, ++ ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++static int compare_dev(struct device *dev, void *data) ++{ ++ return dev == data; ++} ++ ++static void vc4_match_add_drivers(struct device *dev, ++ struct component_match **match, ++ struct platform_driver *const *drivers, ++ int count) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) { ++ struct device_driver *drv = &drivers[i]->driver; ++ struct device *p = NULL, *d; ++ ++ while ((d = bus_find_device(&platform_bus_type, p, drv, ++ (void *)platform_bus_type.match))) { ++ put_device(p); ++ component_match_add(dev, match, compare_dev, d); ++ p = d; ++ } ++ put_device(p); ++ } ++} ++ ++static int vc4_drm_bind(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm; ++ struct drm_connector *connector; ++ struct vc4_dev *vc4; ++ struct device_node *firmware_node; ++ int ret = 0; ++ ++ dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL); ++ if (!vc4) ++ return -ENOMEM; ++ ++ firmware_node = of_parse_phandle(dev->of_node, "firmware", 0); ++ vc4->firmware = rpi_firmware_get(firmware_node); ++ if (!vc4->firmware) { ++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); ++ return -EPROBE_DEFER; ++ } ++ of_node_put(firmware_node); ++ ++ drm = drm_dev_alloc(&vc4_drm_driver, dev); ++ if (!drm) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, drm); ++ vc4->dev = drm; ++ drm->dev_private = vc4; ++ ++ drm_dev_set_unique(drm, dev_name(dev)); ++ ++ vc4_bo_cache_init(drm); ++ ++ drm_mode_config_init(drm); ++ if (ret) ++ goto unref; ++ ++ vc4_gem_init(drm); ++ ++ ret = component_bind_all(dev, drm); ++ if (ret) ++ goto gem_destroy; ++ ++ ret = drm_dev_register(drm, 0); ++ if (ret < 0) ++ goto unbind_all; ++ ++ /* Connector registration has to occur after DRM device ++ * registration, because it creates sysfs entries based on the ++ * DRM device. ++ */ ++ list_for_each_entry(connector, &drm->mode_config.connector_list, head) { ++ ret = drm_connector_register(connector); ++ if (ret) ++ goto unregister; ++ } ++ ++ vc4_kms_load(drm); ++ ++ return 0; ++ ++unregister: ++ drm_dev_unregister(drm); ++unbind_all: ++ component_unbind_all(dev, drm); ++gem_destroy: ++ vc4_gem_destroy(drm); ++unref: ++ drm_dev_unref(drm); ++ vc4_bo_cache_destroy(drm); ++ return ret; ++} ++ ++static void vc4_drm_unbind(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_fini(vc4->fbdev); ++ ++ drm_mode_config_cleanup(drm); ++ ++ drm_put_dev(drm); ++} ++ ++static const struct component_master_ops vc4_drm_ops = { ++ .bind = vc4_drm_bind, ++ .unbind = vc4_drm_unbind, ++}; ++ ++static struct platform_driver *const component_drivers[] = { ++ &vc4_hdmi_driver, ++ &vc4_crtc_driver, ++ &vc4_hvs_driver, ++ &vc4_v3d_driver, ++}; ++ ++static int vc4_platform_drm_probe(struct platform_device *pdev) ++{ ++ struct component_match *match = NULL; ++ struct device *dev = &pdev->dev; ++ ++ vc4_match_add_drivers(dev, &match, ++ component_drivers, ARRAY_SIZE(component_drivers)); ++ ++ return component_master_add_with_match(dev, &vc4_drm_ops, match); ++} ++ ++static int vc4_platform_drm_remove(struct platform_device *pdev) ++{ ++ component_master_del(&pdev->dev, &vc4_drm_ops); ++ ++ return 0; ++} ++ ++static const struct of_device_id vc4_of_match[] = { ++ { .compatible = "brcm,bcm2835-vc4", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, vc4_of_match); ++ ++static struct platform_driver vc4_platform_driver = { ++ .probe = vc4_platform_drm_probe, ++ .remove = vc4_platform_drm_remove, ++ .driver = { ++ .name = "vc4-drm", ++ .of_match_table = vc4_of_match, ++ }, ++}; ++ ++static int __init vc4_drm_register(void) ++{ ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(component_drivers); i++) { ++ ret = platform_driver_register(component_drivers[i]); ++ if (ret) { ++ while (--i >= 0) ++ platform_driver_unregister(component_drivers[i]); ++ return ret; ++ } ++ } ++ return platform_driver_register(&vc4_platform_driver); ++} ++ ++static void __exit vc4_drm_unregister(void) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(component_drivers) - 1; i >= 0; i--) ++ platform_driver_unregister(component_drivers[i]); ++ ++ platform_driver_unregister(&vc4_platform_driver); ++} ++ ++module_init(vc4_drm_register); ++module_exit(vc4_drm_unregister); ++ ++MODULE_ALIAS("platform:vc4-drm"); ++MODULE_DESCRIPTION("Broadcom VC4 DRM Driver"); ++MODULE_AUTHOR("Eric Anholt "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +new file mode 100644 +index 0000000..03e037e +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -0,0 +1,462 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#include "drmP.h" ++#include "drm_gem_cma_helper.h" ++ ++struct vc4_dev { ++ struct drm_device *dev; ++ ++ struct vc4_hdmi *hdmi; ++ struct vc4_hvs *hvs; ++ struct vc4_crtc *crtc[3]; ++ struct vc4_v3d *v3d; ++ ++ struct drm_fbdev_cma *fbdev; ++ struct rpi_firmware *firmware; ++ ++ struct vc4_hang_state *hang_state; ++ ++ /* The kernel-space BO cache. Tracks buffers that have been ++ * unreferenced by all other users (refcounts of 0!) but not ++ * yet freed, so we can do cheap allocations. ++ */ ++ struct vc4_bo_cache { ++ /* Array of list heads for entries in the BO cache, ++ * based on number of pages, so we can do O(1) lookups ++ * in the cache when allocating. ++ */ ++ struct list_head *size_list; ++ uint32_t size_list_size; ++ ++ /* List of all BOs in the cache, ordered by age, so we ++ * can do O(1) lookups when trying to free old ++ * buffers. ++ */ ++ struct list_head time_list; ++ struct work_struct time_work; ++ struct timer_list time_timer; ++ } bo_cache; ++ ++ struct vc4_bo_stats { ++ u32 num_allocated; ++ u32 size_allocated; ++ u32 num_cached; ++ u32 size_cached; ++ } bo_stats; ++ ++ /* Protects bo_cache and the BO stats. */ ++ struct mutex bo_lock; ++ ++ /* Sequence number for the last job queued in job_list. ++ * Starts at 0 (no jobs emitted). ++ */ ++ uint64_t emit_seqno; ++ ++ /* Sequence number for the last completed job on the GPU. ++ * Starts at 0 (no jobs completed). ++ */ ++ uint64_t finished_seqno; ++ ++ /* List of all struct vc4_exec_info for jobs to be executed. ++ * The first job in the list is the one currently programmed ++ * into ct0ca/ct1ca for execution. ++ */ ++ struct list_head job_list; ++ /* List of the finished vc4_exec_infos waiting to be freed by ++ * job_done_work. ++ */ ++ struct list_head job_done_list; ++ /* Spinlock used to synchronize the job_list and seqno ++ * accesses between the IRQ handler and GEM ioctls. ++ */ ++ spinlock_t job_lock; ++ wait_queue_head_t job_wait_queue; ++ struct work_struct job_done_work; ++ ++ /* List of struct vc4_seqno_cb for callbacks to be made from a ++ * workqueue when the given seqno is passed. ++ */ ++ struct list_head seqno_cb_list; ++ ++ /* The binner overflow memory that's currently set up in ++ * BPOA/BPOS registers. When overflow occurs and a new one is ++ * allocated, the previous one will be moved to ++ * vc4->current_exec's free list. ++ */ ++ struct vc4_bo *overflow_mem; ++ struct work_struct overflow_mem_work; ++ ++ struct { ++ uint32_t last_ct0ca, last_ct1ca; ++ struct timer_list timer; ++ struct work_struct reset_work; ++ } hangcheck; ++ ++ struct semaphore async_modeset; ++}; ++ ++static inline struct vc4_dev * ++to_vc4_dev(struct drm_device *dev) ++{ ++ return (struct vc4_dev *)dev->dev_private; ++} ++ ++struct vc4_bo { ++ struct drm_gem_cma_object base; ++ ++ /* seqno of the last job to render to this BO. */ ++ uint64_t seqno; ++ ++ /* List entry for the BO's position in either ++ * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list ++ */ ++ struct list_head unref_head; ++ ++ /* Time in jiffies when the BO was put in vc4->bo_cache. */ ++ unsigned long free_time; ++ ++ /* List entry for the BO's position in vc4_dev->bo_cache.size_list */ ++ struct list_head size_head; ++ ++ /* Struct for shader validation state, if created by ++ * DRM_IOCTL_VC4_CREATE_SHADER_BO. ++ */ ++ struct vc4_validated_shader_info *validated_shader; ++}; ++ ++static inline struct vc4_bo * ++to_vc4_bo(struct drm_gem_object *bo) ++{ ++ return (struct vc4_bo *)bo; ++} ++ ++struct vc4_seqno_cb { ++ struct work_struct work; ++ uint64_t seqno; ++ void (*func)(struct vc4_seqno_cb *cb); ++}; ++ ++struct vc4_v3d { ++ struct platform_device *pdev; ++ void __iomem *regs; ++}; ++ ++struct vc4_hvs { ++ struct platform_device *pdev; ++ void __iomem *regs; ++ void __iomem *dlist; ++}; ++ ++struct vc4_plane { ++ struct drm_plane base; ++}; ++ ++static inline struct vc4_plane * ++to_vc4_plane(struct drm_plane *plane) ++{ ++ return (struct vc4_plane *)plane; ++} ++ ++enum vc4_encoder_type { ++ VC4_ENCODER_TYPE_HDMI, ++ VC4_ENCODER_TYPE_VEC, ++ VC4_ENCODER_TYPE_DSI0, ++ VC4_ENCODER_TYPE_DSI1, ++ VC4_ENCODER_TYPE_SMI, ++ VC4_ENCODER_TYPE_DPI, ++}; ++ ++struct vc4_encoder { ++ struct drm_encoder base; ++ enum vc4_encoder_type type; ++ u32 clock_select; ++}; ++ ++static inline struct vc4_encoder * ++to_vc4_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_encoder, base); ++} ++ ++#define V3D_READ(offset) readl(vc4->v3d->regs + offset) ++#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset) ++#define HVS_READ(offset) readl(vc4->hvs->regs + offset) ++#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset) ++ ++struct vc4_exec_info { ++ /* Sequence number for this bin/render job. */ ++ uint64_t seqno; ++ ++ /* Kernel-space copy of the ioctl arguments */ ++ struct drm_vc4_submit_cl *args; ++ ++ /* This is the array of BOs that were looked up at the start of exec. ++ * Command validation will use indices into this array. ++ */ ++ struct drm_gem_cma_object **bo; ++ uint32_t bo_count; ++ ++ /* Pointers for our position in vc4->job_list */ ++ struct list_head head; ++ ++ /* List of other BOs used in the job that need to be released ++ * once the job is complete. ++ */ ++ struct list_head unref_list; ++ ++ /* Current unvalidated indices into @bo loaded by the non-hardware ++ * VC4_PACKET_GEM_HANDLES. ++ */ ++ uint32_t bo_index[2]; ++ ++ /* This is the BO where we store the validated command lists, shader ++ * records, and uniforms. ++ */ ++ struct drm_gem_cma_object *exec_bo; ++ ++ /** ++ * This tracks the per-shader-record state (packet 64) that ++ * determines the length of the shader record and the offset ++ * it's expected to be found at. It gets read in from the ++ * command lists. ++ */ ++ struct vc4_shader_state { ++ uint32_t addr; ++ /* Maximum vertex index referenced by any primitive using this ++ * shader state. ++ */ ++ uint32_t max_index; ++ } *shader_state; ++ ++ /** How many shader states the user declared they were using. */ ++ uint32_t shader_state_size; ++ /** How many shader state records the validator has seen. */ ++ uint32_t shader_state_count; ++ ++ bool found_tile_binning_mode_config_packet; ++ bool found_start_tile_binning_packet; ++ bool found_increment_semaphore_packet; ++ bool found_flush; ++ uint8_t bin_tiles_x, bin_tiles_y; ++ struct drm_gem_cma_object *tile_bo; ++ uint32_t tile_alloc_offset; ++ ++ /** ++ * Computed addresses pointing into exec_bo where we start the ++ * bin thread (ct0) and render thread (ct1). ++ */ ++ uint32_t ct0ca, ct0ea; ++ uint32_t ct1ca, ct1ea; ++ ++ /* Pointer to the unvalidated bin CL (if present). */ ++ void *bin_u; ++ ++ /* Pointers to the shader recs. These paddr gets incremented as CL ++ * packets are relocated in validate_gl_shader_state, and the vaddrs ++ * (u and v) get incremented and size decremented as the shader recs ++ * themselves are validated. ++ */ ++ void *shader_rec_u; ++ void *shader_rec_v; ++ uint32_t shader_rec_p; ++ uint32_t shader_rec_size; ++ ++ /* Pointers to the uniform data. These pointers are incremented, and ++ * size decremented, as each batch of uniforms is uploaded. ++ */ ++ void *uniforms_u; ++ void *uniforms_v; ++ uint32_t uniforms_p; ++ uint32_t uniforms_size; ++}; ++ ++static inline struct vc4_exec_info * ++vc4_first_job(struct vc4_dev *vc4) ++{ ++ if (list_empty(&vc4->job_list)) ++ return NULL; ++ return list_first_entry(&vc4->job_list, struct vc4_exec_info, head); ++} ++ ++/** ++ * struct vc4_texture_sample_info - saves the offsets into the UBO for texture ++ * setup parameters. ++ * ++ * This will be used at draw time to relocate the reference to the texture ++ * contents in p0, and validate that the offset combined with ++ * width/height/stride/etc. from p1 and p2/p3 doesn't sample outside the BO. ++ * Note that the hardware treats unprovided config parameters as 0, so not all ++ * of them need to be set up for every texure sample, and we'll store ~0 as ++ * the offset to mark the unused ones. ++ * ++ * See the VC4 3D architecture guide page 41 ("Texture and Memory Lookup Unit ++ * Setup") for definitions of the texture parameters. ++ */ ++struct vc4_texture_sample_info { ++ bool is_direct; ++ uint32_t p_offset[4]; ++}; ++ ++/** ++ * struct vc4_validated_shader_info - information about validated shaders that ++ * needs to be used from command list validation. ++ * ++ * For a given shader, each time a shader state record references it, we need ++ * to verify that the shader doesn't read more uniforms than the shader state ++ * record's uniform BO pointer can provide, and we need to apply relocations ++ * and validate the shader state record's uniforms that define the texture ++ * samples. ++ */ ++struct vc4_validated_shader_info { ++ uint32_t uniforms_size; ++ uint32_t uniforms_src_size; ++ uint32_t num_texture_samples; ++ struct vc4_texture_sample_info *texture_samples; ++}; ++ ++/** ++ * _wait_for - magic (register) wait macro ++ * ++ * Does the right thing for modeset paths when run under kdgb or similar atomic ++ * contexts. Note that it's important that we check the condition again after ++ * having timed out, since the timeout could be due to preemption or similar and ++ * we've never had a chance to check the condition before the timeout. ++ */ ++#define _wait_for(COND, MS, W) ({ \ ++ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \ ++ int ret__ = 0; \ ++ while (!(COND)) { \ ++ if (time_after(jiffies, timeout__)) { \ ++ if (!(COND)) \ ++ ret__ = -ETIMEDOUT; \ ++ break; \ ++ } \ ++ if (W && drm_can_sleep()) { \ ++ msleep(W); \ ++ } else { \ ++ cpu_relax(); \ ++ } \ ++ } \ ++ ret__; \ ++}) ++ ++#define wait_for(COND, MS) _wait_for(COND, MS, 1) ++ ++/* vc4_bo.c */ ++struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size); ++void vc4_free_object(struct drm_gem_object *gem_obj); ++struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size, ++ bool from_cache); ++int vc4_dumb_create(struct drm_file *file_priv, ++ struct drm_device *dev, ++ struct drm_mode_create_dumb *args); ++struct dma_buf *vc4_prime_export(struct drm_device *dev, ++ struct drm_gem_object *obj, int flags); ++int vc4_create_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_mmap(struct file *filp, struct vm_area_struct *vma); ++int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); ++void *vc4_prime_vmap(struct drm_gem_object *obj); ++void vc4_bo_cache_init(struct drm_device *dev); ++void vc4_bo_cache_destroy(struct drm_device *dev); ++int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); ++ ++/* vc4_crtc.c */ ++extern struct platform_driver vc4_crtc_driver; ++int vc4_enable_vblank(struct drm_device *dev, int crtc_id); ++void vc4_disable_vblank(struct drm_device *dev, int crtc_id); ++void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); ++int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); ++ ++/* vc4_debugfs.c */ ++int vc4_debugfs_init(struct drm_minor *minor); ++void vc4_debugfs_cleanup(struct drm_minor *minor); ++ ++/* vc4_drv.c */ ++void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); ++ ++/* vc4_gem.c */ ++void vc4_gem_init(struct drm_device *dev); ++void vc4_gem_destroy(struct drm_device *dev); ++int vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int vc4_wait_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++void vc4_submit_next_job(struct drm_device *dev); ++int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, ++ uint64_t timeout_ns, bool interruptible); ++void vc4_job_handle_completed(struct vc4_dev *vc4); ++int vc4_queue_seqno_cb(struct drm_device *dev, ++ struct vc4_seqno_cb *cb, uint64_t seqno, ++ void (*func)(struct vc4_seqno_cb *cb)); ++ ++/* vc4_hdmi.c */ ++extern struct platform_driver vc4_hdmi_driver; ++int vc4_hdmi_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); ++int vc4_irq_postinstall(struct drm_device *dev); ++void vc4_irq_uninstall(struct drm_device *dev); ++void vc4_irq_reset(struct drm_device *dev); ++ ++/* vc4_hvs.c */ ++extern struct platform_driver vc4_hvs_driver; ++void vc4_hvs_dump_state(struct drm_device *dev); ++int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused); ++ ++/* vc4_kms.c */ ++int vc4_kms_load(struct drm_device *dev); ++ ++/* vc4_plane.c */ ++struct drm_plane *vc4_plane_init(struct drm_device *dev, ++ enum drm_plane_type type); ++u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); ++u32 vc4_plane_dlist_size(struct drm_plane_state *state); ++void vc4_plane_async_set_fb(struct drm_plane *plane, ++ struct drm_framebuffer *fb); ++ ++/* vc4_v3d.c */ ++extern struct platform_driver vc4_v3d_driver; ++int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); ++int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); ++int vc4_v3d_set_power(struct vc4_dev *vc4, bool on); ++ ++/* vc4_validate.c */ ++int ++vc4_validate_bin_cl(struct drm_device *dev, ++ void *validated, ++ void *unvalidated, ++ struct vc4_exec_info *exec); ++ ++int ++vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec); ++ ++struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec, ++ uint32_t hindex); ++ ++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec); ++ ++bool vc4_check_tex_size(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *fbo, ++ uint32_t offset, uint8_t tiling_format, ++ uint32_t width, uint32_t height, uint8_t cpp); ++ ++/* vc4_validate_shader.c */ ++struct vc4_validated_shader_info * ++vc4_validate_shader(struct drm_gem_cma_object *shader_obj); +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +new file mode 100644 +index 0000000..39f29e7 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -0,0 +1,867 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++#include "vc4_trace.h" ++ ++static void ++vc4_queue_hangcheck(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ mod_timer(&vc4->hangcheck.timer, ++ round_jiffies_up(jiffies + msecs_to_jiffies(100))); ++} ++ ++struct vc4_hang_state { ++ struct drm_vc4_get_hang_state user_state; ++ ++ u32 bo_count; ++ struct drm_gem_object **bo; ++}; ++ ++static void ++vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state) ++{ ++ unsigned int i; ++ ++ mutex_lock(&dev->struct_mutex); ++ for (i = 0; i < state->user_state.bo_count; i++) ++ drm_gem_object_unreference(state->bo[i]); ++ mutex_unlock(&dev->struct_mutex); ++ ++ kfree(state); ++} ++ ++int ++vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_get_hang_state *get_state = data; ++ struct drm_vc4_get_hang_state_bo *bo_state; ++ struct vc4_hang_state *kernel_state; ++ struct drm_vc4_get_hang_state *state; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; ++ u32 i; ++ int ret; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ kernel_state = vc4->hang_state; ++ if (!kernel_state) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return -ENOENT; ++ } ++ state = &kernel_state->user_state; ++ ++ /* If the user's array isn't big enough, just return the ++ * required array size. ++ */ ++ if (get_state->bo_count < state->bo_count) { ++ get_state->bo_count = state->bo_count; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return 0; ++ } ++ ++ vc4->hang_state = NULL; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ /* Save the user's BO pointer, so we don't stomp it with the memcpy. */ ++ state->bo = get_state->bo; ++ memcpy(get_state, state, sizeof(*state)); ++ ++ bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL); ++ if (!bo_state) { ++ ret = -ENOMEM; ++ goto err_free; ++ } ++ ++ for (i = 0; i < state->bo_count; i++) { ++ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]); ++ u32 handle; ++ ++ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i], ++ &handle); ++ ++ if (ret) { ++ state->bo_count = i - 1; ++ goto err; ++ } ++ bo_state[i].handle = handle; ++ bo_state[i].paddr = vc4_bo->base.paddr; ++ bo_state[i].size = vc4_bo->base.base.size; ++ } ++ ++ ret = copy_to_user((void __user *)(uintptr_t)get_state->bo, ++ bo_state, ++ state->bo_count * sizeof(*bo_state)); ++ kfree(bo_state); ++ ++err_free: ++ ++ vc4_free_hang_state(dev, kernel_state); ++ ++err: ++ return ret; ++} ++ ++static void ++vc4_save_hang_state(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_vc4_get_hang_state *state; ++ struct vc4_hang_state *kernel_state; ++ struct vc4_exec_info *exec; ++ struct vc4_bo *bo; ++ unsigned long irqflags; ++ unsigned int i, unref_list_count; ++ ++ kernel_state = kcalloc(1, sizeof(*state), GFP_KERNEL); ++ if (!kernel_state) ++ return; ++ ++ state = &kernel_state->user_state; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ exec = vc4_first_job(vc4); ++ if (!exec) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return; ++ } ++ ++ unref_list_count = 0; ++ list_for_each_entry(bo, &exec->unref_list, unref_head) ++ unref_list_count++; ++ ++ state->bo_count = exec->bo_count + unref_list_count; ++ kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo), ++ GFP_ATOMIC); ++ if (!kernel_state->bo) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return; ++ } ++ ++ for (i = 0; i < exec->bo_count; i++) { ++ drm_gem_object_reference(&exec->bo[i]->base); ++ kernel_state->bo[i] = &exec->bo[i]->base; ++ } ++ ++ list_for_each_entry(bo, &exec->unref_list, unref_head) { ++ drm_gem_object_reference(&bo->base.base); ++ kernel_state->bo[i] = &bo->base.base; ++ i++; ++ } ++ ++ state->start_bin = exec->ct0ca; ++ state->start_render = exec->ct1ca; ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ state->ct0ca = V3D_READ(V3D_CTNCA(0)); ++ state->ct0ea = V3D_READ(V3D_CTNEA(0)); ++ ++ state->ct1ca = V3D_READ(V3D_CTNCA(1)); ++ state->ct1ea = V3D_READ(V3D_CTNEA(1)); ++ ++ state->ct0cs = V3D_READ(V3D_CTNCS(0)); ++ state->ct1cs = V3D_READ(V3D_CTNCS(1)); ++ ++ state->ct0ra0 = V3D_READ(V3D_CT00RA0); ++ state->ct1ra0 = V3D_READ(V3D_CT01RA0); ++ ++ state->bpca = V3D_READ(V3D_BPCA); ++ state->bpcs = V3D_READ(V3D_BPCS); ++ state->bpoa = V3D_READ(V3D_BPOA); ++ state->bpos = V3D_READ(V3D_BPOS); ++ ++ state->vpmbase = V3D_READ(V3D_VPMBASE); ++ ++ state->dbge = V3D_READ(V3D_DBGE); ++ state->fdbgo = V3D_READ(V3D_FDBGO); ++ state->fdbgb = V3D_READ(V3D_FDBGB); ++ state->fdbgr = V3D_READ(V3D_FDBGR); ++ state->fdbgs = V3D_READ(V3D_FDBGS); ++ state->errstat = V3D_READ(V3D_ERRSTAT); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ if (vc4->hang_state) { ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ vc4_free_hang_state(dev, kernel_state); ++ } else { ++ vc4->hang_state = kernel_state; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ } ++} ++ ++static void ++vc4_reset(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ DRM_INFO("Resetting GPU.\n"); ++ vc4_v3d_set_power(vc4, false); ++ vc4_v3d_set_power(vc4, true); ++ ++ vc4_irq_reset(dev); ++ ++ /* Rearm the hangcheck -- another job might have been waiting ++ * for our hung one to get kicked off, and vc4_irq_reset() ++ * would have started it. ++ */ ++ vc4_queue_hangcheck(dev); ++} ++ ++static void ++vc4_reset_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, hangcheck.reset_work); ++ ++ vc4_save_hang_state(vc4->dev); ++ ++ vc4_reset(vc4->dev); ++} ++ ++static void ++vc4_hangcheck_elapsed(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t ct0ca, ct1ca; ++ ++ /* If idle, we can stop watching for hangs. */ ++ if (list_empty(&vc4->job_list)) ++ return; ++ ++ ct0ca = V3D_READ(V3D_CTNCA(0)); ++ ct1ca = V3D_READ(V3D_CTNCA(1)); ++ ++ /* If we've made any progress in execution, rearm the timer ++ * and wait. ++ */ ++ if (ct0ca != vc4->hangcheck.last_ct0ca || ++ ct1ca != vc4->hangcheck.last_ct1ca) { ++ vc4->hangcheck.last_ct0ca = ct0ca; ++ vc4->hangcheck.last_ct1ca = ct1ca; ++ vc4_queue_hangcheck(dev); ++ return; ++ } ++ ++ /* We've gone too long with no progress, reset. This has to ++ * be done from a work struct, since resetting can sleep and ++ * this timer hook isn't allowed to. ++ */ ++ schedule_work(&vc4->hangcheck.reset_work); ++} ++ ++static void ++submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Set the current and end address of the control list. ++ * Writing the end register is what starts the job. ++ */ ++ V3D_WRITE(V3D_CTNCA(thread), start); ++ V3D_WRITE(V3D_CTNEA(thread), end); ++} ++ ++int ++vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, ++ bool interruptible) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ unsigned long timeout_expire; ++ DEFINE_WAIT(wait); ++ ++ if (vc4->finished_seqno >= seqno) ++ return 0; ++ ++ if (timeout_ns == 0) ++ return -ETIME; ++ ++ timeout_expire = jiffies + nsecs_to_jiffies(timeout_ns); ++ ++ trace_vc4_wait_for_seqno_begin(dev, seqno, timeout_ns); ++ for (;;) { ++ prepare_to_wait(&vc4->job_wait_queue, &wait, ++ interruptible ? TASK_INTERRUPTIBLE : ++ TASK_UNINTERRUPTIBLE); ++ ++ if (interruptible && signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; ++ } ++ ++ if (vc4->finished_seqno >= seqno) ++ break; ++ ++ if (timeout_ns != ~0ull) { ++ if (time_after_eq(jiffies, timeout_expire)) { ++ ret = -ETIME; ++ break; ++ } ++ schedule_timeout(timeout_expire - jiffies); ++ } else { ++ schedule(); ++ } ++ } ++ ++ finish_wait(&vc4->job_wait_queue, &wait); ++ trace_vc4_wait_for_seqno_end(dev, seqno); ++ ++ if (ret && ret != -ERESTARTSYS) { ++ DRM_ERROR("timeout waiting for render thread idle\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ++vc4_flush_caches(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Flush the GPU L2 caches. These caches sit on top of system ++ * L3 (the 128kb or so shared with the CPU), and are ++ * non-allocating in the L3. ++ */ ++ V3D_WRITE(V3D_L2CACTL, ++ V3D_L2CACTL_L2CCLR); ++ ++ V3D_WRITE(V3D_SLCACTL, ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T1CC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_T0CC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_UCC) | ++ VC4_SET_FIELD(0xf, V3D_SLCACTL_ICC)); ++} ++ ++/* Sets the registers for the next job to be actually be executed in ++ * the hardware. ++ * ++ * The job_lock should be held during this. ++ */ ++void ++vc4_submit_next_job(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_exec_info *exec = vc4_first_job(vc4); ++ ++ if (!exec) ++ return; ++ ++ vc4_flush_caches(dev); ++ ++ /* Disable the binner's pre-loaded overflow memory address */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ if (exec->ct0ca != exec->ct0ea) ++ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea); ++ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea); ++} ++ ++static void ++vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) ++{ ++ struct vc4_bo *bo; ++ unsigned i; ++ ++ for (i = 0; i < exec->bo_count; i++) { ++ bo = to_vc4_bo(&exec->bo[i]->base); ++ bo->seqno = seqno; ++ } ++ ++ list_for_each_entry(bo, &exec->unref_list, unref_head) { ++ bo->seqno = seqno; ++ } ++} ++ ++/* Queues a struct vc4_exec_info for execution. If no job is ++ * currently executing, then submits it. ++ * ++ * Unlike most GPUs, our hardware only handles one command list at a ++ * time. To queue multiple jobs at once, we'd need to edit the ++ * previous command list to have a jump to the new one at the end, and ++ * then bump the end address. That's a change for a later date, ++ * though. ++ */ ++static void ++vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint64_t seqno; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ ++ seqno = ++vc4->emit_seqno; ++ exec->seqno = seqno; ++ vc4_update_bo_seqnos(exec, seqno); ++ ++ list_add_tail(&exec->head, &vc4->job_list); ++ ++ /* If no job was executing, kick ours off. Otherwise, it'll ++ * get started when the previous job's frame done interrupt ++ * occurs. ++ */ ++ if (vc4_first_job(vc4) == exec) { ++ vc4_submit_next_job(dev); ++ vc4_queue_hangcheck(dev); ++ } ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} ++ ++/** ++ * Looks up a bunch of GEM handles for BOs and stores the array for ++ * use in the command validator that actually writes relocated ++ * addresses pointing to them. ++ */ ++static int ++vc4_cl_lookup_bos(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct vc4_exec_info *exec) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ uint32_t *handles; ++ int ret = 0; ++ int i; ++ ++ exec->bo_count = args->bo_handle_count; ++ ++ if (!exec->bo_count) { ++ /* See comment on bo_index for why we have to check ++ * this. ++ */ ++ DRM_ERROR("Rendering requires BOs to validate\n"); ++ return -EINVAL; ++ } ++ ++ exec->bo = kcalloc(exec->bo_count, sizeof(struct drm_gem_cma_object *), ++ GFP_KERNEL); ++ if (!exec->bo) { ++ DRM_ERROR("Failed to allocate validated BO pointers\n"); ++ return -ENOMEM; ++ } ++ ++ handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t)); ++ if (!handles) { ++ DRM_ERROR("Failed to allocate incoming GEM handles\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(handles, ++ (void __user *)(uintptr_t)args->bo_handles, ++ exec->bo_count * sizeof(uint32_t)); ++ if (ret) { ++ DRM_ERROR("Failed to copy in GEM handles\n"); ++ goto fail; ++ } ++ ++ spin_lock(&file_priv->table_lock); ++ for (i = 0; i < exec->bo_count; i++) { ++ struct drm_gem_object *bo = idr_find(&file_priv->object_idr, ++ handles[i]); ++ if (!bo) { ++ DRM_ERROR("Failed to look up GEM BO %d: %d\n", ++ i, handles[i]); ++ ret = -EINVAL; ++ spin_unlock(&file_priv->table_lock); ++ goto fail; ++ } ++ drm_gem_object_reference(bo); ++ exec->bo[i] = (struct drm_gem_cma_object *)bo; ++ } ++ spin_unlock(&file_priv->table_lock); ++ ++fail: ++ kfree(handles); ++ return 0; ++} ++ ++static int ++vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ void *temp = NULL; ++ void *bin; ++ int ret = 0; ++ uint32_t bin_offset = 0; ++ uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size, ++ 16); ++ uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size; ++ uint32_t exec_size = uniforms_offset + args->uniforms_size; ++ uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) * ++ args->shader_rec_count); ++ struct vc4_bo *bo; ++ ++ if (uniforms_offset < shader_rec_offset || ++ exec_size < uniforms_offset || ++ args->shader_rec_count >= (UINT_MAX / ++ sizeof(struct vc4_shader_state)) || ++ temp_size < exec_size) { ++ DRM_ERROR("overflow in exec arguments\n"); ++ goto fail; ++ } ++ ++ /* Allocate space where we'll store the copied in user command lists ++ * and shader records. ++ * ++ * We don't just copy directly into the BOs because we need to ++ * read the contents back for validation, and I think the ++ * bo->vaddr is uncached access. ++ */ ++ temp = kmalloc(temp_size, GFP_KERNEL); ++ if (!temp) { ++ DRM_ERROR("Failed to allocate storage for copying " ++ "in bin/render CLs.\n"); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ bin = temp + bin_offset; ++ exec->shader_rec_u = temp + shader_rec_offset; ++ exec->uniforms_u = temp + uniforms_offset; ++ exec->shader_state = temp + exec_size; ++ exec->shader_state_size = args->shader_rec_count; ++ ++ ret = copy_from_user(bin, ++ (void __user *)(uintptr_t)args->bin_cl, ++ args->bin_cl_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in bin cl\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(exec->shader_rec_u, ++ (void __user *)(uintptr_t)args->shader_rec, ++ args->shader_rec_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in shader recs\n"); ++ goto fail; ++ } ++ ++ ret = copy_from_user(exec->uniforms_u, ++ (void __user *)(uintptr_t)args->uniforms, ++ args->uniforms_size); ++ if (ret) { ++ DRM_ERROR("Failed to copy in uniforms cl\n"); ++ goto fail; ++ } ++ ++ bo = vc4_bo_create(dev, exec_size, true); ++ if (!bo) { ++ DRM_ERROR("Couldn't allocate BO for binning\n"); ++ ret = PTR_ERR(exec->exec_bo); ++ goto fail; ++ } ++ exec->exec_bo = &bo->base; ++ ++ list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head, ++ &exec->unref_list); ++ ++ exec->ct0ca = exec->exec_bo->paddr + bin_offset; ++ ++ exec->bin_u = bin; ++ ++ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset; ++ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset; ++ exec->shader_rec_size = args->shader_rec_size; ++ ++ exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset; ++ exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset; ++ exec->uniforms_size = args->uniforms_size; ++ ++ ret = vc4_validate_bin_cl(dev, ++ exec->exec_bo->vaddr + bin_offset, ++ bin, ++ exec); ++ if (ret) ++ goto fail; ++ ++ ret = vc4_validate_shader_recs(dev, exec); ++ ++fail: ++ kfree(temp); ++ return ret; ++} ++ ++static void ++vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ unsigned i; ++ ++ /* Need the struct lock for drm_gem_object_unreference(). */ ++ mutex_lock(&dev->struct_mutex); ++ if (exec->bo) { ++ for (i = 0; i < exec->bo_count; i++) ++ drm_gem_object_unreference(&exec->bo[i]->base); ++ kfree(exec->bo); ++ } ++ ++ while (!list_empty(&exec->unref_list)) { ++ struct vc4_bo *bo = list_first_entry(&exec->unref_list, ++ struct vc4_bo, unref_head); ++ list_del(&bo->unref_head); ++ drm_gem_object_unreference(&bo->base.base); ++ } ++ mutex_unlock(&dev->struct_mutex); ++ ++ kfree(exec); ++} ++ ++void ++vc4_job_handle_completed(struct vc4_dev *vc4) ++{ ++ unsigned long irqflags; ++ struct vc4_seqno_cb *cb, *cb_temp; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ while (!list_empty(&vc4->job_done_list)) { ++ struct vc4_exec_info *exec = ++ list_first_entry(&vc4->job_done_list, ++ struct vc4_exec_info, head); ++ list_del(&exec->head); ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ vc4_complete_exec(vc4->dev, exec); ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ } ++ ++ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) { ++ if (cb->seqno <= vc4->finished_seqno) { ++ list_del_init(&cb->work.entry); ++ schedule_work(&cb->work); ++ } ++ } ++ ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} ++ ++static void vc4_seqno_cb_work(struct work_struct *work) ++{ ++ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work); ++ ++ cb->func(cb); ++} ++ ++int vc4_queue_seqno_cb(struct drm_device *dev, ++ struct vc4_seqno_cb *cb, uint64_t seqno, ++ void (*func)(struct vc4_seqno_cb *cb)) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ unsigned long irqflags; ++ ++ cb->func = func; ++ INIT_WORK(&cb->work, vc4_seqno_cb_work); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ if (seqno > vc4->finished_seqno) { ++ cb->seqno = seqno; ++ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list); ++ } else { ++ schedule_work(&cb->work); ++ } ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ return ret; ++} ++ ++/* Scheduled when any job has been completed, this walks the list of ++ * jobs that had completed and unrefs their BOs and frees their exec ++ * structs. ++ */ ++static void ++vc4_job_done_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, job_done_work); ++ ++ vc4_job_handle_completed(vc4); ++} ++ ++static int ++vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev, ++ uint64_t seqno, ++ uint64_t *timeout_ns) ++{ ++ unsigned long start = jiffies; ++ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns, true); ++ ++ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) { ++ uint64_t delta = jiffies_to_nsecs(jiffies - start); ++ ++ if (*timeout_ns >= delta) ++ *timeout_ns -= delta; ++ } ++ ++ return ret; ++} ++ ++int ++vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_vc4_wait_seqno *args = data; ++ ++ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno, ++ &args->timeout_ns); ++} ++ ++int ++vc4_wait_bo_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ int ret; ++ struct drm_vc4_wait_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ struct vc4_bo *bo; ++ ++ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); ++ return -EINVAL; ++ } ++ bo = to_vc4_bo(gem_obj); ++ ++ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, ++ &args->timeout_ns); ++ ++ drm_gem_object_unreference_unlocked(gem_obj); ++ return ret; ++} ++ ++/** ++ * Submits a command list to the VC4. ++ * ++ * This is what is called batchbuffer emitting on other hardware. ++ */ ++int ++vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct drm_vc4_submit_cl *args = data; ++ struct vc4_exec_info *exec; ++ int ret; ++ ++ if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { ++ DRM_ERROR("Unknown flags: 0x%02x\n", args->flags); ++ return -EINVAL; ++ } ++ ++ exec = kcalloc(1, sizeof(*exec), GFP_KERNEL); ++ if (!exec) { ++ DRM_ERROR("malloc failure on exec struct\n"); ++ return -ENOMEM; ++ } ++ ++ exec->args = args; ++ INIT_LIST_HEAD(&exec->unref_list); ++ ++ ret = vc4_cl_lookup_bos(dev, file_priv, exec); ++ if (ret) ++ goto fail; ++ ++ if (exec->args->bin_cl_size != 0) { ++ ret = vc4_get_bcl(dev, exec); ++ if (ret) ++ goto fail; ++ } else { ++ exec->ct0ca = 0; ++ exec->ct0ea = 0; ++ } ++ ++ ret = vc4_get_rcl(dev, exec); ++ if (ret) ++ goto fail; ++ ++ /* Clear this out of the struct we'll be putting in the queue, ++ * since it's part of our stack. ++ */ ++ exec->args = NULL; ++ ++ vc4_queue_submit(dev, exec); ++ ++ /* Return the seqno for our job. */ ++ args->seqno = vc4->emit_seqno; ++ ++ return 0; ++ ++fail: ++ vc4_complete_exec(vc4->dev, exec); ++ ++ return ret; ++} ++ ++void ++vc4_gem_init(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ INIT_LIST_HEAD(&vc4->job_list); ++ INIT_LIST_HEAD(&vc4->job_done_list); ++ INIT_LIST_HEAD(&vc4->seqno_cb_list); ++ spin_lock_init(&vc4->job_lock); ++ ++ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work); ++ setup_timer(&vc4->hangcheck.timer, ++ vc4_hangcheck_elapsed, ++ (unsigned long)dev); ++ ++ INIT_WORK(&vc4->job_done_work, vc4_job_done_work); ++} ++ ++void ++vc4_gem_destroy(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Waiting for exec to finish would need to be done before ++ * unregistering V3D. ++ */ ++ WARN_ON(vc4->emit_seqno != vc4->finished_seqno); ++ ++ /* V3D should already have disabled its interrupt and cleared ++ * the overflow allocation registers. Now free the object. ++ */ ++ if (vc4->overflow_mem) { ++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); ++ vc4->overflow_mem = NULL; ++ } ++ ++ vc4_bo_cache_destroy(dev); ++ ++ if (vc4->hang_state) ++ vc4_free_hang_state(dev, vc4->hang_state); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +new file mode 100644 +index 0000000..d15c529 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -0,0 +1,592 @@ ++/* ++ * Copyright (C) 2015 Broadcom ++ * Copyright (c) 2014 The Linux Foundation. All rights reserved. ++ * Copyright (C) 2013 Red Hat ++ * Author: Rob Clark ++ * ++ * 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 Falcon HDMI module ++ * ++ * The HDMI core has a state machine and a PHY. Most of the unit ++ * operates off of the HSM clock from CPRMAN. It also internally uses ++ * the PLLH_PIX clock for the PHY. ++ */ ++ ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_edid.h" ++#include "linux/clk.h" ++#include "linux/component.h" ++#include "linux/i2c.h" ++#include "linux/of_gpio.h" ++#include "linux/of_platform.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++/* General HDMI hardware state. */ ++struct vc4_hdmi { ++ struct platform_device *pdev; ++ ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ ++ struct i2c_adapter *ddc; ++ void __iomem *hdmicore_regs; ++ void __iomem *hd_regs; ++ int hpd_gpio; ++ ++ struct clk *pixel_clock; ++ struct clk *hsm_clock; ++}; ++ ++#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) ++#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) ++#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) ++#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) ++ ++/* VC4 HDMI encoder KMS struct */ ++struct vc4_hdmi_encoder { ++ struct vc4_encoder base; ++ bool hdmi_monitor; ++}; ++ ++static inline struct vc4_hdmi_encoder * ++to_vc4_hdmi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_hdmi_encoder, base.base); ++} ++ ++/* VC4 HDMI connector KMS struct */ ++struct vc4_hdmi_connector { ++ struct drm_connector base; ++ ++ /* 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_hdmi_connector * ++to_vc4_hdmi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_hdmi_connector, base); ++} ++ ++#define HDMI_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} hdmi_regs[] = { ++ HDMI_REG(VC4_HDMI_CORE_REV), ++ HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), ++ HDMI_REG(VC4_HDMI_HOTPLUG_INT), ++ HDMI_REG(VC4_HDMI_HOTPLUG), ++ HDMI_REG(VC4_HDMI_HORZA), ++ HDMI_REG(VC4_HDMI_HORZB), ++ HDMI_REG(VC4_HDMI_FIFO_CTL), ++ HDMI_REG(VC4_HDMI_SCHEDULER_CONTROL), ++ HDMI_REG(VC4_HDMI_VERTA0), ++ HDMI_REG(VC4_HDMI_VERTA1), ++ HDMI_REG(VC4_HDMI_VERTB0), ++ HDMI_REG(VC4_HDMI_VERTB1), ++ HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), ++}; ++ ++static const struct { ++ u32 reg; ++ const char *name; ++} hd_regs[] = { ++ HDMI_REG(VC4_HD_M_CTL), ++ HDMI_REG(VC4_HD_MAI_CTL), ++ HDMI_REG(VC4_HD_VID_CTL), ++ HDMI_REG(VC4_HD_CSC_CTL), ++ HDMI_REG(VC4_HD_FRAME_COUNT), ++}; ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_hdmi_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hdmi_regs[i].name, hdmi_regs[i].reg, ++ HDMI_READ(hdmi_regs[i].reg)); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hd_regs[i].name, hd_regs[i].reg, ++ HD_READ(hd_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++static void vc4_hdmi_dump_regs(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hdmi_regs[i].reg, hdmi_regs[i].name, ++ HDMI_READ(hdmi_regs[i].reg)); ++ } ++ for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hd_regs[i].reg, hd_regs[i].name, ++ HD_READ(hd_regs[i].reg)); ++ } ++} ++ ++static enum drm_connector_status ++vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct drm_device *dev = connector->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ return connector_status_connected; ++ ++ if (vc4->hdmi->hpd_gpio) { ++ if (gpio_get_value(vc4->hdmi->hpd_gpio)) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++ } ++ ++ if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++} ++ ++static void vc4_hdmi_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct vc4_hdmi_connector *vc4_connector = ++ to_vc4_hdmi_connector(connector); ++ struct drm_encoder *encoder = vc4_connector->encoder; ++ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); ++ struct drm_device *dev = connector->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret = 0; ++ struct edid *edid; ++ ++ edid = drm_get_edid(connector, vc4->hdmi->ddc); ++ if (!edid) ++ return -ENODEV; ++ ++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); ++ drm_mode_connector_update_edid_property(connector, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ ++ return ret; ++} ++ ++static struct drm_encoder * ++vc4_hdmi_connector_best_encoder(struct drm_connector *connector) ++{ ++ struct vc4_hdmi_connector *hdmi_connector = ++ to_vc4_hdmi_connector(connector); ++ return hdmi_connector->encoder; ++} ++ ++static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { ++ .dpms = drm_atomic_helper_connector_dpms, ++ .detect = vc4_hdmi_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = vc4_hdmi_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_hdmi_connector_helper_funcs = { ++ .get_modes = vc4_hdmi_connector_get_modes, ++ .best_encoder = vc4_hdmi_connector_best_encoder, ++}; ++ ++static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, ++ struct drm_encoder *encoder) ++{ ++ struct drm_connector *connector = NULL; ++ struct vc4_hdmi_connector *hdmi_connector; ++ int ret = 0; ++ ++ hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), ++ GFP_KERNEL); ++ if (!hdmi_connector) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ connector = &hdmi_connector->base; ++ ++ hdmi_connector->encoder = encoder; ++ ++ drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA); ++ drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); ++ ++ connector->polled = (DRM_CONNECTOR_POLL_CONNECT | ++ DRM_CONNECTOR_POLL_DISCONNECT); ++ ++ connector->interlace_allowed = 0; ++ connector->doublescan_allowed = 0; ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ ++ return connector; ++ ++ fail: ++ if (connector) ++ vc4_hdmi_connector_destroy(connector); ++ ++ return ERR_PTR(ret); ++} ++ ++static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++} ++ ++static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { ++ .destroy = vc4_hdmi_encoder_destroy, ++}; ++ ++static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *unadjusted_mode, ++ struct drm_display_mode *mode) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ bool debug_dump_regs = false; ++ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; ++ bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; ++ u32 vactive = (mode->vdisplay >> ++ ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); ++ u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, ++ VC4_HDMI_VERTA_VSP) | ++ VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, ++ VC4_HDMI_VERTA_VFP) | ++ VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); ++ u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->vtotal - mode->vsync_end, ++ VC4_HDMI_VERTB_VBP)); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("HDMI regs before:\n"); ++ vc4_hdmi_dump_regs(dev); ++ } ++ ++ HD_WRITE(VC4_HD_VID_CTL, 0); ++ ++ clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000); ++ ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | ++ VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); ++ ++ HDMI_WRITE(VC4_HDMI_HORZA, ++ (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | ++ (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | ++ VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP)); ++ ++ HDMI_WRITE(VC4_HDMI_HORZB, ++ VC4_SET_FIELD(mode->htotal - mode->hsync_end, ++ VC4_HDMI_HORZB_HBP) | ++ VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, ++ VC4_HDMI_HORZB_HSP) | ++ VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, ++ VC4_HDMI_HORZB_HFP)); ++ ++ HDMI_WRITE(VC4_HDMI_VERTA0, verta); ++ HDMI_WRITE(VC4_HDMI_VERTA1, verta); ++ ++ HDMI_WRITE(VC4_HDMI_VERTB0, vertb); ++ HDMI_WRITE(VC4_HDMI_VERTB1, vertb); ++ ++ HD_WRITE(VC4_HD_VID_CTL, ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ ++ /* The RGB order applies even when CSC is disabled. */ ++ HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, ++ VC4_HD_CSC_CTL_ORDER)); ++ ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); ++ ++ if (debug_dump_regs) { ++ DRM_INFO("HDMI regs after:\n"); ++ vc4_hdmi_dump_regs(dev); ++ } ++} ++ ++static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ HD_WRITE(VC4_HD_VID_CTL, ++ HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); ++} ++ ++static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ ++ HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); ++ ++ HD_WRITE(VC4_HD_VID_CTL, ++ HD_READ(VC4_HD_VID_CTL) | ++ VC4_HD_VID_CTL_ENABLE | ++ VC4_HD_VID_CTL_UNDERFLOW_ENABLE | ++ VC4_HD_VID_CTL_FRAME_COUNTER_RESET); ++ ++ if (vc4_encoder->hdmi_monitor) { ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ++ ++ ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); ++ } else { ++ HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, ++ HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ ~(VC4_HDMI_RAM_PACKET_ENABLE)); ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ++ ++ ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); ++ } ++ ++ if (vc4_encoder->hdmi_monitor) { ++ u32 drift; ++ ++ WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); ++ HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); ++ ++ /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set ++ * up the infoframe. ++ */ ++ ++ drift = HDMI_READ(VC4_HDMI_FIFO_CTL); ++ drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; ++ ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift & ~VC4_HDMI_FIFO_CTL_RECENTER); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift | VC4_HDMI_FIFO_CTL_RECENTER); ++ udelay(1000); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift & ~VC4_HDMI_FIFO_CTL_RECENTER); ++ HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ drift | VC4_HDMI_FIFO_CTL_RECENTER); ++ ++ ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) & ++ VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); ++ WARN_ONCE(ret, "Timeout waiting for " ++ "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); ++ } ++} ++ ++static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { ++ .mode_set = vc4_hdmi_encoder_mode_set, ++ .disable = vc4_hdmi_encoder_disable, ++ .enable = vc4_hdmi_encoder_enable, ++}; ++ ++static int vc4_hdmi_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 = drm->dev_private; ++ struct vc4_hdmi *hdmi; ++ struct vc4_hdmi_encoder *vc4_hdmi_encoder; ++ struct device_node *ddc_node; ++ u32 value; ++ int ret; ++ ++ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); ++ if (!hdmi) ++ return -ENOMEM; ++ ++ vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder), ++ GFP_KERNEL); ++ if (!vc4_hdmi_encoder) ++ return -ENOMEM; ++ vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI; ++ hdmi->encoder = &vc4_hdmi_encoder->base.base; ++ ++ hdmi->pdev = pdev; ++ hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(hdmi->hdmicore_regs)) ++ return PTR_ERR(hdmi->hdmicore_regs); ++ ++ hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); ++ if (IS_ERR(hdmi->hd_regs)) ++ return PTR_ERR(hdmi->hd_regs); ++ ++ ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); ++ if (!ddc_node) { ++ DRM_ERROR("Failed to find ddc node in device tree\n"); ++ return -ENODEV; ++ } ++ ++ hdmi->pixel_clock = devm_clk_get(dev, "pixel"); ++ if (IS_ERR(hdmi->pixel_clock)) { ++ DRM_ERROR("Failed to get pixel clock\n"); ++ return PTR_ERR(hdmi->pixel_clock); ++ } ++ hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); ++ if (IS_ERR(hdmi->hsm_clock)) { ++ DRM_ERROR("Failed to get HDMI state machine clock\n"); ++ return PTR_ERR(hdmi->hsm_clock); ++ } ++ ++ hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); ++ if (!hdmi->ddc) { ++ DRM_DEBUG("Failed to get ddc i2c adapter by node\n"); ++ return -EPROBE_DEFER; ++ } ++ ++ /* Enable the clocks at startup. We can't quite recover from ++ * turning off the pixel clock during disable/enables yet, so ++ * it's always running. ++ */ ++ ret = clk_prepare_enable(hdmi->pixel_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); ++ goto err_put_i2c; ++ } ++ ++ ret = clk_prepare_enable(hdmi->hsm_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", ++ ret); ++ goto err_unprepare_pix; ++ } ++ ++ /* Only use the GPIO HPD pin if present in the DT, otherwise ++ * we'll use the HDMI core's register. ++ */ ++ if (of_find_property(dev->of_node, "hpd-gpios", &value)) { ++ hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0); ++ if (hdmi->hpd_gpio < 0) { ++ ret = hdmi->hpd_gpio; ++ goto err_unprepare_hsm; ++ } ++ } ++ ++ vc4->hdmi = hdmi; ++ ++ /* HDMI core must be enabled. */ ++ WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0); ++ ++ drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, ++ DRM_MODE_ENCODER_TMDS); ++ drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs); ++ ++ hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder); ++ if (IS_ERR(hdmi->connector)) { ++ ret = PTR_ERR(hdmi->connector); ++ goto err_destroy_encoder; ++ } ++ ++ return 0; ++ ++err_destroy_encoder: ++ vc4_hdmi_encoder_destroy(hdmi->encoder); ++err_unprepare_hsm: ++ clk_disable_unprepare(hdmi->hsm_clock); ++err_unprepare_pix: ++ clk_disable_unprepare(hdmi->pixel_clock); ++err_put_i2c: ++ put_device(&vc4->hdmi->ddc->dev); ++ ++ return ret; ++} ++ ++static void vc4_hdmi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = drm->dev_private; ++ struct vc4_hdmi *hdmi = vc4->hdmi; ++ ++ vc4_hdmi_connector_destroy(hdmi->connector); ++ vc4_hdmi_encoder_destroy(hdmi->encoder); ++ ++ clk_disable_unprepare(hdmi->pixel_clock); ++ clk_disable_unprepare(hdmi->hsm_clock); ++ put_device(&hdmi->ddc->dev); ++ ++ vc4->hdmi = NULL; ++} ++ ++static const struct component_ops vc4_hdmi_ops = { ++ .bind = vc4_hdmi_bind, ++ .unbind = vc4_hdmi_unbind, ++}; ++ ++static int vc4_hdmi_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_hdmi_ops); ++} ++ ++static int vc4_hdmi_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_hdmi_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_hdmi_dt_match[] = { ++ { .compatible = "brcm,bcm2835-hdmi" }, ++ {} ++}; ++ ++struct platform_driver vc4_hdmi_driver = { ++ .probe = vc4_hdmi_dev_probe, ++ .remove = vc4_hdmi_dev_remove, ++ .driver = { ++ .name = "vc4_hdmi", ++ .of_match_table = vc4_hdmi_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c +new file mode 100644 +index 0000000..8098c5b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 HVS module. ++ * ++ * The HVS is the piece of hardware that does translation, scaling, ++ * colorspace conversion, and compositing of pixels stored in ++ * framebuffers into a FIFO of pixels going out to the Pixel Valve ++ * (CRTC). It operates at the system clock rate (the system audio ++ * clock gate, specifically), which is much higher than the pixel ++ * clock rate. ++ * ++ * There is a single global HVS, with multiple output FIFOs that can ++ * be consumed by the PVs. This file just manages the resources for ++ * the HVS, while the vc4_crtc.c code actually drives HVS setup for ++ * each CRTC. ++ */ ++ ++#include "linux/component.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define HVS_REG(reg) { reg, #reg } ++static const struct { ++ u32 reg; ++ const char *name; ++} hvs_regs[] = { ++ HVS_REG(SCALER_DISPCTRL), ++ HVS_REG(SCALER_DISPSTAT), ++ HVS_REG(SCALER_DISPID), ++ HVS_REG(SCALER_DISPECTRL), ++ HVS_REG(SCALER_DISPPROF), ++ HVS_REG(SCALER_DISPDITHER), ++ HVS_REG(SCALER_DISPEOLN), ++ HVS_REG(SCALER_DISPLIST0), ++ HVS_REG(SCALER_DISPLIST1), ++ HVS_REG(SCALER_DISPLIST2), ++ HVS_REG(SCALER_DISPLSTAT), ++ HVS_REG(SCALER_DISPLACT0), ++ HVS_REG(SCALER_DISPLACT1), ++ HVS_REG(SCALER_DISPLACT2), ++ HVS_REG(SCALER_DISPCTRL0), ++ HVS_REG(SCALER_DISPBKGND0), ++ HVS_REG(SCALER_DISPSTAT0), ++ HVS_REG(SCALER_DISPBASE0), ++ HVS_REG(SCALER_DISPCTRL1), ++ HVS_REG(SCALER_DISPBKGND1), ++ HVS_REG(SCALER_DISPSTAT1), ++ HVS_REG(SCALER_DISPBASE1), ++ HVS_REG(SCALER_DISPCTRL2), ++ HVS_REG(SCALER_DISPBKGND2), ++ HVS_REG(SCALER_DISPSTAT2), ++ HVS_REG(SCALER_DISPBASE2), ++ HVS_REG(SCALER_DISPALPHA2), ++}; ++ ++void vc4_hvs_dump_state(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { ++ DRM_INFO("0x%04x (%s): 0x%08x\n", ++ hvs_regs[i].reg, hvs_regs[i].name, ++ HVS_READ(hvs_regs[i].reg)); ++ } ++ ++ DRM_INFO("HVS ctx:\n"); ++ for (i = 0; i < 64; i += 4) { ++ DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 0), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 1), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 2), ++ readl((u32 __iomem *)vc4->hvs->dlist + i + 3)); ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++int vc4_hvs_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ hvs_regs[i].name, hvs_regs[i].reg, ++ HVS_READ(hvs_regs[i].reg)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static int vc4_hvs_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 = drm->dev_private; ++ struct vc4_hvs *hvs = NULL; ++ ++ hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); ++ if (!hvs) ++ return -ENOMEM; ++ ++ hvs->pdev = pdev; ++ ++ hvs->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(hvs->regs)) ++ return PTR_ERR(hvs->regs); ++ ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; ++ ++ vc4->hvs = hvs; ++ return 0; ++} ++ ++static void vc4_hvs_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = drm->dev_private; ++ ++ vc4->hvs = NULL; ++} ++ ++static const struct component_ops vc4_hvs_ops = { ++ .bind = vc4_hvs_bind, ++ .unbind = vc4_hvs_unbind, ++}; ++ ++static int vc4_hvs_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_hvs_ops); ++} ++ ++static int vc4_hvs_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_hvs_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_hvs_dt_match[] = { ++ { .compatible = "brcm,bcm2835-hvs" }, ++ {} ++}; ++ ++struct platform_driver vc4_hvs_driver = { ++ .probe = vc4_hvs_dev_probe, ++ .remove = vc4_hvs_dev_remove, ++ .driver = { ++ .name = "vc4_hvs", ++ .of_match_table = vc4_hvs_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +new file mode 100644 +index 0000000..b68060e +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -0,0 +1,210 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Interrupt management for the V3D engine. ++ * ++ * We have an interrupt status register (V3D_INTCTL) which reports ++ * interrupts, and where writing 1 bits clears those interrupts. ++ * There are also a pair of interrupt registers ++ * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or ++ * disables that specific interrupt, and 0s written are ignored ++ * (reading either one returns the set of enabled interrupts). ++ * ++ * When we take a render frame interrupt, we need to wake the ++ * processes waiting for some frame to be done, and get the next frame ++ * submitted ASAP (so the hardware doesn't sit idle when there's work ++ * to do). ++ * ++ * When we take the binner out of memory interrupt, we need to ++ * allocate some new memory and pass it to the binner so that the ++ * current job can make progress. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \ ++ V3D_INT_FRDONE) ++ ++DECLARE_WAIT_QUEUE_HEAD(render_wait); ++ ++static void ++vc4_overflow_mem_work(struct work_struct *work) ++{ ++ struct vc4_dev *vc4 = ++ container_of(work, struct vc4_dev, overflow_mem_work); ++ struct drm_device *dev = vc4->dev; ++ struct vc4_bo *bo; ++ ++ bo = vc4_bo_create(dev, 256 * 1024, true); ++ if (!bo) { ++ DRM_ERROR("Couldn't allocate binner overflow mem\n"); ++ return; ++ } ++ ++ /* If there's a job executing currently, then our previous ++ * overflow allocation is getting used in that job and we need ++ * to queue it to be released when the job is done. But if no ++ * job is executing at all, then we can free the old overflow ++ * object direcctly. ++ * ++ * No lock necessary for this pointer since we're the only ++ * ones that update the pointer, and our workqueue won't ++ * reenter. ++ */ ++ if (vc4->overflow_mem) { ++ struct vc4_exec_info *current_exec; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ current_exec = vc4_first_job(vc4); ++ if (current_exec) { ++ vc4->overflow_mem->seqno = vc4->finished_seqno + 1; ++ list_add_tail(&vc4->overflow_mem->unref_head, ++ ¤t_exec->unref_list); ++ vc4->overflow_mem = NULL; ++ } ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ } ++ ++ if (vc4->overflow_mem) ++ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); ++ vc4->overflow_mem = bo; ++ ++ V3D_WRITE(V3D_BPOA, bo->base.paddr); ++ V3D_WRITE(V3D_BPOS, bo->base.base.size); ++ V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); ++ V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); ++} ++ ++static void ++vc4_irq_finish_job(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_exec_info *exec = vc4_first_job(vc4); ++ ++ if (!exec) ++ return; ++ ++ vc4->finished_seqno++; ++ list_move_tail(&exec->head, &vc4->job_done_list); ++ vc4_submit_next_job(dev); ++ ++ wake_up_all(&vc4->job_wait_queue); ++ schedule_work(&vc4->job_done_work); ++} ++ ++irqreturn_t ++vc4_irq(int irq, void *arg) ++{ ++ struct drm_device *dev = arg; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ uint32_t intctl; ++ irqreturn_t status = IRQ_NONE; ++ ++ barrier(); ++ intctl = V3D_READ(V3D_INTCTL); ++ ++ /* Acknowledge the interrupts we're handling here. The render ++ * frame done interrupt will be cleared, while OUTOMEM will ++ * stay high until the underlying cause is cleared. ++ */ ++ V3D_WRITE(V3D_INTCTL, intctl); ++ ++ if (intctl & V3D_INT_OUTOMEM) { ++ /* Disable OUTOMEM until the work is done. */ ++ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM); ++ schedule_work(&vc4->overflow_mem_work); ++ status = IRQ_HANDLED; ++ } ++ ++ if (intctl & V3D_INT_FRDONE) { ++ spin_lock(&vc4->job_lock); ++ vc4_irq_finish_job(dev); ++ spin_unlock(&vc4->job_lock); ++ status = IRQ_HANDLED; ++ } ++ ++ return status; ++} ++ ++void ++vc4_irq_preinstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ init_waitqueue_head(&vc4->job_wait_queue); ++ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work); ++ ++ /* Clear any pending interrupts someone might have left around ++ * for us. ++ */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++} ++ ++int ++vc4_irq_postinstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Enable both the render done and out of memory interrupts. */ ++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); ++ ++ return 0; ++} ++ ++void ++vc4_irq_uninstall(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Disable sending interrupts for our driver's IRQs. */ ++ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS); ++ ++ /* Clear any pending interrupts we might have left. */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++ ++ cancel_work_sync(&vc4->overflow_mem_work); ++} ++ ++/** Reinitializes interrupt registers when a GPU reset is performed. */ ++void vc4_irq_reset(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; ++ ++ /* Acknowledge any stale IRQs. */ ++ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); ++ ++ /* ++ * Turn all our interrupts on. Binner out of memory is the ++ * only one we expect to trigger at this point, since we've ++ * just come from poweron and haven't supplied any overflow ++ * memory yet. ++ */ ++ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); ++ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ vc4_irq_finish_job(dev); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c +new file mode 100644 +index 0000000..918c9da +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -0,0 +1,214 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 KMS ++ * ++ * This is the general code for implementing KMS mode setting that ++ * doesn't clearly associate with any of the other objects (plane, ++ * crtc, HDMI encoder). ++ */ ++ ++#include "drm_crtc.h" ++#include "drm_atomic.h" ++#include "drm_atomic_helper.h" ++#include "drm_crtc_helper.h" ++#include "drm_plane_helper.h" ++#include "drm_fb_cma_helper.h" ++#include "vc4_drv.h" ++ ++static void vc4_output_poll_changed(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ if (vc4->fbdev) ++ drm_fbdev_cma_hotplug_event(vc4->fbdev); ++} ++ ++struct vc4_commit { ++ struct drm_device *dev; ++ struct drm_atomic_state *state; ++ struct vc4_seqno_cb cb; ++}; ++ ++static void ++vc4_atomic_complete_commit(struct vc4_commit *c) ++{ ++ struct drm_atomic_state *state = c->state; ++ struct drm_device *dev = state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ drm_atomic_helper_commit_modeset_disables(dev, state); ++ ++ drm_atomic_helper_commit_planes(dev, state); ++ ++ drm_atomic_helper_commit_modeset_enables(dev, state); ++ ++ drm_atomic_helper_wait_for_vblanks(dev, state); ++ ++ drm_atomic_helper_cleanup_planes(dev, state); ++ ++ drm_atomic_state_free(state); ++ ++ up(&vc4->async_modeset); ++ ++ kfree(c); ++} ++ ++static void ++vc4_atomic_complete_commit_seqno_cb(struct vc4_seqno_cb *cb) ++{ ++ struct vc4_commit *c = container_of(cb, struct vc4_commit, cb); ++ ++ vc4_atomic_complete_commit(c); ++} ++ ++static struct vc4_commit *commit_init(struct drm_atomic_state *state) ++{ ++ struct vc4_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); ++ ++ if (!c) ++ return NULL; ++ c->dev = state->dev; ++ c->state = state; ++ ++ return c; ++} ++ ++/** ++ * vc4_atomic_commit - commit validated state object ++ * @dev: DRM device ++ * @state: the driver state object ++ * @async: asynchronous commit ++ * ++ * This function commits a with drm_atomic_helper_check() pre-validated state ++ * object. This can still fail when e.g. the framebuffer reservation fails. For ++ * now this doesn't implement asynchronous commits. ++ * ++ * RETURNS ++ * Zero for success or -errno. ++ */ ++static int vc4_atomic_commit(struct drm_device *dev, ++ struct drm_atomic_state *state, ++ bool async) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ int i; ++ uint64_t wait_seqno = 0; ++ struct vc4_commit *c; ++ ++ c = commit_init(state); ++ if (!c) ++ return -ENOMEM; ++ ++ /* Make sure that any outstanding modesets have finished. */ ++ ret = down_interruptible(&vc4->async_modeset); ++ if (ret) { ++ kfree(c); ++ return ret; ++ } ++ ++ ret = drm_atomic_helper_prepare_planes(dev, state); ++ if (ret) { ++ kfree(c); ++ up(&vc4->async_modeset); ++ return ret; ++ } ++ ++ for (i = 0; i < dev->mode_config.num_total_plane; i++) { ++ struct drm_plane *plane = state->planes[i]; ++ struct drm_plane_state *new_state = state->plane_states[i]; ++ ++ if (!plane) ++ continue; ++ ++ if ((plane->state->fb != new_state->fb) && new_state->fb) { ++ struct drm_gem_cma_object *cma_bo = ++ drm_fb_cma_get_gem_obj(new_state->fb, 0); ++ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); ++ ++ wait_seqno = max(bo->seqno, wait_seqno); ++ } ++ } ++ ++ /* ++ * This is the point of no return - everything below never fails except ++ * when the hw goes bonghits. Which means we can commit the new state on ++ * the software side now. ++ */ ++ ++ drm_atomic_helper_swap_state(dev, state); ++ ++ /* ++ * Everything below can be run asynchronously without the need to grab ++ * any modeset locks at all under one condition: It must be guaranteed ++ * that the asynchronous work has either been cancelled (if the driver ++ * supports it, which at least requires that the framebuffers get ++ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed ++ * before the new state gets committed on the software side with ++ * drm_atomic_helper_swap_state(). ++ * ++ * This scheme allows new atomic state updates to be prepared and ++ * checked in parallel to the asynchronous completion of the previous ++ * update. Which is important since compositors need to figure out the ++ * composition of the next frame right after having submitted the ++ * current layout. ++ */ ++ ++ if (async) { ++ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno, ++ vc4_atomic_complete_commit_seqno_cb); ++ } else { ++ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false); ++ vc4_atomic_complete_commit(c); ++ } ++ ++ return 0; ++} ++ ++static const struct drm_mode_config_funcs vc4_mode_funcs = { ++ .output_poll_changed = vc4_output_poll_changed, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = vc4_atomic_commit, ++ .fb_create = drm_fb_cma_create, ++}; ++ ++int vc4_kms_load(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ int ret; ++ ++ sema_init(&vc4->async_modeset, 1); ++ ++ ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ++ if (ret < 0) { ++ dev_err(dev->dev, "failed to initialize vblank\n"); ++ return ret; ++ } ++ ++ dev->mode_config.max_width = 2048; ++ dev->mode_config.max_height = 2048; ++ dev->mode_config.funcs = &vc4_mode_funcs; ++ dev->mode_config.preferred_depth = 24; ++ dev->mode_config.async_page_flip = true; ++ ++ dev->vblank_disable_allowed = true; ++ ++ drm_mode_config_reset(dev); ++ ++ vc4->fbdev = drm_fbdev_cma_init(dev, 32, ++ dev->mode_config.num_crtc, ++ dev->mode_config.num_connector); ++ if (IS_ERR(vc4->fbdev)) ++ vc4->fbdev = NULL; ++ ++ drm_kms_helper_poll_init(dev); ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/vc4/vc4_packet.h b/drivers/gpu/drm/vc4/vc4_packet.h +new file mode 100644 +index 0000000..0f31cc0 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_packet.h +@@ -0,0 +1,399 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef VC4_PACKET_H ++#define VC4_PACKET_H ++ ++#include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */ ++ ++enum vc4_packet { ++ VC4_PACKET_HALT = 0, ++ VC4_PACKET_NOP = 1, ++ ++ VC4_PACKET_FLUSH = 4, ++ VC4_PACKET_FLUSH_ALL = 5, ++ VC4_PACKET_START_TILE_BINNING = 6, ++ VC4_PACKET_INCREMENT_SEMAPHORE = 7, ++ VC4_PACKET_WAIT_ON_SEMAPHORE = 8, ++ ++ VC4_PACKET_BRANCH = 16, ++ VC4_PACKET_BRANCH_TO_SUB_LIST = 17, ++ ++ VC4_PACKET_STORE_MS_TILE_BUFFER = 24, ++ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25, ++ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26, ++ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27, ++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28, ++ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29, ++ ++ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32, ++ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33, ++ ++ VC4_PACKET_COMPRESSED_PRIMITIVE = 48, ++ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49, ++ ++ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56, ++ ++ VC4_PACKET_GL_SHADER_STATE = 64, ++ VC4_PACKET_NV_SHADER_STATE = 65, ++ VC4_PACKET_VG_SHADER_STATE = 66, ++ ++ VC4_PACKET_CONFIGURATION_BITS = 96, ++ VC4_PACKET_FLAT_SHADE_FLAGS = 97, ++ VC4_PACKET_POINT_SIZE = 98, ++ VC4_PACKET_LINE_WIDTH = 99, ++ VC4_PACKET_RHT_X_BOUNDARY = 100, ++ VC4_PACKET_DEPTH_OFFSET = 101, ++ VC4_PACKET_CLIP_WINDOW = 102, ++ VC4_PACKET_VIEWPORT_OFFSET = 103, ++ VC4_PACKET_Z_CLIPPING = 104, ++ VC4_PACKET_CLIPPER_XY_SCALING = 105, ++ VC4_PACKET_CLIPPER_Z_SCALING = 106, ++ ++ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112, ++ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113, ++ VC4_PACKET_CLEAR_COLORS = 114, ++ VC4_PACKET_TILE_COORDINATES = 115, ++ ++ /* Not an actual hardware packet -- this is what we use to put ++ * references to GEM bos in the command stream, since we need the u32 ++ * int the actual address packet in order to store the offset from the ++ * start of the BO. ++ */ ++ VC4_PACKET_GEM_HANDLES = 254, ++} __attribute__ ((__packed__)); ++ ++#define VC4_PACKET_HALT_SIZE 1 ++#define VC4_PACKET_NOP_SIZE 1 ++#define VC4_PACKET_FLUSH_SIZE 1 ++#define VC4_PACKET_FLUSH_ALL_SIZE 1 ++#define VC4_PACKET_START_TILE_BINNING_SIZE 1 ++#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1 ++#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1 ++#define VC4_PACKET_BRANCH_SIZE 5 ++#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5 ++#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1 ++#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1 ++#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5 ++#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5 ++#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7 ++#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7 ++#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14 ++#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10 ++#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1 ++#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1 ++#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2 ++#define VC4_PACKET_GL_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_NV_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_VG_SHADER_STATE_SIZE 5 ++#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4 ++#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5 ++#define VC4_PACKET_POINT_SIZE_SIZE 5 ++#define VC4_PACKET_LINE_WIDTH_SIZE 5 ++#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3 ++#define VC4_PACKET_DEPTH_OFFSET_SIZE 5 ++#define VC4_PACKET_CLIP_WINDOW_SIZE 9 ++#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5 ++#define VC4_PACKET_Z_CLIPPING_SIZE 9 ++#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9 ++#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9 ++#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16 ++#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11 ++#define VC4_PACKET_CLEAR_COLORS_SIZE 14 ++#define VC4_PACKET_TILE_COORDINATES_SIZE 3 ++#define VC4_PACKET_GEM_HANDLES_SIZE 9 ++ ++/* Number of multisamples supported. */ ++#define VC4_MAX_SAMPLES 4 ++/* Size of a full resolution color or Z tile buffer load/store. */ ++#define VC4_TILE_BUFFER_SIZE (64 * 64 * 4) ++ ++/** @{ ++ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG. ++*/ ++#define VC4_TILING_FORMAT_LINEAR 0 ++#define VC4_TILING_FORMAT_T 1 ++#define VC4_TILING_FORMAT_LT 2 ++/** @} */ ++ ++/** @{ ++ * ++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and ++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER. ++ */ ++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0) ++ ++/** @{ ++ * ++ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and ++ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER. ++ */ ++#define VC4_LOADSTORE_FULL_RES_EOF BIT(3) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1) ++#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0) ++ ++/** @{ ++ * ++ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address) ++ */ ++ ++#define VC4_LOADSTORE_TILE_BUFFER_EOF BIT(3) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK BIT(2) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS BIT(1) ++#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR BIT(0) ++ ++/** @} */ ++ ++/** @{ ++ * ++ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL ++ */ ++#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR BIT(15) ++#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR BIT(14) ++#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR BIT(13) ++#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP BIT(12) ++ ++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8) ++#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8 ++#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0 ++#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1 ++#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2 ++/** @} */ ++ ++/** @{ ++ * ++ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and ++ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL ++ */ ++#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6) ++#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6 ++#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6) ++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6) ++#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6) ++ ++/** The values of the field are VC4_TILING_FORMAT_* */ ++#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4) ++#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4 ++ ++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0) ++#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0 ++#define VC4_LOADSTORE_TILE_BUFFER_NONE 0 ++#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1 ++#define VC4_LOADSTORE_TILE_BUFFER_ZS 2 ++#define VC4_LOADSTORE_TILE_BUFFER_Z 3 ++#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4 ++#define VC4_LOADSTORE_TILE_BUFFER_FULL 5 ++/** @} */ ++ ++#define VC4_INDEX_BUFFER_U8 (0 << 4) ++#define VC4_INDEX_BUFFER_U16 (1 << 4) ++ ++/* This flag is only present in NV shader state. */ ++#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS BIT(3) ++#define VC4_SHADER_FLAG_ENABLE_CLIPPING BIT(2) ++#define VC4_SHADER_FLAG_VS_POINT_SIZE BIT(1) ++#define VC4_SHADER_FLAG_FS_SINGLE_THREAD BIT(0) ++ ++/** @{ byte 2 of config bits. */ ++#define VC4_CONFIG_BITS_EARLY_Z_UPDATE BIT(1) ++#define VC4_CONFIG_BITS_EARLY_Z BIT(0) ++/** @} */ ++ ++/** @{ byte 1 of config bits. */ ++#define VC4_CONFIG_BITS_Z_UPDATE BIT(7) ++/** same values in this 3-bit field as PIPE_FUNC_* */ ++#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4 ++#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE BIT(3) ++ ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1) ++#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1) ++ ++#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT BIT(0) ++/** @} */ ++ ++/** @{ byte 0 of config bits. */ ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6) ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6) ++#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6) ++ ++#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES BIT(4) ++#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET BIT(3) ++#define VC4_CONFIG_BITS_CW_PRIMITIVES BIT(2) ++#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK BIT(1) ++#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT BIT(0) ++/** @} */ ++ ++/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */ ++#define VC4_BIN_CONFIG_DB_NON_MS BIT(7) ++ ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5) ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2 ++#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3 ++ ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3) ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2 ++#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3 ++ ++#define VC4_BIN_CONFIG_AUTO_INIT_TSDA BIT(2) ++#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT BIT(1) ++#define VC4_BIN_CONFIG_MS_MODE_4X BIT(0) ++/** @} */ ++ ++/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */ ++#define VC4_RENDER_CONFIG_DB_NON_MS BIT(12) ++#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE BIT(11) ++#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G BIT(10) ++#define VC4_RENDER_CONFIG_COVERAGE_MODE BIT(9) ++#define VC4_RENDER_CONFIG_ENABLE_VG_MASK BIT(8) ++ ++/** The values of the field are VC4_TILING_FORMAT_* */ ++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6) ++#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6 ++ ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4) ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4) ++#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4) ++ ++#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2) ++#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2 ++#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0 ++#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1 ++#define VC4_RENDER_CONFIG_FORMAT_BGR565 2 ++ ++#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT BIT(1) ++#define VC4_RENDER_CONFIG_MS_MODE_4X BIT(0) ++ ++#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4) ++#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0) ++#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0) ++ ++enum vc4_texture_data_type { ++ VC4_TEXTURE_TYPE_RGBA8888 = 0, ++ VC4_TEXTURE_TYPE_RGBX8888 = 1, ++ VC4_TEXTURE_TYPE_RGBA4444 = 2, ++ VC4_TEXTURE_TYPE_RGBA5551 = 3, ++ VC4_TEXTURE_TYPE_RGB565 = 4, ++ VC4_TEXTURE_TYPE_LUMINANCE = 5, ++ VC4_TEXTURE_TYPE_ALPHA = 6, ++ VC4_TEXTURE_TYPE_LUMALPHA = 7, ++ VC4_TEXTURE_TYPE_ETC1 = 8, ++ VC4_TEXTURE_TYPE_S16F = 9, ++ VC4_TEXTURE_TYPE_S8 = 10, ++ VC4_TEXTURE_TYPE_S16 = 11, ++ VC4_TEXTURE_TYPE_BW1 = 12, ++ VC4_TEXTURE_TYPE_A4 = 13, ++ VC4_TEXTURE_TYPE_A1 = 14, ++ VC4_TEXTURE_TYPE_RGBA64 = 15, ++ VC4_TEXTURE_TYPE_RGBA32R = 16, ++ VC4_TEXTURE_TYPE_YUV422R = 17, ++}; ++ ++#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12) ++#define VC4_TEX_P0_OFFSET_SHIFT 12 ++#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10) ++#define VC4_TEX_P0_CSWIZ_SHIFT 10 ++#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9) ++#define VC4_TEX_P0_CMMODE_SHIFT 9 ++#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8) ++#define VC4_TEX_P0_FLIPY_SHIFT 8 ++#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4) ++#define VC4_TEX_P0_TYPE_SHIFT 4 ++#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0) ++#define VC4_TEX_P0_MIPLVLS_SHIFT 0 ++ ++#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31) ++#define VC4_TEX_P1_TYPE4_SHIFT 31 ++#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20) ++#define VC4_TEX_P1_HEIGHT_SHIFT 20 ++#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19) ++#define VC4_TEX_P1_ETCFLIP_SHIFT 19 ++#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8) ++#define VC4_TEX_P1_WIDTH_SHIFT 8 ++ ++#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7) ++#define VC4_TEX_P1_MAGFILT_SHIFT 7 ++# define VC4_TEX_P1_MAGFILT_LINEAR 0 ++# define VC4_TEX_P1_MAGFILT_NEAREST 1 ++ ++#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4) ++#define VC4_TEX_P1_MINFILT_SHIFT 4 ++# define VC4_TEX_P1_MINFILT_LINEAR 0 ++# define VC4_TEX_P1_MINFILT_NEAREST 1 ++# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2 ++# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3 ++# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4 ++# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5 ++ ++#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2) ++#define VC4_TEX_P1_WRAP_T_SHIFT 2 ++#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0) ++#define VC4_TEX_P1_WRAP_S_SHIFT 0 ++# define VC4_TEX_P1_WRAP_REPEAT 0 ++# define VC4_TEX_P1_WRAP_CLAMP 1 ++# define VC4_TEX_P1_WRAP_MIRROR 2 ++# define VC4_TEX_P1_WRAP_BORDER 3 ++ ++#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30) ++#define VC4_TEX_P2_PTYPE_SHIFT 30 ++# define VC4_TEX_P2_PTYPE_IGNORED 0 ++# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1 ++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2 ++# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3 ++ ++/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */ ++#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12) ++#define VC4_TEX_P2_CMST_SHIFT 12 ++#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0) ++#define VC4_TEX_P2_BSLOD_SHIFT 0 ++ ++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */ ++#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12) ++#define VC4_TEX_P2_CHEIGHT_SHIFT 12 ++#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0) ++#define VC4_TEX_P2_CWIDTH_SHIFT 0 ++ ++/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */ ++#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12) ++#define VC4_TEX_P2_CYOFF_SHIFT 12 ++#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0) ++#define VC4_TEX_P2_CXOFF_SHIFT 0 ++ ++#endif /* VC4_PACKET_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c +new file mode 100644 +index 0000000..0f85eb5 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++/** ++ * DOC: VC4 plane module ++ * ++ * Each DRM plane is a layer of pixels being scanned out by the HVS. ++ * ++ * At atomic modeset check time, we compute the HVS display element ++ * state that would be necessary for displaying the plane (giving us a ++ * chance to figure out if a plane configuration is invalid), then at ++ * atomic flush time the CRTC will ask us to write our element state ++ * into the region of the HVS that it has allocated for us. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++#include "drm_atomic_helper.h" ++#include "drm_fb_cma_helper.h" ++#include "drm_plane_helper.h" ++ ++struct vc4_plane_state { ++ struct drm_plane_state base; ++ u32 *dlist; ++ u32 dlist_size; /* Number of dwords in allocated for the display list */ ++ u32 dlist_count; /* Number of used dwords in the display list. */ ++ ++ /* Offset in the dlist to pointer word 0. */ ++ u32 pw0_offset; ++ ++ /* Offset where the plane's dlist was last stored in the ++ hardware at vc4_crtc_atomic_flush() time. ++ */ ++ u32 *hw_dlist; ++}; ++ ++static inline struct vc4_plane_state * ++to_vc4_plane_state(struct drm_plane_state *state) ++{ ++ return (struct vc4_plane_state *)state; ++} ++ ++static const struct hvs_format { ++ u32 drm; /* DRM_FORMAT_* */ ++ u32 hvs; /* HVS_FORMAT_* */ ++ u32 pixel_order; ++ bool has_alpha; ++} hvs_formats[] = { ++ { ++ .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, ++ }, ++ { ++ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false, ++ }, ++ { ++ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, ++ }, ++ { ++ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, ++ }, ++}; ++ ++static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) ++{ ++ unsigned i; ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { ++ if (hvs_formats[i].drm == drm_format) ++ return &hvs_formats[i]; ++ } ++ ++ return NULL; ++} ++ ++static bool plane_enabled(struct drm_plane_state *state) ++{ ++ return state->fb && state->crtc; ++} ++ ++static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ if (WARN_ON(!plane->state)) ++ return NULL; ++ ++ vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return NULL; ++ ++ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); ++ ++ if (vc4_state->dlist) { ++ vc4_state->dlist = kmemdup(vc4_state->dlist, ++ vc4_state->dlist_count * 4, ++ GFP_KERNEL); ++ if (!vc4_state->dlist) { ++ kfree(vc4_state); ++ return NULL; ++ } ++ vc4_state->dlist_size = vc4_state->dlist_count; ++ } ++ ++ return &vc4_state->base; ++} ++ ++static void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ kfree(vc4_state->dlist); ++ __drm_atomic_helper_plane_destroy_state(plane, &vc4_state->base); ++ kfree(state); ++} ++ ++/* Called during init to allocate the plane's atomic state. */ ++static void vc4_plane_reset(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ WARN_ON(plane->state); ++ ++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return; ++ ++ plane->state = &vc4_state->base; ++ vc4_state->base.plane = plane; ++} ++ ++static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) ++{ ++ if (vc4_state->dlist_count == vc4_state->dlist_size) { ++ u32 new_size = max(4u, vc4_state->dlist_count * 2); ++ u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL); ++ ++ if (!new_dlist) ++ return; ++ memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4); ++ ++ kfree(vc4_state->dlist); ++ vc4_state->dlist = new_dlist; ++ vc4_state->dlist_size = new_size; ++ } ++ ++ vc4_state->dlist[vc4_state->dlist_count++] = val; ++} ++ ++/* Writes out a full display list for an active plane to the plane's ++ * private dlist state. ++ */ ++static int vc4_plane_mode_set(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_framebuffer *fb = state->fb; ++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); ++ u32 ctl0_offset = vc4_state->dlist_count; ++ const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format); ++ uint32_t offset = fb->offsets[0]; ++ int crtc_x = state->crtc_x; ++ int crtc_y = state->crtc_y; ++ int crtc_w = state->crtc_w; ++ int crtc_h = state->crtc_h; ++ ++ if (state->crtc_w << 16 != state->src_w || ++ state->crtc_h << 16 != state->src_h) { ++ /* We don't support scaling yet, which involves ++ * allocating the LBM memory for scaling temporary ++ * storage, and putting filter kernels in the HVS ++ * context. ++ */ ++ return -EINVAL; ++ } ++ ++ if (crtc_x < 0) { ++ offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x; ++ crtc_w += crtc_x; ++ crtc_x = 0; ++ } ++ ++ if (crtc_y < 0) { ++ offset += fb->pitches[0] * -crtc_y; ++ crtc_h += crtc_y; ++ crtc_y = 0; ++ } ++ ++ vc4_dlist_write(vc4_state, ++ SCALER_CTL0_VALID | ++ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | ++ (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | ++ SCALER_CTL0_UNITY); ++ ++ /* Position Word 0: Image Positions and Alpha Value */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) | ++ VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) | ++ VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y)); ++ ++ /* Position Word 1: Scaled Image Dimensions. ++ * Skipped due to SCALER_CTL0_UNITY scaling. ++ */ ++ ++ /* Position Word 2: Source Image Size, Alpha Mode */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(format->has_alpha ? ++ SCALER_POS2_ALPHA_MODE_PIPELINE : ++ SCALER_POS2_ALPHA_MODE_FIXED, ++ SCALER_POS2_ALPHA_MODE) | ++ VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) | ++ VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT)); ++ ++ /* Position Word 3: Context. Written by the HVS. */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ vc4_state->pw0_offset = vc4_state->dlist_count; ++ ++ /* Pointer Word 0: RGB / Y Pointer */ ++ vc4_dlist_write(vc4_state, bo->paddr + offset); ++ ++ /* Pointer Context Word 0: Written by the HVS */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ /* Pitch word 0: Pointer 0 Pitch */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); ++ ++ vc4_state->dlist[ctl0_offset] |= ++ VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); ++ ++ return 0; ++} ++ ++/* If a modeset involves changing the setup of a plane, the atomic ++ * infrastructure will call this to validate a proposed plane setup. ++ * However, if a plane isn't getting updated, this (and the ++ * corresponding vc4_plane_atomic_update) won't get called. Thus, we ++ * compute the dlist here and have all active plane dlists get updated ++ * in the CRTC's flush. ++ */ ++static int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ vc4_state->dlist_count = 0; ++ ++ if (plane_enabled(state)) ++ return vc4_plane_mode_set(plane, state); ++ else ++ return 0; ++} ++ ++static void vc4_plane_atomic_update(struct drm_plane *plane, ++ struct drm_plane_state *old_state) ++{ ++ /* No contents here. Since we don't know where in the CRTC's ++ * dlist we should be stored, our dlist is uploaded to the ++ * hardware with vc4_plane_write_dlist() at CRTC atomic_flush ++ * time. ++ */ ++} ++ ++u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); ++ int i; ++ ++ vc4_state->hw_dlist = dlist; ++ ++ /* Can't memcpy_toio() because it needs to be 32-bit writes. */ ++ for (i = 0; i < vc4_state->dlist_count; i++) ++ writel(vc4_state->dlist[i], &dlist[i]); ++ ++ return vc4_state->dlist_count; ++} ++ ++u32 vc4_plane_dlist_size(struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ return vc4_state->dlist_count; ++} ++ ++/* Updates the plane to immediately (well, once the FIFO needs ++ * refilling) scan out from at a new framebuffer. ++ */ ++void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); ++ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); ++ uint32_t addr; ++ ++ /* We're skipping the address adjustment for negative origin, ++ * because this is only called on the primary plane. ++ */ ++ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); ++ addr = bo->paddr + fb->offsets[0]; ++ ++ /* Write the new address into the hardware immediately. The ++ * scanout will start from this address as soon as the FIFO ++ * needs to refill with pixels. ++ */ ++ writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]); ++ ++ /* Also update the CPU-side dlist copy, so that any later ++ * atomic updates that don't do a new modeset on our plane ++ * also use our updated address. ++ */ ++ vc4_state->dlist[vc4_state->pw0_offset] = addr; ++} ++ ++static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { ++ .prepare_fb = NULL, ++ .cleanup_fb = NULL, ++ .atomic_check = vc4_plane_atomic_check, ++ .atomic_update = vc4_plane_atomic_update, ++}; ++ ++static void vc4_plane_destroy(struct drm_plane *plane) ++{ ++ drm_plane_helper_disable(plane); ++ drm_plane_cleanup(plane); ++} ++ ++static const struct drm_plane_funcs vc4_plane_funcs = { ++ .update_plane = drm_atomic_helper_update_plane, ++ .disable_plane = drm_atomic_helper_disable_plane, ++ .destroy = vc4_plane_destroy, ++ .set_property = NULL, ++ .reset = vc4_plane_reset, ++ .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .atomic_destroy_state = vc4_plane_destroy_state, ++}; ++ ++struct drm_plane *vc4_plane_init(struct drm_device *dev, ++ enum drm_plane_type type) ++{ ++ struct drm_plane *plane = NULL; ++ struct vc4_plane *vc4_plane; ++ u32 formats[ARRAY_SIZE(hvs_formats)]; ++ int ret = 0; ++ unsigned i; ++ ++ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), ++ GFP_KERNEL); ++ if (!vc4_plane) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) ++ formats[i] = hvs_formats[i].drm; ++ plane = &vc4_plane->base; ++ ret = drm_universal_plane_init(dev, plane, 0xff, ++ &vc4_plane_funcs, ++ formats, ARRAY_SIZE(formats), ++ type); ++ ++ drm_plane_helper_add(plane, &vc4_plane_helper_funcs); ++ ++ return plane; ++fail: ++ if (plane) ++ vc4_plane_destroy(plane); ++ ++ return ERR_PTR(ret); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_qpu_defines.h b/drivers/gpu/drm/vc4/vc4_qpu_defines.h +new file mode 100644 +index 0000000..d5c2f3c +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h +@@ -0,0 +1,264 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef VC4_QPU_DEFINES_H ++#define VC4_QPU_DEFINES_H ++ ++enum qpu_op_add { ++ QPU_A_NOP, ++ QPU_A_FADD, ++ QPU_A_FSUB, ++ QPU_A_FMIN, ++ QPU_A_FMAX, ++ QPU_A_FMINABS, ++ QPU_A_FMAXABS, ++ QPU_A_FTOI, ++ QPU_A_ITOF, ++ QPU_A_ADD = 12, ++ QPU_A_SUB, ++ QPU_A_SHR, ++ QPU_A_ASR, ++ QPU_A_ROR, ++ QPU_A_SHL, ++ QPU_A_MIN, ++ QPU_A_MAX, ++ QPU_A_AND, ++ QPU_A_OR, ++ QPU_A_XOR, ++ QPU_A_NOT, ++ QPU_A_CLZ, ++ QPU_A_V8ADDS = 30, ++ QPU_A_V8SUBS = 31, ++}; ++ ++enum qpu_op_mul { ++ QPU_M_NOP, ++ QPU_M_FMUL, ++ QPU_M_MUL24, ++ QPU_M_V8MULD, ++ QPU_M_V8MIN, ++ QPU_M_V8MAX, ++ QPU_M_V8ADDS, ++ QPU_M_V8SUBS, ++}; ++ ++enum qpu_raddr { ++ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */ ++ /* 0-31 are the plain regfile a or b fields */ ++ QPU_R_UNIF = 32, ++ QPU_R_VARY = 35, ++ QPU_R_ELEM_QPU = 38, ++ QPU_R_NOP, ++ QPU_R_XY_PIXEL_COORD = 41, ++ QPU_R_MS_REV_FLAGS = 41, ++ QPU_R_VPM = 48, ++ QPU_R_VPM_LD_BUSY, ++ QPU_R_VPM_LD_WAIT, ++ QPU_R_MUTEX_ACQUIRE, ++}; ++ ++enum qpu_waddr { ++ /* 0-31 are the plain regfile a or b fields */ ++ QPU_W_ACC0 = 32, /* aka r0 */ ++ QPU_W_ACC1, ++ QPU_W_ACC2, ++ QPU_W_ACC3, ++ QPU_W_TMU_NOSWAP, ++ QPU_W_ACC5, ++ QPU_W_HOST_INT, ++ QPU_W_NOP, ++ QPU_W_UNIFORMS_ADDRESS, ++ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */ ++ QPU_W_MS_FLAGS = 42, ++ QPU_W_REV_FLAG = 42, ++ QPU_W_TLB_STENCIL_SETUP = 43, ++ QPU_W_TLB_Z, ++ QPU_W_TLB_COLOR_MS, ++ QPU_W_TLB_COLOR_ALL, ++ QPU_W_TLB_ALPHA_MASK, ++ QPU_W_VPM, ++ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */ ++ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */ ++ QPU_W_MUTEX_RELEASE, ++ QPU_W_SFU_RECIP, ++ QPU_W_SFU_RECIPSQRT, ++ QPU_W_SFU_EXP, ++ QPU_W_SFU_LOG, ++ QPU_W_TMU0_S, ++ QPU_W_TMU0_T, ++ QPU_W_TMU0_R, ++ QPU_W_TMU0_B, ++ QPU_W_TMU1_S, ++ QPU_W_TMU1_T, ++ QPU_W_TMU1_R, ++ QPU_W_TMU1_B, ++}; ++ ++enum qpu_sig_bits { ++ QPU_SIG_SW_BREAKPOINT, ++ QPU_SIG_NONE, ++ QPU_SIG_THREAD_SWITCH, ++ QPU_SIG_PROG_END, ++ QPU_SIG_WAIT_FOR_SCOREBOARD, ++ QPU_SIG_SCOREBOARD_UNLOCK, ++ QPU_SIG_LAST_THREAD_SWITCH, ++ QPU_SIG_COVERAGE_LOAD, ++ QPU_SIG_COLOR_LOAD, ++ QPU_SIG_COLOR_LOAD_END, ++ QPU_SIG_LOAD_TMU0, ++ QPU_SIG_LOAD_TMU1, ++ QPU_SIG_ALPHA_MASK_LOAD, ++ QPU_SIG_SMALL_IMM, ++ QPU_SIG_LOAD_IMM, ++ QPU_SIG_BRANCH ++}; ++ ++enum qpu_mux { ++ /* hardware mux values */ ++ QPU_MUX_R0, ++ QPU_MUX_R1, ++ QPU_MUX_R2, ++ QPU_MUX_R3, ++ QPU_MUX_R4, ++ QPU_MUX_R5, ++ QPU_MUX_A, ++ QPU_MUX_B, ++ ++ /* non-hardware mux values */ ++ QPU_MUX_IMM, ++}; ++ ++enum qpu_cond { ++ QPU_COND_NEVER, ++ QPU_COND_ALWAYS, ++ QPU_COND_ZS, ++ QPU_COND_ZC, ++ QPU_COND_NS, ++ QPU_COND_NC, ++ QPU_COND_CS, ++ QPU_COND_CC, ++}; ++ ++enum qpu_pack_mul { ++ QPU_PACK_MUL_NOP, ++ /* replicated to each 8 bits of the 32-bit dst. */ ++ QPU_PACK_MUL_8888 = 3, ++ QPU_PACK_MUL_8A, ++ QPU_PACK_MUL_8B, ++ QPU_PACK_MUL_8C, ++ QPU_PACK_MUL_8D, ++}; ++ ++enum qpu_pack_a { ++ QPU_PACK_A_NOP, ++ /* convert to 16 bit float if float input, or to int16. */ ++ QPU_PACK_A_16A, ++ QPU_PACK_A_16B, ++ /* replicated to each 8 bits of the 32-bit dst. */ ++ QPU_PACK_A_8888, ++ /* Convert to 8-bit unsigned int. */ ++ QPU_PACK_A_8A, ++ QPU_PACK_A_8B, ++ QPU_PACK_A_8C, ++ QPU_PACK_A_8D, ++ ++ /* Saturating variants of the previous instructions. */ ++ QPU_PACK_A_32_SAT, /* int-only */ ++ QPU_PACK_A_16A_SAT, /* int or float */ ++ QPU_PACK_A_16B_SAT, ++ QPU_PACK_A_8888_SAT, ++ QPU_PACK_A_8A_SAT, ++ QPU_PACK_A_8B_SAT, ++ QPU_PACK_A_8C_SAT, ++ QPU_PACK_A_8D_SAT, ++}; ++ ++enum qpu_unpack_r4 { ++ QPU_UNPACK_R4_NOP, ++ QPU_UNPACK_R4_F16A_TO_F32, ++ QPU_UNPACK_R4_F16B_TO_F32, ++ QPU_UNPACK_R4_8D_REP, ++ QPU_UNPACK_R4_8A, ++ QPU_UNPACK_R4_8B, ++ QPU_UNPACK_R4_8C, ++ QPU_UNPACK_R4_8D, ++}; ++ ++#define QPU_MASK(high, low) \ ++ ((((uint64_t)1 << ((high) - (low) + 1)) - 1) << (low)) ++ ++#define QPU_GET_FIELD(word, field) \ ++ ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT)) ++ ++#define QPU_SIG_SHIFT 60 ++#define QPU_SIG_MASK QPU_MASK(63, 60) ++ ++#define QPU_UNPACK_SHIFT 57 ++#define QPU_UNPACK_MASK QPU_MASK(59, 57) ++ ++/** ++ * If set, the pack field means PACK_MUL or R4 packing, instead of normal ++ * regfile a packing. ++ */ ++#define QPU_PM ((uint64_t)1 << 56) ++ ++#define QPU_PACK_SHIFT 52 ++#define QPU_PACK_MASK QPU_MASK(55, 52) ++ ++#define QPU_COND_ADD_SHIFT 49 ++#define QPU_COND_ADD_MASK QPU_MASK(51, 49) ++#define QPU_COND_MUL_SHIFT 46 ++#define QPU_COND_MUL_MASK QPU_MASK(48, 46) ++ ++#define QPU_SF ((uint64_t)1 << 45) ++ ++#define QPU_WADDR_ADD_SHIFT 38 ++#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38) ++#define QPU_WADDR_MUL_SHIFT 32 ++#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32) ++ ++#define QPU_OP_MUL_SHIFT 29 ++#define QPU_OP_MUL_MASK QPU_MASK(31, 29) ++ ++#define QPU_RADDR_A_SHIFT 18 ++#define QPU_RADDR_A_MASK QPU_MASK(23, 18) ++#define QPU_RADDR_B_SHIFT 12 ++#define QPU_RADDR_B_MASK QPU_MASK(17, 12) ++#define QPU_SMALL_IMM_SHIFT 12 ++#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12) ++ ++#define QPU_ADD_A_SHIFT 9 ++#define QPU_ADD_A_MASK QPU_MASK(11, 9) ++#define QPU_ADD_B_SHIFT 6 ++#define QPU_ADD_B_MASK QPU_MASK(8, 6) ++#define QPU_MUL_A_SHIFT 3 ++#define QPU_MUL_A_MASK QPU_MASK(5, 3) ++#define QPU_MUL_B_SHIFT 0 ++#define QPU_MUL_B_MASK QPU_MASK(2, 0) ++ ++#define QPU_WS ((uint64_t)1 << 44) ++ ++#define QPU_OP_ADD_SHIFT 24 ++#define QPU_OP_ADD_MASK QPU_MASK(28, 24) ++ ++#endif /* VC4_QPU_DEFINES_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +new file mode 100644 +index 0000000..4e52a0a +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -0,0 +1,570 @@ ++/* ++ * Copyright © 2014-2015 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. ++ */ ++ ++#ifndef VC4_REGS_H ++#define VC4_REGS_H ++ ++#include ++ ++#define VC4_MASK(high, low) ((u32)GENMASK(high, low)) ++/* Using the GNU statement expression extension */ ++#define VC4_SET_FIELD(value, field) \ ++ ({ \ ++ uint32_t fieldval = (value) << field##_SHIFT; \ ++ WARN_ON((fieldval & ~field##_MASK) != 0); \ ++ fieldval & field##_MASK; \ ++ }) ++ ++#define VC4_GET_FIELD(word, field) (((word) & field##_MASK) >> \ ++ field##_SHIFT) ++ ++#define V3D_IDENT0 0x00000 ++# define V3D_EXPECTED_IDENT0 \ ++ ((2 << 24) | \ ++ ('V' << 0) | \ ++ ('3' << 8) | \ ++ ('D' << 16)) ++ ++#define V3D_IDENT1 0x00004 ++/* Multiples of 1kb */ ++# define V3D_IDENT1_VPM_SIZE_MASK VC4_MASK(31, 28) ++# define V3D_IDENT1_VPM_SIZE_SHIFT 28 ++# define V3D_IDENT1_NSEM_MASK VC4_MASK(23, 16) ++# define V3D_IDENT1_NSEM_SHIFT 16 ++# define V3D_IDENT1_TUPS_MASK VC4_MASK(15, 12) ++# define V3D_IDENT1_TUPS_SHIFT 12 ++# define V3D_IDENT1_QUPS_MASK VC4_MASK(11, 8) ++# define V3D_IDENT1_QUPS_SHIFT 8 ++# define V3D_IDENT1_NSLC_MASK VC4_MASK(7, 4) ++# define V3D_IDENT1_NSLC_SHIFT 4 ++# define V3D_IDENT1_REV_MASK VC4_MASK(3, 0) ++# define V3D_IDENT1_REV_SHIFT 0 ++ ++#define V3D_IDENT2 0x00008 ++#define V3D_SCRATCH 0x00010 ++#define V3D_L2CACTL 0x00020 ++# define V3D_L2CACTL_L2CCLR BIT(2) ++# define V3D_L2CACTL_L2CDIS BIT(1) ++# define V3D_L2CACTL_L2CENA BIT(0) ++ ++#define V3D_SLCACTL 0x00024 ++# define V3D_SLCACTL_T1CC_MASK VC4_MASK(27, 24) ++# define V3D_SLCACTL_T1CC_SHIFT 24 ++# define V3D_SLCACTL_T0CC_MASK VC4_MASK(19, 16) ++# define V3D_SLCACTL_T0CC_SHIFT 16 ++# define V3D_SLCACTL_UCC_MASK VC4_MASK(11, 8) ++# define V3D_SLCACTL_UCC_SHIFT 8 ++# define V3D_SLCACTL_ICC_MASK VC4_MASK(3, 0) ++# define V3D_SLCACTL_ICC_SHIFT 0 ++ ++#define V3D_INTCTL 0x00030 ++#define V3D_INTENA 0x00034 ++#define V3D_INTDIS 0x00038 ++# define V3D_INT_SPILLUSE BIT(3) ++# define V3D_INT_OUTOMEM BIT(2) ++# define V3D_INT_FLDONE BIT(1) ++# define V3D_INT_FRDONE BIT(0) ++ ++#define V3D_CT0CS 0x00100 ++#define V3D_CT1CS 0x00104 ++#define V3D_CTNCS(n) (V3D_CT0CS + 4 * n) ++# define V3D_CTRSTA BIT(15) ++# define V3D_CTSEMA BIT(12) ++# define V3D_CTRTSD BIT(8) ++# define V3D_CTRUN BIT(5) ++# define V3D_CTSUBS BIT(4) ++# define V3D_CTERR BIT(3) ++# define V3D_CTMODE BIT(0) ++ ++#define V3D_CT0EA 0x00108 ++#define V3D_CT1EA 0x0010c ++#define V3D_CTNEA(n) (V3D_CT0EA + 4 * (n)) ++#define V3D_CT0CA 0x00110 ++#define V3D_CT1CA 0x00114 ++#define V3D_CTNCA(n) (V3D_CT0CA + 4 * (n)) ++#define V3D_CT00RA0 0x00118 ++#define V3D_CT01RA0 0x0011c ++#define V3D_CTNRA0(n) (V3D_CT00RA0 + 4 * (n)) ++#define V3D_CT0LC 0x00120 ++#define V3D_CT1LC 0x00124 ++#define V3D_CTNLC(n) (V3D_CT0LC + 4 * (n)) ++#define V3D_CT0PC 0x00128 ++#define V3D_CT1PC 0x0012c ++#define V3D_CTNPC(n) (V3D_CT0PC + 4 * (n)) ++ ++#define V3D_PCS 0x00130 ++# define V3D_BMOOM BIT(8) ++# define V3D_RMBUSY BIT(3) ++# define V3D_RMACTIVE BIT(2) ++# define V3D_BMBUSY BIT(1) ++# define V3D_BMACTIVE BIT(0) ++ ++#define V3D_BFC 0x00134 ++#define V3D_RFC 0x00138 ++#define V3D_BPCA 0x00300 ++#define V3D_BPCS 0x00304 ++#define V3D_BPOA 0x00308 ++#define V3D_BPOS 0x0030c ++#define V3D_BXCF 0x00310 ++#define V3D_SQRSV0 0x00410 ++#define V3D_SQRSV1 0x00414 ++#define V3D_SQCNTL 0x00418 ++#define V3D_SRQPC 0x00430 ++#define V3D_SRQUA 0x00434 ++#define V3D_SRQUL 0x00438 ++#define V3D_SRQCS 0x0043c ++#define V3D_VPACNTL 0x00500 ++#define V3D_VPMBASE 0x00504 ++#define V3D_PCTRC 0x00670 ++#define V3D_PCTRE 0x00674 ++#define V3D_PCTR0 0x00680 ++#define V3D_PCTRS0 0x00684 ++#define V3D_PCTR1 0x00688 ++#define V3D_PCTRS1 0x0068c ++#define V3D_PCTR2 0x00690 ++#define V3D_PCTRS2 0x00694 ++#define V3D_PCTR3 0x00698 ++#define V3D_PCTRS3 0x0069c ++#define V3D_PCTR4 0x006a0 ++#define V3D_PCTRS4 0x006a4 ++#define V3D_PCTR5 0x006a8 ++#define V3D_PCTRS5 0x006ac ++#define V3D_PCTR6 0x006b0 ++#define V3D_PCTRS6 0x006b4 ++#define V3D_PCTR7 0x006b8 ++#define V3D_PCTRS7 0x006bc ++#define V3D_PCTR8 0x006c0 ++#define V3D_PCTRS8 0x006c4 ++#define V3D_PCTR9 0x006c8 ++#define V3D_PCTRS9 0x006cc ++#define V3D_PCTR10 0x006d0 ++#define V3D_PCTRS10 0x006d4 ++#define V3D_PCTR11 0x006d8 ++#define V3D_PCTRS11 0x006dc ++#define V3D_PCTR12 0x006e0 ++#define V3D_PCTRS12 0x006e4 ++#define V3D_PCTR13 0x006e8 ++#define V3D_PCTRS13 0x006ec ++#define V3D_PCTR14 0x006f0 ++#define V3D_PCTRS14 0x006f4 ++#define V3D_PCTR15 0x006f8 ++#define V3D_PCTRS15 0x006fc ++#define V3D_DBGE 0x00f00 ++#define V3D_FDBGO 0x00f04 ++#define V3D_FDBGB 0x00f08 ++#define V3D_FDBGR 0x00f0c ++#define V3D_FDBGS 0x00f10 ++#define V3D_ERRSTAT 0x00f20 ++ ++#define PV_CONTROL 0x00 ++# define PV_CONTROL_FORMAT_MASK VC4_MASK(23, 21) ++# define PV_CONTROL_FORMAT_SHIFT 21 ++# define PV_CONTROL_FORMAT_24 0 ++# define PV_CONTROL_FORMAT_DSIV_16 1 ++# define PV_CONTROL_FORMAT_DSIC_16 2 ++# define PV_CONTROL_FORMAT_DSIV_18 3 ++# define PV_CONTROL_FORMAT_DSIV_24 4 ++ ++# define PV_CONTROL_FIFO_LEVEL_MASK VC4_MASK(20, 15) ++# define PV_CONTROL_FIFO_LEVEL_SHIFT 15 ++# define PV_CONTROL_CLR_AT_START BIT(14) ++# define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) ++# define PV_CONTROL_WAIT_HSTART BIT(12) ++# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 ++# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 ++# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) ++# define PV_CONTROL_CLK_SELECT_SHIFT 2 ++# define PV_CONTROL_FIFO_CLR BIT(1) ++# define PV_CONTROL_EN BIT(0) ++ ++#define PV_V_CONTROL 0x04 ++# define PV_VCONTROL_INTERLACE BIT(4) ++# define PV_VCONTROL_CONTINUOUS BIT(1) ++# define PV_VCONTROL_VIDEN BIT(0) ++ ++#define PV_VSYNCD 0x08 ++ ++#define PV_HORZA 0x0c ++# define PV_HORZA_HBP_MASK VC4_MASK(31, 16) ++# define PV_HORZA_HBP_SHIFT 16 ++# define PV_HORZA_HSYNC_MASK VC4_MASK(15, 0) ++# define PV_HORZA_HSYNC_SHIFT 0 ++ ++#define PV_HORZB 0x10 ++# define PV_HORZB_HFP_MASK VC4_MASK(31, 16) ++# define PV_HORZB_HFP_SHIFT 16 ++# define PV_HORZB_HACTIVE_MASK VC4_MASK(15, 0) ++# define PV_HORZB_HACTIVE_SHIFT 0 ++ ++#define PV_VERTA 0x14 ++# define PV_VERTA_VBP_MASK VC4_MASK(31, 16) ++# define PV_VERTA_VBP_SHIFT 16 ++# define PV_VERTA_VSYNC_MASK VC4_MASK(15, 0) ++# define PV_VERTA_VSYNC_SHIFT 0 ++ ++#define PV_VERTB 0x18 ++# define PV_VERTB_VFP_MASK VC4_MASK(31, 16) ++# define PV_VERTB_VFP_SHIFT 16 ++# define PV_VERTB_VACTIVE_MASK VC4_MASK(15, 0) ++# define PV_VERTB_VACTIVE_SHIFT 0 ++ ++#define PV_VERTA_EVEN 0x1c ++#define PV_VERTB_EVEN 0x20 ++ ++#define PV_INTEN 0x24 ++#define PV_INTSTAT 0x28 ++# define PV_INT_VID_IDLE BIT(9) ++# define PV_INT_VFP_END BIT(8) ++# define PV_INT_VFP_START BIT(7) ++# define PV_INT_VACT_START BIT(6) ++# define PV_INT_VBP_START BIT(5) ++# define PV_INT_VSYNC_START BIT(4) ++# define PV_INT_HFP_START BIT(3) ++# define PV_INT_HACT_START BIT(2) ++# define PV_INT_HBP_START BIT(1) ++# define PV_INT_HSYNC_START BIT(0) ++ ++#define PV_STAT 0x2c ++ ++#define PV_HACT_ACT 0x30 ++ ++#define SCALER_DISPCTRL 0x00000000 ++/* Global register for clock gating the HVS */ ++# define SCALER_DISPCTRL_ENABLE BIT(31) ++# define SCALER_DISPCTRL_DSP2EISLUR BIT(15) ++# define SCALER_DISPCTRL_DSP1EISLUR BIT(14) ++/* Enables Display 0 short line and underrun contribution to ++ * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are ++ * always enabled. ++ */ ++# define SCALER_DISPCTRL_DSP0EISLUR BIT(13) ++# define SCALER_DISPCTRL_DSP2EIEOLN BIT(12) ++# define SCALER_DISPCTRL_DSP2EIEOF BIT(11) ++# define SCALER_DISPCTRL_DSP1EIEOLN BIT(10) ++# define SCALER_DISPCTRL_DSP1EIEOF BIT(9) ++/* Enables Display 0 end-of-line-N contribution to ++ * SCALER_DISPSTAT_IRQDISP0 ++ */ ++# define SCALER_DISPCTRL_DSP0EIEOLN BIT(8) ++/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ ++# define SCALER_DISPCTRL_DSP0EIEOF BIT(7) ++ ++# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) ++# define SCALER_DISPCTRL_SLVWREIRQ BIT(5) ++# define SCALER_DISPCTRL_DMAEIRQ BIT(4) ++# define SCALER_DISPCTRL_DISP2EIRQ BIT(3) ++# define SCALER_DISPCTRL_DISP1EIRQ BIT(2) ++/* Enables interrupt generation on the enabled EOF/EOLN/EISLUR ++ * bits and short frames.. ++ */ ++# define SCALER_DISPCTRL_DISP0EIRQ BIT(1) ++/* Enables interrupt generation on scaler profiler interrupt. */ ++# define SCALER_DISPCTRL_SCLEIRQ BIT(0) ++ ++#define SCALER_DISPSTAT 0x00000004 ++# define SCALER_DISPSTAT_COBLOW2 BIT(29) ++# define SCALER_DISPSTAT_EOLN2 BIT(28) ++# define SCALER_DISPSTAT_ESFRAME2 BIT(27) ++# define SCALER_DISPSTAT_ESLINE2 BIT(26) ++# define SCALER_DISPSTAT_EUFLOW2 BIT(25) ++# define SCALER_DISPSTAT_EOF2 BIT(24) ++ ++# define SCALER_DISPSTAT_COBLOW1 BIT(21) ++# define SCALER_DISPSTAT_EOLN1 BIT(20) ++# define SCALER_DISPSTAT_ESFRAME1 BIT(19) ++# define SCALER_DISPSTAT_ESLINE1 BIT(18) ++# define SCALER_DISPSTAT_EUFLOW1 BIT(17) ++# define SCALER_DISPSTAT_EOF1 BIT(16) ++ ++# define SCALER_DISPSTAT_RESP_MASK VC4_MASK(15, 14) ++# define SCALER_DISPSTAT_RESP_SHIFT 14 ++# define SCALER_DISPSTAT_RESP_OKAY 0 ++# define SCALER_DISPSTAT_RESP_EXOKAY 1 ++# define SCALER_DISPSTAT_RESP_SLVERR 2 ++# define SCALER_DISPSTAT_RESP_DECERR 3 ++ ++# define SCALER_DISPSTAT_COBLOW0 BIT(13) ++/* Set when the DISPEOLN line is done compositing. */ ++# define SCALER_DISPSTAT_EOLN0 BIT(12) ++/* Set when VSTART is seen but there are still pixels in the current ++ * output line. ++ */ ++# define SCALER_DISPSTAT_ESFRAME0 BIT(11) ++/* Set when HSTART is seen but there are still pixels in the current ++ * output line. ++ */ ++# define SCALER_DISPSTAT_ESLINE0 BIT(10) ++/* Set when the the downstream tries to read from the display FIFO ++ * while it's empty. ++ */ ++# define SCALER_DISPSTAT_EUFLOW0 BIT(9) ++/* Set when the display mode changes from RUN to EOF */ ++# define SCALER_DISPSTAT_EOF0 BIT(8) ++ ++/* Set on AXI invalid DMA ID error. */ ++# define SCALER_DISPSTAT_DMA_ERROR BIT(7) ++/* Set on AXI slave read decode error */ ++# define SCALER_DISPSTAT_IRQSLVRD BIT(6) ++/* Set on AXI slave write decode error */ ++# define SCALER_DISPSTAT_IRQSLVWR BIT(5) ++/* Set when SCALER_DISPSTAT_DMA_ERROR is set, or ++ * SCALER_DISPSTAT_RESP_ERROR is not SCALER_DISPSTAT_RESP_OKAY. ++ */ ++# define SCALER_DISPSTAT_IRQDMA BIT(4) ++# define SCALER_DISPSTAT_IRQDISP2 BIT(3) ++# define SCALER_DISPSTAT_IRQDISP1 BIT(2) ++/* Set when any of the EOF/EOLN/ESFRAME/ESLINE bits are set and their ++ * corresponding interrupt bit is enabled in DISPCTRL. ++ */ ++# define SCALER_DISPSTAT_IRQDISP0 BIT(1) ++/* On read, the profiler interrupt. On write, clear *all* interrupt bits. */ ++# define SCALER_DISPSTAT_IRQSCL BIT(0) ++ ++#define SCALER_DISPID 0x00000008 ++#define SCALER_DISPECTRL 0x0000000c ++#define SCALER_DISPPROF 0x00000010 ++#define SCALER_DISPDITHER 0x00000014 ++#define SCALER_DISPEOLN 0x00000018 ++#define SCALER_DISPLIST0 0x00000020 ++#define SCALER_DISPLIST1 0x00000024 ++#define SCALER_DISPLIST2 0x00000028 ++#define SCALER_DISPLSTAT 0x0000002c ++#define SCALER_DISPLISTX(x) (SCALER_DISPLIST0 + \ ++ (x) * (SCALER_DISPLIST1 - \ ++ SCALER_DISPLIST0)) ++ ++#define SCALER_DISPLACT0 0x00000030 ++#define SCALER_DISPLACT1 0x00000034 ++#define SCALER_DISPLACT2 0x00000038 ++#define SCALER_DISPCTRL0 0x00000040 ++# define SCALER_DISPCTRLX_ENABLE BIT(31) ++# define SCALER_DISPCTRLX_RESET BIT(30) ++# define SCALER_DISPCTRLX_WIDTH_MASK VC4_MASK(23, 12) ++# define SCALER_DISPCTRLX_WIDTH_SHIFT 12 ++# define SCALER_DISPCTRLX_HEIGHT_MASK VC4_MASK(11, 0) ++# define SCALER_DISPCTRLX_HEIGHT_SHIFT 0 ++ ++#define SCALER_DISPBKGND0 0x00000044 ++#define SCALER_DISPSTAT0 0x00000048 ++#define SCALER_DISPBASE0 0x0000004c ++# define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30) ++# define SCALER_DISPSTATX_MODE_SHIFT 30 ++# define SCALER_DISPSTATX_MODE_DISABLED 0 ++# define SCALER_DISPSTATX_MODE_INIT 1 ++# define SCALER_DISPSTATX_MODE_RUN 2 ++# define SCALER_DISPSTATX_MODE_EOF 3 ++# define SCALER_DISPSTATX_FULL BIT(29) ++# define SCALER_DISPSTATX_EMPTY BIT(28) ++#define SCALER_DISPCTRL1 0x00000050 ++#define SCALER_DISPBKGND1 0x00000054 ++#define SCALER_DISPSTAT1 0x00000058 ++#define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \ ++ (x) * (SCALER_DISPSTAT1 - \ ++ SCALER_DISPSTAT0)) ++#define SCALER_DISPBASE1 0x0000005c ++#define SCALER_DISPCTRL2 0x00000060 ++#define SCALER_DISPCTRLX(x) (SCALER_DISPCTRL0 + \ ++ (x) * (SCALER_DISPCTRL1 - \ ++ SCALER_DISPCTRL0)) ++#define SCALER_DISPBKGND2 0x00000064 ++#define SCALER_DISPSTAT2 0x00000068 ++#define SCALER_DISPBASE2 0x0000006c ++#define SCALER_DISPALPHA2 0x00000070 ++#define SCALER_GAMADDR 0x00000078 ++#define SCALER_GAMDATA 0x000000e0 ++#define SCALER_DLIST_START 0x00002000 ++#define SCALER_DLIST_SIZE 0x00004000 ++ ++#define VC4_HDMI_CORE_REV 0x000 ++ ++#define VC4_HDMI_SW_RESET_CONTROL 0x004 ++# define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) ++# define VC4_HDMI_SW_RESET_HDMI BIT(0) ++ ++#define VC4_HDMI_HOTPLUG_INT 0x008 ++ ++#define VC4_HDMI_HOTPLUG 0x00c ++# define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) ++ ++#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 ++# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) ++ ++#define VC4_HDMI_HORZA 0x0c4 ++# define VC4_HDMI_HORZA_VPOS BIT(14) ++# define VC4_HDMI_HORZA_HPOS BIT(13) ++/* Horizontal active pixels (hdisplay). */ ++# define VC4_HDMI_HORZA_HAP_MASK VC4_MASK(12, 0) ++# define VC4_HDMI_HORZA_HAP_SHIFT 0 ++ ++#define VC4_HDMI_HORZB 0x0c8 ++/* Horizontal pack porch (htotal - hsync_end). */ ++# define VC4_HDMI_HORZB_HBP_MASK VC4_MASK(29, 20) ++# define VC4_HDMI_HORZB_HBP_SHIFT 20 ++/* Horizontal sync pulse (hsync_end - hsync_start). */ ++# define VC4_HDMI_HORZB_HSP_MASK VC4_MASK(19, 10) ++# define VC4_HDMI_HORZB_HSP_SHIFT 10 ++/* Horizontal front porch (hsync_start - hdisplay). */ ++# define VC4_HDMI_HORZB_HFP_MASK VC4_MASK(9, 0) ++# define VC4_HDMI_HORZB_HFP_SHIFT 0 ++ ++#define VC4_HDMI_FIFO_CTL 0x05c ++# define VC4_HDMI_FIFO_CTL_RECENTER_DONE BIT(14) ++# define VC4_HDMI_FIFO_CTL_USE_EMPTY BIT(13) ++# define VC4_HDMI_FIFO_CTL_ON_VB BIT(7) ++# define VC4_HDMI_FIFO_CTL_RECENTER BIT(6) ++# define VC4_HDMI_FIFO_CTL_FIFO_RESET BIT(5) ++# define VC4_HDMI_FIFO_CTL_USE_PLL_LOCK BIT(4) ++# define VC4_HDMI_FIFO_CTL_INV_CLK_XFR BIT(3) ++# define VC4_HDMI_FIFO_CTL_CAPTURE_PTR BIT(2) ++# define VC4_HDMI_FIFO_CTL_USE_FULL BIT(1) ++# define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N BIT(0) ++# define VC4_HDMI_FIFO_VALID_WRITE_MASK 0xefff ++ ++#define VC4_HDMI_SCHEDULER_CONTROL 0x0c0 ++# define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15) ++# define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5) ++# define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT BIT(3) ++# define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE BIT(1) ++# define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI BIT(0) ++ ++#define VC4_HDMI_VERTA0 0x0cc ++#define VC4_HDMI_VERTA1 0x0d4 ++/* Vertical sync pulse (vsync_end - vsync_start). */ ++# define VC4_HDMI_VERTA_VSP_MASK VC4_MASK(24, 20) ++# define VC4_HDMI_VERTA_VSP_SHIFT 20 ++/* Vertical front porch (vsync_start - vdisplay). */ ++# define VC4_HDMI_VERTA_VFP_MASK VC4_MASK(19, 13) ++# define VC4_HDMI_VERTA_VFP_SHIFT 13 ++/* Vertical active lines (vdisplay). */ ++# define VC4_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) ++# define VC4_HDMI_VERTA_VAL_SHIFT 0 ++ ++#define VC4_HDMI_VERTB0 0x0d0 ++#define VC4_HDMI_VERTB1 0x0d8 ++/* Vertical sync pulse offset (for interlaced) */ ++# define VC4_HDMI_VERTB_VSPO_MASK VC4_MASK(21, 9) ++# define VC4_HDMI_VERTB_VSPO_SHIFT 9 ++/* Vertical pack porch (vtotal - vsync_end). */ ++# define VC4_HDMI_VERTB_VBP_MASK VC4_MASK(8, 0) ++# define VC4_HDMI_VERTB_VBP_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 ++ ++#define VC4_HD_M_CTL 0x00c ++# define VC4_HD_M_SW_RST BIT(2) ++# define VC4_HD_M_ENABLE BIT(0) ++ ++#define VC4_HD_MAI_CTL 0x014 ++ ++#define VC4_HD_VID_CTL 0x038 ++# define VC4_HD_VID_CTL_ENABLE BIT(31) ++# define VC4_HD_VID_CTL_UNDERFLOW_ENABLE BIT(30) ++# define VC4_HD_VID_CTL_FRAME_COUNTER_RESET BIT(29) ++# define VC4_HD_VID_CTL_VSYNC_LOW BIT(28) ++# define VC4_HD_VID_CTL_HSYNC_LOW BIT(27) ++ ++#define VC4_HD_CSC_CTL 0x040 ++# define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) ++# define VC4_HD_CSC_CTL_ORDER_SHIFT 5 ++# define VC4_HD_CSC_CTL_ORDER_RGB 0 ++# define VC4_HD_CSC_CTL_ORDER_BGR 1 ++# define VC4_HD_CSC_CTL_ORDER_BRG 2 ++# define VC4_HD_CSC_CTL_ORDER_GRB 3 ++# define VC4_HD_CSC_CTL_ORDER_GBR 4 ++# define VC4_HD_CSC_CTL_ORDER_RBG 5 ++# define VC4_HD_CSC_CTL_PADMSB BIT(4) ++# define VC4_HD_CSC_CTL_MODE_MASK VC4_MASK(3, 2) ++# define VC4_HD_CSC_CTL_MODE_SHIFT 2 ++# define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 ++# define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 ++# define VC4_HD_CSC_CTL_MODE_CUSTOM 2 ++# define VC4_HD_CSC_CTL_RGB2YCC BIT(1) ++# define VC4_HD_CSC_CTL_ENABLE BIT(0) ++ ++#define VC4_HD_FRAME_COUNT 0x068 ++ ++/* HVS display list information. */ ++#define HVS_BOOTLOADER_DLIST_END 32 ++ ++enum hvs_pixel_format { ++ /* 8bpp */ ++ HVS_PIXEL_FORMAT_RGB332 = 0, ++ /* 16bpp */ ++ HVS_PIXEL_FORMAT_RGBA4444 = 1, ++ HVS_PIXEL_FORMAT_RGB555 = 2, ++ HVS_PIXEL_FORMAT_RGBA5551 = 3, ++ HVS_PIXEL_FORMAT_RGB565 = 4, ++ /* 24bpp */ ++ HVS_PIXEL_FORMAT_RGB888 = 5, ++ HVS_PIXEL_FORMAT_RGBA6666 = 6, ++ /* 32bpp */ ++ HVS_PIXEL_FORMAT_RGBA8888 = 7 ++}; ++ ++/* Note: the LSB is the rightmost character shown. Only valid for ++ * HVS_PIXEL_FORMAT_RGB8888, not RGB888. ++ */ ++#define HVS_PIXEL_ORDER_RGBA 0 ++#define HVS_PIXEL_ORDER_BGRA 1 ++#define HVS_PIXEL_ORDER_ARGB 2 ++#define HVS_PIXEL_ORDER_ABGR 3 ++ ++#define HVS_PIXEL_ORDER_XBRG 0 ++#define HVS_PIXEL_ORDER_XRBG 1 ++#define HVS_PIXEL_ORDER_XRGB 2 ++#define HVS_PIXEL_ORDER_XBGR 3 ++ ++#define HVS_PIXEL_ORDER_XYCBCR 0 ++#define HVS_PIXEL_ORDER_XYCRCB 1 ++#define HVS_PIXEL_ORDER_YXCBCR 2 ++#define HVS_PIXEL_ORDER_YXCRCB 3 ++ ++#define SCALER_CTL0_END BIT(31) ++#define SCALER_CTL0_VALID BIT(30) ++ ++#define SCALER_CTL0_SIZE_MASK VC4_MASK(29, 24) ++#define SCALER_CTL0_SIZE_SHIFT 24 ++ ++#define SCALER_CTL0_HFLIP BIT(16) ++#define SCALER_CTL0_VFLIP BIT(15) ++ ++#define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13) ++#define SCALER_CTL0_ORDER_SHIFT 13 ++ ++/* Set to indicate no scaling. */ ++#define SCALER_CTL0_UNITY BIT(4) ++ ++#define SCALER_CTL0_PIXEL_FORMAT_MASK VC4_MASK(3, 0) ++#define SCALER_CTL0_PIXEL_FORMAT_SHIFT 0 ++ ++#define SCALER_POS0_FIXED_ALPHA_MASK VC4_MASK(31, 24) ++#define SCALER_POS0_FIXED_ALPHA_SHIFT 24 ++ ++#define SCALER_POS0_START_Y_MASK VC4_MASK(23, 12) ++#define SCALER_POS0_START_Y_SHIFT 12 ++ ++#define SCALER_POS0_START_X_MASK VC4_MASK(11, 0) ++#define SCALER_POS0_START_X_SHIFT 0 ++ ++#define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30) ++#define SCALER_POS2_ALPHA_MODE_SHIFT 30 ++#define SCALER_POS2_ALPHA_MODE_PIPELINE 0 ++#define SCALER_POS2_ALPHA_MODE_FIXED 1 ++#define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 ++#define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 ++ ++#define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) ++#define SCALER_POS2_HEIGHT_SHIFT 16 ++ ++#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) ++#define SCALER_POS2_WIDTH_SHIFT 0 ++ ++#define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0) ++#define SCALER_SRC_PITCH_SHIFT 0 ++ ++#endif /* VC4_REGS_H */ +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +new file mode 100644 +index 0000000..8a2a312 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -0,0 +1,634 @@ ++/* ++ * Copyright © 2014-2015 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Render command list generation ++ * ++ * In the VC4 driver, render command list generation is performed by the ++ * kernel instead of userspace. We do this because validating a ++ * user-submitted command list is hard to get right and has high CPU overhead, ++ * while the number of valid configurations for render command lists is ++ * actually fairly low. ++ */ ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_packet.h" ++ ++struct vc4_rcl_setup { ++ struct drm_gem_cma_object *color_read; ++ struct drm_gem_cma_object *color_write; ++ struct drm_gem_cma_object *zs_read; ++ struct drm_gem_cma_object *zs_write; ++ struct drm_gem_cma_object *msaa_color_write; ++ struct drm_gem_cma_object *msaa_zs_write; ++ ++ struct drm_gem_cma_object *rcl; ++ u32 next_offset; ++}; ++ ++static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) ++{ ++ *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 1; ++} ++ ++static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val) ++{ ++ *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 2; ++} ++ ++static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val) ++{ ++ *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val; ++ setup->next_offset += 4; ++} ++ ++/* ++ * Emits a no-op STORE_TILE_BUFFER_GENERAL. ++ * ++ * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of ++ * some sort before another load is triggered. ++ */ ++static void vc4_store_before_load(struct vc4_rcl_setup *setup) ++{ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, ++ VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE, ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER) | ++ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR | ++ VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR | ++ VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR); ++ rcl_u32(setup, 0); /* no address, since we're in None mode */ ++} ++ ++/* ++ * Calculates the physical address of the start of a tile in a RCL surface. ++ * ++ * Unlike the other load/store packets, ++ * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile ++ * coordinates packet, and instead just store to the address given. ++ */ ++static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *bo, ++ struct drm_vc4_submit_rcl_surface *surf, ++ uint8_t x, uint8_t y) ++{ ++ return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE * ++ (DIV_ROUND_UP(exec->args->width, 32) * y + x); ++} ++ ++/* ++ * Emits a PACKET_TILE_COORDINATES if one isn't already pending. ++ * ++ * The tile coordinates packet triggers a pending load if there is one, are ++ * used for clipping during rendering, and determine where loads/stores happen ++ * relative to their base address. ++ */ ++static void vc4_tile_coordinates(struct vc4_rcl_setup *setup, ++ uint32_t x, uint32_t y) ++{ ++ rcl_u8(setup, VC4_PACKET_TILE_COORDINATES); ++ rcl_u8(setup, x); ++ rcl_u8(setup, y); ++} ++ ++static void emit_tile(struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup, ++ uint8_t x, uint8_t y, bool first, bool last) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ ++ /* Note that the load doesn't actually occur until the ++ * tile coords packet is processed, and only one load ++ * may be outstanding at a time. ++ */ ++ if (setup->color_read) { ++ if (args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->color_read, ++ &args->color_read, x, y) | ++ VC4_LOADSTORE_FULL_RES_DISABLE_ZS); ++ } else { ++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->color_read.bits); ++ rcl_u32(setup, setup->color_read->paddr + ++ args->color_read.offset); ++ } ++ } ++ ++ if (setup->zs_read) { ++ if (args->zs_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->zs_read, ++ &args->zs_read, x, y) | ++ VC4_LOADSTORE_FULL_RES_DISABLE_COLOR); ++ } else { ++ if (setup->color_read) { ++ /* Exec previous load. */ ++ vc4_tile_coordinates(setup, x, y); ++ vc4_store_before_load(setup); ++ } ++ ++ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->zs_read.bits); ++ rcl_u32(setup, setup->zs_read->paddr + ++ args->zs_read.offset); ++ } ++ } ++ ++ /* Clipping depends on tile coordinates having been ++ * emitted, so we always need one here. ++ */ ++ vc4_tile_coordinates(setup, x, y); ++ ++ /* Wait for the binner before jumping to the first ++ * tile's lists. ++ */ ++ if (first && has_bin) ++ rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE); ++ ++ if (has_bin) { ++ rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); ++ rcl_u32(setup, (exec->tile_bo->paddr + ++ exec->tile_alloc_offset + ++ (y * exec->bin_tiles_x + x) * 32)); ++ } ++ ++ if (setup->msaa_color_write) { ++ bool last_tile_write = (!setup->msaa_zs_write && ++ !setup->zs_write && ++ !setup->color_write); ++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS; ++ ++ if (!last_tile_write) ++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; ++ else if (last) ++ bits |= VC4_LOADSTORE_FULL_RES_EOF; ++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->msaa_color_write, ++ &args->msaa_color_write, x, y) | ++ bits); ++ } ++ ++ if (setup->msaa_zs_write) { ++ bool last_tile_write = (!setup->zs_write && ++ !setup->color_write); ++ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR; ++ ++ if (setup->msaa_color_write) ++ vc4_tile_coordinates(setup, x, y); ++ if (!last_tile_write) ++ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; ++ else if (last) ++ bits |= VC4_LOADSTORE_FULL_RES_EOF; ++ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); ++ rcl_u32(setup, ++ vc4_full_res_offset(exec, setup->msaa_zs_write, ++ &args->msaa_zs_write, x, y) | ++ bits); ++ } ++ ++ if (setup->zs_write) { ++ bool last_tile_write = !setup->color_write; ++ ++ if (setup->msaa_color_write || setup->msaa_zs_write) ++ vc4_tile_coordinates(setup, x, y); ++ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, args->zs_write.bits | ++ (last_tile_write ? ++ 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR)); ++ rcl_u32(setup, ++ (setup->zs_write->paddr + args->zs_write.offset) | ++ ((last && last_tile_write) ? ++ VC4_LOADSTORE_TILE_BUFFER_EOF : 0)); ++ } ++ ++ if (setup->color_write) { ++ if (setup->msaa_color_write || setup->msaa_zs_write || ++ setup->zs_write) { ++ vc4_tile_coordinates(setup, x, y); ++ } ++ ++ if (last) ++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF); ++ else ++ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER); ++ } ++} ++ ++static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ uint8_t min_x_tile = args->min_x_tile; ++ uint8_t min_y_tile = args->min_y_tile; ++ uint8_t max_x_tile = args->max_x_tile; ++ uint8_t max_y_tile = args->max_y_tile; ++ uint8_t xtiles = max_x_tile - min_x_tile + 1; ++ uint8_t ytiles = max_y_tile - min_y_tile + 1; ++ uint8_t x, y; ++ uint32_t size, loop_body_size; ++ ++ size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE; ++ loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE; ++ ++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { ++ size += VC4_PACKET_CLEAR_COLORS_SIZE + ++ VC4_PACKET_TILE_COORDINATES_SIZE + ++ VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ } ++ ++ if (setup->color_read) { ++ if (args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; ++ } else { ++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; ++ } ++ } ++ if (setup->zs_read) { ++ if (args->zs_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; ++ } else { ++ if (setup->color_read && ++ !(args->color_read.flags & ++ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) { ++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE; ++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ } ++ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; ++ } ++ } ++ ++ if (has_bin) { ++ size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE; ++ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE; ++ } ++ ++ if (setup->msaa_color_write) ++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; ++ if (setup->msaa_zs_write) ++ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; ++ ++ if (setup->zs_write) ++ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; ++ if (setup->color_write) ++ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE; ++ ++ /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */ ++ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE * ++ ((setup->msaa_color_write != NULL) + ++ (setup->msaa_zs_write != NULL) + ++ (setup->color_write != NULL) + ++ (setup->zs_write != NULL) - 1); ++ ++ size += xtiles * ytiles * loop_body_size; ++ ++ setup->rcl = &vc4_bo_create(dev, size, true)->base; ++ if (!setup->rcl) ++ return -ENOMEM; ++ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, ++ &exec->unref_list); ++ ++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); ++ rcl_u32(setup, ++ (setup->color_write ? (setup->color_write->paddr + ++ args->color_write.offset) : ++ 0)); ++ rcl_u16(setup, args->width); ++ rcl_u16(setup, args->height); ++ rcl_u16(setup, args->color_write.bits); ++ ++ /* The tile buffer gets cleared when the previous tile is stored. If ++ * the clear values changed between frames, then the tile buffer has ++ * stale clear values in it, so we have to do a store in None mode (no ++ * writes) so that we trigger the tile buffer clear. ++ */ ++ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { ++ rcl_u8(setup, VC4_PACKET_CLEAR_COLORS); ++ rcl_u32(setup, args->clear_color[0]); ++ rcl_u32(setup, args->clear_color[1]); ++ rcl_u32(setup, args->clear_z); ++ rcl_u8(setup, args->clear_s); ++ ++ vc4_tile_coordinates(setup, 0, 0); ++ ++ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); ++ rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE); ++ rcl_u32(setup, 0); /* no address, since we're in None mode */ ++ } ++ ++ for (y = min_y_tile; y <= max_y_tile; y++) { ++ for (x = min_x_tile; x <= max_x_tile; x++) { ++ bool first = (x == min_x_tile && y == min_y_tile); ++ bool last = (x == max_x_tile && y == max_y_tile); ++ ++ emit_tile(exec, setup, x, y, first, last); ++ } ++ } ++ ++ BUG_ON(setup->next_offset != size); ++ exec->ct1ca = setup->rcl->paddr; ++ exec->ct1ea = setup->rcl->paddr + setup->next_offset; ++ ++ return 0; ++} ++ ++static int vc4_full_res_bounds_check(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object *obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ struct drm_vc4_submit_cl *args = exec->args; ++ u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32); ++ ++ if (surf->offset > obj->base.size) { ++ DRM_ERROR("surface offset %d > BO size %zd\n", ++ surf->offset, obj->base.size); ++ return -EINVAL; ++ } ++ ++ if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE < ++ render_tiles_stride * args->max_y_tile + args->max_x_tile) { ++ DRM_ERROR("MSAA tile %d, %d out of bounds " ++ "(bo size %zd, offset %d).\n", ++ args->max_x_tile, args->max_y_tile, ++ obj->base.size, ++ surf->offset); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ if (surf->flags != 0 || surf->bits != 0) { ++ DRM_ERROR("MSAA surface had nonzero flags/bits\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (surf->offset & 0xf) { ++ DRM_ERROR("MSAA write must be 16b aligned.\n"); ++ return -EINVAL; ++ } ++ ++ return vc4_full_res_bounds_check(exec, *obj, surf); ++} ++ ++static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ uint8_t tiling = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_TILING); ++ uint8_t buffer = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER); ++ uint8_t format = VC4_GET_FIELD(surf->bits, ++ VC4_LOADSTORE_TILE_BUFFER_FORMAT); ++ int cpp; ++ int ret; ++ ++ if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ DRM_ERROR("Extra flags set\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { ++ if (surf == &exec->args->zs_write) { ++ DRM_ERROR("general zs write may not be a full-res.\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->bits != 0) { ++ DRM_ERROR("load/store general bits set with " ++ "full res load/store.\n"); ++ return -EINVAL; ++ } ++ ++ ret = vc4_full_res_bounds_check(exec, *obj, surf); ++ if (!ret) ++ return ret; ++ ++ return 0; ++ } ++ ++ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK | ++ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK | ++ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) { ++ DRM_ERROR("Unknown bits in load/store: 0x%04x\n", ++ surf->bits); ++ return -EINVAL; ++ } ++ ++ if (tiling > VC4_TILING_FORMAT_LT) { ++ DRM_ERROR("Bad tiling format\n"); ++ return -EINVAL; ++ } ++ ++ if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) { ++ if (format != 0) { ++ DRM_ERROR("No color format should be set for ZS\n"); ++ return -EINVAL; ++ } ++ cpp = 4; ++ } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) { ++ switch (format) { ++ case VC4_LOADSTORE_TILE_BUFFER_BGR565: ++ case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER: ++ cpp = 2; ++ break; ++ case VC4_LOADSTORE_TILE_BUFFER_RGBA8888: ++ cpp = 4; ++ break; ++ default: ++ DRM_ERROR("Bad tile buffer format\n"); ++ return -EINVAL; ++ } ++ } else { ++ DRM_ERROR("Bad load/store buffer %d.\n", buffer); ++ return -EINVAL; ++ } ++ ++ if (surf->offset & 0xf) { ++ DRM_ERROR("load/store buffer must be 16b aligned.\n"); ++ return -EINVAL; ++ } ++ ++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, ++ exec->args->width, exec->args->height, cpp)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec, ++ struct vc4_rcl_setup *setup, ++ struct drm_gem_cma_object **obj, ++ struct drm_vc4_submit_rcl_surface *surf) ++{ ++ uint8_t tiling = VC4_GET_FIELD(surf->bits, ++ VC4_RENDER_CONFIG_MEMORY_FORMAT); ++ uint8_t format = VC4_GET_FIELD(surf->bits, ++ VC4_RENDER_CONFIG_FORMAT); ++ int cpp; ++ ++ if (surf->flags != 0) { ++ DRM_ERROR("No flags supported on render config.\n"); ++ return -EINVAL; ++ } ++ ++ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK | ++ VC4_RENDER_CONFIG_FORMAT_MASK | ++ VC4_RENDER_CONFIG_MS_MODE_4X | ++ VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) { ++ DRM_ERROR("Unknown bits in render config: 0x%04x\n", ++ surf->bits); ++ return -EINVAL; ++ } ++ ++ if (surf->hindex == ~0) ++ return 0; ++ ++ *obj = vc4_use_bo(exec, surf->hindex); ++ if (!*obj) ++ return -EINVAL; ++ ++ if (tiling > VC4_TILING_FORMAT_LT) { ++ DRM_ERROR("Bad tiling format\n"); ++ return -EINVAL; ++ } ++ ++ switch (format) { ++ case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED: ++ case VC4_RENDER_CONFIG_FORMAT_BGR565: ++ cpp = 2; ++ break; ++ case VC4_RENDER_CONFIG_FORMAT_RGBA8888: ++ cpp = 4; ++ break; ++ default: ++ DRM_ERROR("Bad tile buffer format\n"); ++ return -EINVAL; ++ } ++ ++ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, ++ exec->args->width, exec->args->height, cpp)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) ++{ ++ struct vc4_rcl_setup setup = {0}; ++ struct drm_vc4_submit_cl *args = exec->args; ++ bool has_bin = args->bin_cl_size != 0; ++ int ret; ++ ++ if (args->min_x_tile > args->max_x_tile || ++ args->min_y_tile > args->max_y_tile) { ++ DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n", ++ args->min_x_tile, args->min_y_tile, ++ args->max_x_tile, args->max_y_tile); ++ return -EINVAL; ++ } ++ ++ if (has_bin && ++ (args->max_x_tile > exec->bin_tiles_x || ++ args->max_y_tile > exec->bin_tiles_y)) { ++ DRM_ERROR("Render tiles (%d,%d) outside of bin config " ++ "(%d,%d)\n", ++ args->max_x_tile, args->max_y_tile, ++ exec->bin_tiles_x, exec->bin_tiles_y); ++ return -EINVAL; ++ } ++ ++ ret = vc4_rcl_render_config_surface_setup(exec, &setup, ++ &setup.color_write, ++ &args->color_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write, ++ &args->msaa_color_write); ++ if (ret) ++ return ret; ++ ++ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write, ++ &args->msaa_zs_write); ++ if (ret) ++ return ret; ++ ++ /* We shouldn't even have the job submitted to us if there's no ++ * surface to write out. ++ */ ++ if (!setup.color_write && !setup.zs_write && ++ !setup.msaa_color_write && !setup.msaa_zs_write) { ++ DRM_ERROR("RCL requires color or Z/S write\n"); ++ return -EINVAL; ++ } ++ ++ return vc4_create_rcl_bo(dev, exec, &setup); ++} +diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h +new file mode 100644 +index 0000000..ad7b1ea +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_trace.h +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) ++#define _VC4_TRACE_H_ ++ ++#include ++#include ++#include ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM vc4 ++#define TRACE_INCLUDE_FILE vc4_trace ++ ++TRACE_EVENT(vc4_wait_for_seqno_begin, ++ TP_PROTO(struct drm_device *dev, uint64_t seqno, uint64_t timeout), ++ TP_ARGS(dev, seqno, timeout), ++ ++ TP_STRUCT__entry( ++ __field(u32, dev) ++ __field(u64, seqno) ++ __field(u64, timeout) ++ ), ++ ++ TP_fast_assign( ++ __entry->dev = dev->primary->index; ++ __entry->seqno = seqno; ++ __entry->timeout = timeout; ++ ), ++ ++ TP_printk("dev=%u, seqno=%llu, timeout=%llu", ++ __entry->dev, __entry->seqno, __entry->timeout) ++); ++ ++TRACE_EVENT(vc4_wait_for_seqno_end, ++ TP_PROTO(struct drm_device *dev, uint64_t seqno), ++ TP_ARGS(dev, seqno), ++ ++ TP_STRUCT__entry( ++ __field(u32, dev) ++ __field(u64, seqno) ++ ), ++ ++ TP_fast_assign( ++ __entry->dev = dev->primary->index; ++ __entry->seqno = seqno; ++ ), ++ ++ TP_printk("dev=%u, seqno=%llu", ++ __entry->dev, __entry->seqno) ++); ++ ++#endif /* _VC4_TRACE_H_ */ ++ ++/* This part must be outside protection */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#include +diff --git a/drivers/gpu/drm/vc4/vc4_trace_points.c b/drivers/gpu/drm/vc4/vc4_trace_points.c +new file mode 100644 +index 0000000..e6278f2 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_trace_points.c +@@ -0,0 +1,14 @@ ++/* ++ * Copyright (C) 2015 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. ++ */ ++ ++#include "vc4_drv.h" ++ ++#ifndef __CHECKER__ ++#define CREATE_TRACE_POINTS ++#include "vc4_trace.h" ++#endif +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +new file mode 100644 +index 0000000..4d103f7f +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -0,0 +1,270 @@ ++/* ++ * Copyright (c) 2014 The Linux Foundation. All rights reserved. ++ * Copyright (C) 2013 Red Hat ++ * Author: Rob Clark ++ * ++ * 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 . ++ */ ++ ++#include "linux/component.h" ++#include "soc/bcm2835/raspberrypi-firmware.h" ++#include "vc4_drv.h" ++#include "vc4_regs.h" ++ ++#ifdef CONFIG_DEBUG_FS ++#define REGDEF(reg) { reg, #reg } ++static const struct { ++ uint32_t reg; ++ const char *name; ++} vc4_reg_defs[] = { ++ REGDEF(V3D_IDENT0), ++ REGDEF(V3D_IDENT1), ++ REGDEF(V3D_IDENT2), ++ REGDEF(V3D_SCRATCH), ++ REGDEF(V3D_L2CACTL), ++ REGDEF(V3D_SLCACTL), ++ REGDEF(V3D_INTCTL), ++ REGDEF(V3D_INTENA), ++ REGDEF(V3D_INTDIS), ++ REGDEF(V3D_CT0CS), ++ REGDEF(V3D_CT1CS), ++ REGDEF(V3D_CT0EA), ++ REGDEF(V3D_CT1EA), ++ REGDEF(V3D_CT0CA), ++ REGDEF(V3D_CT1CA), ++ REGDEF(V3D_CT00RA0), ++ REGDEF(V3D_CT01RA0), ++ REGDEF(V3D_CT0LC), ++ REGDEF(V3D_CT1LC), ++ REGDEF(V3D_CT0PC), ++ REGDEF(V3D_CT1PC), ++ REGDEF(V3D_PCS), ++ REGDEF(V3D_BFC), ++ REGDEF(V3D_RFC), ++ REGDEF(V3D_BPCA), ++ REGDEF(V3D_BPCS), ++ REGDEF(V3D_BPOA), ++ REGDEF(V3D_BPOS), ++ REGDEF(V3D_BXCF), ++ REGDEF(V3D_SQRSV0), ++ REGDEF(V3D_SQRSV1), ++ REGDEF(V3D_SQCNTL), ++ REGDEF(V3D_SRQPC), ++ REGDEF(V3D_SRQUA), ++ REGDEF(V3D_SRQUL), ++ REGDEF(V3D_SRQCS), ++ REGDEF(V3D_VPACNTL), ++ REGDEF(V3D_VPMBASE), ++ REGDEF(V3D_PCTRC), ++ REGDEF(V3D_PCTRE), ++ REGDEF(V3D_PCTR0), ++ REGDEF(V3D_PCTRS0), ++ REGDEF(V3D_PCTR1), ++ REGDEF(V3D_PCTRS1), ++ REGDEF(V3D_PCTR2), ++ REGDEF(V3D_PCTRS2), ++ REGDEF(V3D_PCTR3), ++ REGDEF(V3D_PCTRS3), ++ REGDEF(V3D_PCTR4), ++ REGDEF(V3D_PCTRS4), ++ REGDEF(V3D_PCTR5), ++ REGDEF(V3D_PCTRS5), ++ REGDEF(V3D_PCTR6), ++ REGDEF(V3D_PCTRS6), ++ REGDEF(V3D_PCTR7), ++ REGDEF(V3D_PCTRS7), ++ REGDEF(V3D_PCTR8), ++ REGDEF(V3D_PCTRS8), ++ REGDEF(V3D_PCTR9), ++ REGDEF(V3D_PCTRS9), ++ REGDEF(V3D_PCTR10), ++ REGDEF(V3D_PCTRS10), ++ REGDEF(V3D_PCTR11), ++ REGDEF(V3D_PCTRS11), ++ REGDEF(V3D_PCTR12), ++ REGDEF(V3D_PCTRS12), ++ REGDEF(V3D_PCTR13), ++ REGDEF(V3D_PCTRS13), ++ REGDEF(V3D_PCTR14), ++ REGDEF(V3D_PCTRS14), ++ REGDEF(V3D_PCTR15), ++ REGDEF(V3D_PCTRS15), ++ REGDEF(V3D_DBGE), ++ REGDEF(V3D_FDBGO), ++ REGDEF(V3D_FDBGB), ++ REGDEF(V3D_FDBGR), ++ REGDEF(V3D_FDBGS), ++ REGDEF(V3D_ERRSTAT), ++}; ++ ++int vc4_v3d_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); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ vc4_reg_defs[i].name, vc4_reg_defs[i].reg, ++ V3D_READ(vc4_reg_defs[i].reg)); ++ } ++ ++ return 0; ++} ++ ++int vc4_v3d_debugfs_ident(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); ++ uint32_t ident1 = V3D_READ(V3D_IDENT1); ++ uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC); ++ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS); ++ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS); ++ ++ seq_printf(m, "Revision: %d\n", ++ VC4_GET_FIELD(ident1, V3D_IDENT1_REV)); ++ seq_printf(m, "Slices: %d\n", nslc); ++ seq_printf(m, "TMUs: %d\n", nslc * tups); ++ seq_printf(m, "QPUs: %d\n", nslc * qups); ++ seq_printf(m, "Semaphores: %d\n", ++ VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM)); ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++/* ++ * Asks the firmware to turn on power to the V3D engine. ++ * ++ * This may be doable with just the clocks interface, though this ++ * packet does some other register setup from the firmware, too. ++ */ ++int ++vc4_v3d_set_power(struct vc4_dev *vc4, bool on) ++{ ++ u32 packet = on; ++ ++ return rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_SET_ENABLE_QPU, ++ &packet, sizeof(packet)); ++} ++ ++static void vc4_v3d_init_hw(struct drm_device *dev) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ /* Take all the memory that would have been reserved for user ++ * QPU programs, since we don't have an interface for running ++ * them, anyway. ++ */ ++ V3D_WRITE(V3D_VPMBASE, 0); ++} ++ ++static int vc4_v3d_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_v3d *v3d = NULL; ++ int ret; ++ ++ v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); ++ if (!v3d) ++ return -ENOMEM; ++ ++ v3d->pdev = pdev; ++ ++ v3d->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(v3d->regs)) ++ return PTR_ERR(v3d->regs); ++ ++ vc4->v3d = v3d; ++ ++ ret = vc4_v3d_set_power(vc4, true); ++ if (ret) ++ return ret; ++ ++ if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { ++ DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", ++ V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); ++ return -EINVAL; ++ } ++ ++ /* Reset the binner overflow address/size at setup, to be sure ++ * we don't reuse an old one. ++ */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ vc4_v3d_init_hw(drm); ++ ++ ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); ++ if (ret) { ++ DRM_ERROR("Failed to install IRQ handler\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void vc4_v3d_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); ++ ++ drm_irq_uninstall(drm); ++ ++ /* Disable the binner's overflow memory address, so the next ++ * driver probe (if any) doesn't try to reuse our old ++ * allocation. ++ */ ++ V3D_WRITE(V3D_BPOA, 0); ++ V3D_WRITE(V3D_BPOS, 0); ++ ++ vc4_v3d_set_power(vc4, false); ++ ++ vc4->v3d = NULL; ++} ++ ++static const struct component_ops vc4_v3d_ops = { ++ .bind = vc4_v3d_bind, ++ .unbind = vc4_v3d_unbind, ++}; ++ ++static int vc4_v3d_dev_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &vc4_v3d_ops); ++} ++ ++static int vc4_v3d_dev_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &vc4_v3d_ops); ++ return 0; ++} ++ ++static const struct of_device_id vc4_v3d_dt_match[] = { ++ { .compatible = "brcm,vc4-v3d" }, ++ {} ++}; ++ ++struct platform_driver vc4_v3d_driver = { ++ .probe = vc4_v3d_dev_probe, ++ .remove = vc4_v3d_dev_remove, ++ .driver = { ++ .name = "vc4_v3d", ++ .of_match_table = vc4_v3d_dt_match, ++ }, ++}; +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +new file mode 100644 +index 0000000..0fb5b99 +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -0,0 +1,900 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++/** ++ * Command list validator for VC4. ++ * ++ * The VC4 has no IOMMU between it and system memory. So, a user with ++ * access to execute command lists could escalate privilege by ++ * overwriting system memory (drawing to it as a framebuffer) or ++ * reading system memory it shouldn't (reading it as a texture, or ++ * uniform data, or vertex data). ++ * ++ * This validates command lists to ensure that all accesses are within ++ * the bounds of the GEM objects referenced. It explicitly whitelists ++ * packets, and looks at the offsets in any address fields to make ++ * sure they're constrained within the BOs they reference. ++ * ++ * Note that because of the validation that's happening anyway, this ++ * is where GEM relocation processing happens. ++ */ ++ ++#include "uapi/drm/vc4_drm.h" ++#include "vc4_drv.h" ++#include "vc4_packet.h" ++ ++#define VALIDATE_ARGS \ ++ struct vc4_exec_info *exec, \ ++ void *validated, \ ++ void *untrusted ++ ++/** Return the width in pixels of a 64-byte microtile. */ ++static uint32_t ++utile_width(int cpp) ++{ ++ switch (cpp) { ++ case 1: ++ case 2: ++ return 8; ++ case 4: ++ return 4; ++ case 8: ++ return 2; ++ default: ++ DRM_ERROR("unknown cpp: %d\n", cpp); ++ return 1; ++ } ++} ++ ++/** Return the height in pixels of a 64-byte microtile. */ ++static uint32_t ++utile_height(int cpp) ++{ ++ switch (cpp) { ++ case 1: ++ return 8; ++ case 2: ++ case 4: ++ case 8: ++ return 4; ++ default: ++ DRM_ERROR("unknown cpp: %d\n", cpp); ++ return 1; ++ } ++} ++ ++/** ++ * The texture unit decides what tiling format a particular miplevel is using ++ * this function, so we lay out our miptrees accordingly. ++ */ ++static bool ++size_is_lt(uint32_t width, uint32_t height, int cpp) ++{ ++ return (width <= 4 * utile_width(cpp) || ++ height <= 4 * utile_height(cpp)); ++} ++ ++struct drm_gem_cma_object * ++vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) ++{ ++ struct drm_gem_cma_object *obj; ++ struct vc4_bo *bo; ++ ++ if (hindex >= exec->bo_count) { ++ DRM_ERROR("BO index %d greater than BO count %d\n", ++ hindex, exec->bo_count); ++ return NULL; ++ } ++ obj = exec->bo[hindex]; ++ bo = to_vc4_bo(&obj->base); ++ ++ if (bo->validated_shader) { ++ DRM_ERROR("Trying to use shader BO as something other than " ++ "a shader\n"); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++static struct drm_gem_cma_object * ++vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index) ++{ ++ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]); ++} ++ ++static bool ++validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos) ++{ ++ /* Note that the untrusted pointer passed to these functions is ++ * incremented past the packet byte. ++ */ ++ return (untrusted - 1 == exec->bin_u + pos); ++} ++ ++static uint32_t ++gl_shader_rec_size(uint32_t pointer_bits) ++{ ++ uint32_t attribute_count = pointer_bits & 7; ++ bool extended = pointer_bits & 8; ++ ++ if (attribute_count == 0) ++ attribute_count = 8; ++ ++ if (extended) ++ return 100 + attribute_count * 4; ++ else ++ return 36 + attribute_count * 8; ++} ++ ++bool ++vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo, ++ uint32_t offset, uint8_t tiling_format, ++ uint32_t width, uint32_t height, uint8_t cpp) ++{ ++ uint32_t aligned_width, aligned_height, stride, size; ++ uint32_t utile_w = utile_width(cpp); ++ uint32_t utile_h = utile_height(cpp); ++ ++ /* The shaded vertex format stores signed 12.4 fixed point ++ * (-2048,2047) offsets from the viewport center, so we should ++ * never have a render target larger than 4096. The texture ++ * unit can only sample from 2048x2048, so it's even more ++ * restricted. This lets us avoid worrying about overflow in ++ * our math. ++ */ ++ if (width > 4096 || height > 4096) { ++ DRM_ERROR("Surface dimesions (%d,%d) too large", width, height); ++ return false; ++ } ++ ++ switch (tiling_format) { ++ case VC4_TILING_FORMAT_LINEAR: ++ aligned_width = round_up(width, utile_w); ++ aligned_height = height; ++ break; ++ case VC4_TILING_FORMAT_T: ++ aligned_width = round_up(width, utile_w * 8); ++ aligned_height = round_up(height, utile_h * 8); ++ break; ++ case VC4_TILING_FORMAT_LT: ++ aligned_width = round_up(width, utile_w); ++ aligned_height = round_up(height, utile_h); ++ break; ++ default: ++ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format); ++ return false; ++ } ++ ++ stride = aligned_width * cpp; ++ size = stride * aligned_height; ++ ++ if (size + offset < size || ++ size + offset > fbo->base.size) { ++ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n", ++ width, height, ++ aligned_width, aligned_height, ++ size, offset, fbo->base.size); ++ return false; ++ } ++ ++ return true; ++} ++ ++static int ++validate_flush(VALIDATE_ARGS) ++{ ++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) { ++ DRM_ERROR("Bin CL must end with VC4_PACKET_FLUSH\n"); ++ return -EINVAL; ++ } ++ exec->found_flush = true; ++ ++ return 0; ++} ++ ++static int ++validate_start_tile_binning(VALIDATE_ARGS) ++{ ++ if (exec->found_start_tile_binning_packet) { ++ DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n"); ++ return -EINVAL; ++ } ++ exec->found_start_tile_binning_packet = true; ++ ++ if (!exec->found_tile_binning_mode_config_packet) { ++ DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++validate_increment_semaphore(VALIDATE_ARGS) ++{ ++ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) { ++ DRM_ERROR("Bin CL must end with " ++ "VC4_PACKET_INCREMENT_SEMAPHORE\n"); ++ return -EINVAL; ++ } ++ exec->found_increment_semaphore_packet = true; ++ ++ return 0; ++} ++ ++static int ++validate_indexed_prim_list(VALIDATE_ARGS) ++{ ++ struct drm_gem_cma_object *ib; ++ uint32_t length = *(uint32_t *)(untrusted + 1); ++ uint32_t offset = *(uint32_t *)(untrusted + 5); ++ uint32_t max_index = *(uint32_t *)(untrusted + 9); ++ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1; ++ struct vc4_shader_state *shader_state; ++ ++ /* Check overflow condition */ ++ if (exec->shader_state_count == 0) { ++ DRM_ERROR("shader state must precede primitives\n"); ++ return -EINVAL; ++ } ++ shader_state = &exec->shader_state[exec->shader_state_count - 1]; ++ ++ if (max_index > shader_state->max_index) ++ shader_state->max_index = max_index; ++ ++ ib = vc4_use_handle(exec, 0); ++ if (!ib) ++ return -EINVAL; ++ ++ if (offset > ib->base.size || ++ (ib->base.size - offset) / index_size < length) { ++ DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n", ++ offset, length, index_size, ib->base.size); ++ return -EINVAL; ++ } ++ ++ *(uint32_t *)(validated + 5) = ib->paddr + offset; ++ ++ return 0; ++} ++ ++static int ++validate_gl_array_primitive(VALIDATE_ARGS) ++{ ++ uint32_t length = *(uint32_t *)(untrusted + 1); ++ uint32_t base_index = *(uint32_t *)(untrusted + 5); ++ uint32_t max_index; ++ struct vc4_shader_state *shader_state; ++ ++ /* Check overflow condition */ ++ if (exec->shader_state_count == 0) { ++ DRM_ERROR("shader state must precede primitives\n"); ++ return -EINVAL; ++ } ++ shader_state = &exec->shader_state[exec->shader_state_count - 1]; ++ ++ if (length + base_index < length) { ++ DRM_ERROR("primitive vertex count overflow\n"); ++ return -EINVAL; ++ } ++ max_index = length + base_index - 1; ++ ++ if (max_index > shader_state->max_index) ++ shader_state->max_index = max_index; ++ ++ return 0; ++} ++ ++static int ++validate_gl_shader_state(VALIDATE_ARGS) ++{ ++ uint32_t i = exec->shader_state_count++; ++ ++ if (i >= exec->shader_state_size) { ++ DRM_ERROR("More requests for shader states than declared\n"); ++ return -EINVAL; ++ } ++ ++ exec->shader_state[i].addr = *(uint32_t *)untrusted; ++ exec->shader_state[i].max_index = 0; ++ ++ if (exec->shader_state[i].addr & ~0xf) { ++ DRM_ERROR("high bits set in GL shader rec reference\n"); ++ return -EINVAL; ++ } ++ ++ *(uint32_t *)validated = (exec->shader_rec_p + ++ exec->shader_state[i].addr); ++ ++ exec->shader_rec_p += ++ roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16); ++ ++ return 0; ++} ++ ++static int ++validate_tile_binning_config(VALIDATE_ARGS) ++{ ++ struct drm_device *dev = exec->exec_bo->base.dev; ++ struct vc4_bo *tile_bo; ++ uint8_t flags; ++ uint32_t tile_state_size, tile_alloc_size; ++ uint32_t tile_count; ++ ++ if (exec->found_tile_binning_mode_config_packet) { ++ DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); ++ return -EINVAL; ++ } ++ exec->found_tile_binning_mode_config_packet = true; ++ ++ exec->bin_tiles_x = *(uint8_t *)(untrusted + 12); ++ exec->bin_tiles_y = *(uint8_t *)(untrusted + 13); ++ tile_count = exec->bin_tiles_x * exec->bin_tiles_y; ++ flags = *(uint8_t *)(untrusted + 14); ++ ++ if (exec->bin_tiles_x == 0 || ++ exec->bin_tiles_y == 0) { ++ DRM_ERROR("Tile binning config of %dx%d too small\n", ++ exec->bin_tiles_x, exec->bin_tiles_y); ++ return -EINVAL; ++ } ++ ++ if (flags & (VC4_BIN_CONFIG_DB_NON_MS | ++ VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) { ++ DRM_ERROR("unsupported binning config flags 0x%02x\n", flags); ++ return -EINVAL; ++ } ++ ++ /* The tile state data array is 48 bytes per tile, and we put it at ++ * the start of a BO containing both it and the tile alloc. ++ */ ++ tile_state_size = 48 * tile_count; ++ ++ /* Since the tile alloc array will follow us, align. */ ++ exec->tile_alloc_offset = roundup(tile_state_size, 4096); ++ ++ *(uint8_t *)(validated + 14) = ++ ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | ++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) | ++ VC4_BIN_CONFIG_AUTO_INIT_TSDA | ++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32, ++ VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) | ++ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, ++ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); ++ ++ /* Initial block size. */ ++ tile_alloc_size = 32 * tile_count; ++ ++ /* ++ * The initial allocation gets rounded to the next 256 bytes before ++ * the hardware starts fulfilling further allocations. ++ */ ++ tile_alloc_size = roundup(tile_alloc_size, 256); ++ ++ /* Add space for the extra allocations. This is what gets used first, ++ * before overflow memory. It must have at least 4096 bytes, but we ++ * want to avoid overflow memory usage if possible. ++ */ ++ tile_alloc_size += 1024 * 1024; ++ ++ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, ++ true); ++ exec->tile_bo = &tile_bo->base; ++ if (!exec->tile_bo) ++ return -ENOMEM; ++ list_add_tail(&tile_bo->unref_head, &exec->unref_list); ++ ++ /* tile alloc address. */ ++ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr + ++ exec->tile_alloc_offset); ++ /* tile alloc size. */ ++ *(uint32_t *)(validated + 4) = tile_alloc_size; ++ /* tile state address. */ ++ *(uint32_t *)(validated + 8) = exec->tile_bo->paddr; ++ ++ return 0; ++} ++ ++static int ++validate_gem_handles(VALIDATE_ARGS) ++{ ++ memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index)); ++ return 0; ++} ++ ++#define VC4_DEFINE_PACKET(packet, func) \ ++ [packet] = { packet ## _SIZE, #packet, func } ++ ++static const struct cmd_info { ++ uint16_t len; ++ const char *name; ++ int (*func)(struct vc4_exec_info *exec, void *validated, ++ void *untrusted); ++} cmd_info[] = { ++ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, ++ validate_start_tile_binning), ++ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, ++ validate_increment_semaphore), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, ++ validate_indexed_prim_list), ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, ++ validate_gl_array_primitive), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL), ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL), ++ /* Note: The docs say this was also 105, but it was 106 in the ++ * initial userland code drop. ++ */ ++ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, ++ validate_tile_binning_config), ++ ++ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles), ++}; ++ ++int ++vc4_validate_bin_cl(struct drm_device *dev, ++ void *validated, ++ void *unvalidated, ++ struct vc4_exec_info *exec) ++{ ++ uint32_t len = exec->args->bin_cl_size; ++ uint32_t dst_offset = 0; ++ uint32_t src_offset = 0; ++ ++ while (src_offset < len) { ++ void *dst_pkt = validated + dst_offset; ++ void *src_pkt = unvalidated + src_offset; ++ u8 cmd = *(uint8_t *)src_pkt; ++ const struct cmd_info *info; ++ ++ if (cmd >= ARRAY_SIZE(cmd_info)) { ++ DRM_ERROR("0x%08x: packet %d out of bounds\n", ++ src_offset, cmd); ++ return -EINVAL; ++ } ++ ++ info = &cmd_info[cmd]; ++ if (!info->name) { ++ DRM_ERROR("0x%08x: packet %d invalid\n", ++ src_offset, cmd); ++ return -EINVAL; ++ } ++ ++ if (src_offset + info->len > len) { ++ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x " ++ "exceeds bounds (0x%08x)\n", ++ src_offset, cmd, info->name, info->len, ++ src_offset + len); ++ return -EINVAL; ++ } ++ ++ if (cmd != VC4_PACKET_GEM_HANDLES) ++ memcpy(dst_pkt, src_pkt, info->len); ++ ++ if (info->func && info->func(exec, ++ dst_pkt + 1, ++ src_pkt + 1)) { ++ DRM_ERROR("0x%08x: packet %d (%s) failed to validate\n", ++ src_offset, cmd, info->name); ++ return -EINVAL; ++ } ++ ++ src_offset += info->len; ++ /* GEM handle loading doesn't produce HW packets. */ ++ if (cmd != VC4_PACKET_GEM_HANDLES) ++ dst_offset += info->len; ++ ++ /* When the CL hits halt, it'll stop reading anything else. */ ++ if (cmd == VC4_PACKET_HALT) ++ break; ++ } ++ ++ exec->ct0ea = exec->ct0ca + dst_offset; ++ ++ if (!exec->found_start_tile_binning_packet) { ++ DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n"); ++ return -EINVAL; ++ } ++ ++ /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The ++ * semaphore is used to trigger the render CL to start up, and the ++ * FLUSH is what caps the bin lists with ++ * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main ++ * render CL when they get called to) and actually triggers the queued ++ * semaphore increment. ++ */ ++ if (!exec->found_increment_semaphore_packet || !exec->found_flush) { ++ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + " ++ "VC4_PACKET_FLUSH\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static bool ++reloc_tex(struct vc4_exec_info *exec, ++ void *uniform_data_u, ++ struct vc4_texture_sample_info *sample, ++ uint32_t texture_handle_index) ++ ++{ ++ struct drm_gem_cma_object *tex; ++ uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); ++ uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]); ++ uint32_t p2 = (sample->p_offset[2] != ~0 ? ++ *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0); ++ uint32_t p3 = (sample->p_offset[3] != ~0 ? ++ *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0); ++ uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0]; ++ uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK; ++ uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS); ++ uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH); ++ uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT); ++ uint32_t cpp, tiling_format, utile_w, utile_h; ++ uint32_t i; ++ uint32_t cube_map_stride = 0; ++ enum vc4_texture_data_type type; ++ ++ tex = vc4_use_bo(exec, texture_handle_index); ++ if (!tex) ++ return false; ++ ++ if (sample->is_direct) { ++ uint32_t remaining_size = tex->base.size - p0; ++ ++ if (p0 > tex->base.size - 4) { ++ DRM_ERROR("UBO offset greater than UBO size\n"); ++ goto fail; ++ } ++ if (p1 > remaining_size - 4) { ++ DRM_ERROR("UBO clamp would allow reads " ++ "outside of UBO\n"); ++ goto fail; ++ } ++ *validated_p0 = tex->paddr + p0; ++ return true; ++ } ++ ++ if (width == 0) ++ width = 2048; ++ if (height == 0) ++ height = 2048; ++ ++ if (p0 & VC4_TEX_P0_CMMODE_MASK) { ++ if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) == ++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) ++ cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK; ++ if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) == ++ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) { ++ if (cube_map_stride) { ++ DRM_ERROR("Cube map stride set twice\n"); ++ goto fail; ++ } ++ ++ cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK; ++ } ++ if (!cube_map_stride) { ++ DRM_ERROR("Cube map stride not set\n"); ++ goto fail; ++ } ++ } ++ ++ type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) | ++ (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4)); ++ ++ switch (type) { ++ case VC4_TEXTURE_TYPE_RGBA8888: ++ case VC4_TEXTURE_TYPE_RGBX8888: ++ case VC4_TEXTURE_TYPE_RGBA32R: ++ cpp = 4; ++ break; ++ case VC4_TEXTURE_TYPE_RGBA4444: ++ case VC4_TEXTURE_TYPE_RGBA5551: ++ case VC4_TEXTURE_TYPE_RGB565: ++ case VC4_TEXTURE_TYPE_LUMALPHA: ++ case VC4_TEXTURE_TYPE_S16F: ++ case VC4_TEXTURE_TYPE_S16: ++ cpp = 2; ++ break; ++ case VC4_TEXTURE_TYPE_LUMINANCE: ++ case VC4_TEXTURE_TYPE_ALPHA: ++ case VC4_TEXTURE_TYPE_S8: ++ cpp = 1; ++ break; ++ case VC4_TEXTURE_TYPE_ETC1: ++ case VC4_TEXTURE_TYPE_BW1: ++ case VC4_TEXTURE_TYPE_A4: ++ case VC4_TEXTURE_TYPE_A1: ++ case VC4_TEXTURE_TYPE_RGBA64: ++ case VC4_TEXTURE_TYPE_YUV422R: ++ default: ++ DRM_ERROR("Texture format %d unsupported\n", type); ++ goto fail; ++ } ++ utile_w = utile_width(cpp); ++ utile_h = utile_height(cpp); ++ ++ if (type == VC4_TEXTURE_TYPE_RGBA32R) { ++ tiling_format = VC4_TILING_FORMAT_LINEAR; ++ } else { ++ if (size_is_lt(width, height, cpp)) ++ tiling_format = VC4_TILING_FORMAT_LT; ++ else ++ tiling_format = VC4_TILING_FORMAT_T; ++ } ++ ++ if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5, ++ tiling_format, width, height, cpp)) { ++ goto fail; ++ } ++ ++ /* The mipmap levels are stored before the base of the texture. Make ++ * sure there is actually space in the BO. ++ */ ++ for (i = 1; i <= miplevels; i++) { ++ uint32_t level_width = max(width >> i, 1u); ++ uint32_t level_height = max(height >> i, 1u); ++ uint32_t aligned_width, aligned_height; ++ uint32_t level_size; ++ ++ /* Once the levels get small enough, they drop from T to LT. */ ++ if (tiling_format == VC4_TILING_FORMAT_T && ++ size_is_lt(level_width, level_height, cpp)) { ++ tiling_format = VC4_TILING_FORMAT_LT; ++ } ++ ++ switch (tiling_format) { ++ case VC4_TILING_FORMAT_T: ++ aligned_width = round_up(level_width, utile_w * 8); ++ aligned_height = round_up(level_height, utile_h * 8); ++ break; ++ case VC4_TILING_FORMAT_LT: ++ aligned_width = round_up(level_width, utile_w); ++ aligned_height = round_up(level_height, utile_h); ++ break; ++ default: ++ aligned_width = round_up(level_width, utile_w); ++ aligned_height = level_height; ++ break; ++ } ++ ++ level_size = aligned_width * cpp * aligned_height; ++ ++ if (offset < level_size) { ++ DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db " ++ "overflowed buffer bounds (offset %d)\n", ++ i, level_width, level_height, ++ aligned_width, aligned_height, ++ level_size, offset); ++ goto fail; ++ } ++ ++ offset -= level_size; ++ } ++ ++ *validated_p0 = tex->paddr + p0; ++ ++ return true; ++ fail: ++ DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0); ++ DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1); ++ DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2); ++ DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3); ++ return false; ++} ++ ++static int ++validate_gl_shader_rec(struct drm_device *dev, ++ struct vc4_exec_info *exec, ++ struct vc4_shader_state *state) ++{ ++ uint32_t *src_handles; ++ void *pkt_u, *pkt_v; ++ static const uint32_t shader_reloc_offsets[] = { ++ 4, /* fs */ ++ 16, /* vs */ ++ 28, /* cs */ ++ }; ++ uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); ++ struct drm_gem_cma_object *bo[shader_reloc_count + 8]; ++ uint32_t nr_attributes, nr_relocs, packet_size; ++ int i; ++ ++ nr_attributes = state->addr & 0x7; ++ if (nr_attributes == 0) ++ nr_attributes = 8; ++ packet_size = gl_shader_rec_size(state->addr); ++ ++ nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes; ++ if (nr_relocs * 4 > exec->shader_rec_size) { ++ DRM_ERROR("overflowed shader recs reading %d handles " ++ "from %d bytes left\n", ++ nr_relocs, exec->shader_rec_size); ++ return -EINVAL; ++ } ++ src_handles = exec->shader_rec_u; ++ exec->shader_rec_u += nr_relocs * 4; ++ exec->shader_rec_size -= nr_relocs * 4; ++ ++ if (packet_size > exec->shader_rec_size) { ++ DRM_ERROR("overflowed shader recs copying %db packet " ++ "from %d bytes left\n", ++ packet_size, exec->shader_rec_size); ++ return -EINVAL; ++ } ++ pkt_u = exec->shader_rec_u; ++ pkt_v = exec->shader_rec_v; ++ memcpy(pkt_v, pkt_u, packet_size); ++ exec->shader_rec_u += packet_size; ++ /* Shader recs have to be aligned to 16 bytes (due to the attribute ++ * flags being in the low bytes), so round the next validated shader ++ * rec address up. This should be safe, since we've got so many ++ * relocations in a shader rec packet. ++ */ ++ BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4); ++ 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]); ++ return -EINVAL; ++ } ++ ++ bo[i] = exec->bo[src_handles[i]]; ++ if (!bo[i]) ++ return -EINVAL; ++ } ++ for (i = shader_reloc_count; i < nr_relocs; i++) { ++ bo[i] = vc4_use_bo(exec, src_handles[i]); ++ if (!bo[i]) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < shader_reloc_count; i++) { ++ struct vc4_validated_shader_info *validated_shader; ++ uint32_t o = shader_reloc_offsets[i]; ++ uint32_t src_offset = *(uint32_t *)(pkt_u + o); ++ uint32_t *texture_handles_u; ++ void *uniform_data_u; ++ uint32_t tex; ++ ++ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset; ++ ++ if (src_offset != 0) { ++ DRM_ERROR("Shaders must be at offset 0 of " ++ "the BO.\n"); ++ return -EINVAL; ++ } ++ ++ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader; ++ if (!validated_shader) ++ return -EINVAL; ++ ++ if (validated_shader->uniforms_src_size > ++ exec->uniforms_size) { ++ DRM_ERROR("Uniforms src buffer overflow\n"); ++ return -EINVAL; ++ } ++ ++ texture_handles_u = exec->uniforms_u; ++ uniform_data_u = (texture_handles_u + ++ validated_shader->num_texture_samples); ++ ++ memcpy(exec->uniforms_v, uniform_data_u, ++ validated_shader->uniforms_size); ++ ++ for (tex = 0; ++ tex < validated_shader->num_texture_samples; ++ tex++) { ++ if (!reloc_tex(exec, ++ uniform_data_u, ++ &validated_shader->texture_samples[tex], ++ texture_handles_u[tex])) { ++ return -EINVAL; ++ } ++ } ++ ++ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p; ++ ++ exec->uniforms_u += validated_shader->uniforms_src_size; ++ exec->uniforms_v += validated_shader->uniforms_size; ++ exec->uniforms_p += validated_shader->uniforms_size; ++ } ++ ++ for (i = 0; i < nr_attributes; i++) { ++ struct drm_gem_cma_object *vbo = ++ bo[ARRAY_SIZE(shader_reloc_offsets) + i]; ++ uint32_t o = 36 + i * 8; ++ uint32_t offset = *(uint32_t *)(pkt_u + o + 0); ++ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1; ++ uint32_t stride = *(uint8_t *)(pkt_u + o + 5); ++ uint32_t max_index; ++ ++ if (state->addr & 0x8) ++ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; ++ ++ if (vbo->base.size < offset || ++ vbo->base.size - offset < attr_size) { ++ DRM_ERROR("BO offset overflow (%d + %d > %d)\n", ++ offset, attr_size, vbo->base.size); ++ return -EINVAL; ++ } ++ ++ if (stride != 0) { ++ max_index = ((vbo->base.size - offset - attr_size) / ++ stride); ++ if (state->max_index > max_index) { ++ DRM_ERROR("primitives use index %d out of " ++ "supplied %d\n", ++ state->max_index, max_index); ++ return -EINVAL; ++ } ++ } ++ ++ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset; ++ } ++ ++ return 0; ++} ++ ++int ++vc4_validate_shader_recs(struct drm_device *dev, ++ struct vc4_exec_info *exec) ++{ ++ uint32_t i; ++ int ret = 0; ++ ++ for (i = 0; i < exec->shader_state_count; i++) { ++ ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} +diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +new file mode 100644 +index 0000000..f67124b +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -0,0 +1,513 @@ ++/* ++ * Copyright © 2014 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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: Shader validator for VC4. ++ * ++ * The VC4 has no IOMMU between it and system memory, so a user with ++ * access to execute shaders could escalate privilege by overwriting ++ * system memory (using the VPM write address register in the ++ * general-purpose DMA mode) or reading system memory it shouldn't ++ * (reading it as a texture, or uniform data, or vertex data). ++ * ++ * This walks over a shader BO, ensuring that its accesses are ++ * appropriately bounded, and recording how many texture accesses are ++ * made and where so that we can do relocations for them in the ++ * uniform stream. ++ */ ++ ++#include "vc4_drv.h" ++#include "vc4_qpu_defines.h" ++ ++struct vc4_shader_validation_state { ++ struct vc4_texture_sample_info tmu_setup[2]; ++ int tmu_write_count[2]; ++ ++ /* For registers that were last written to by a MIN instruction with ++ * one argument being a uniform, the address of the uniform. ++ * Otherwise, ~0. ++ * ++ * This is used for the validation of direct address memory reads. ++ */ ++ uint32_t live_min_clamp_offsets[32 + 32 + 4]; ++ bool live_max_clamp_regs[32 + 32 + 4]; ++}; ++ ++static uint32_t ++waddr_to_live_reg_index(uint32_t waddr, bool is_b) ++{ ++ if (waddr < 32) { ++ if (is_b) ++ return 32 + waddr; ++ else ++ return waddr; ++ } else if (waddr <= QPU_W_ACC3) { ++ return 64 + waddr - QPU_W_ACC0; ++ } else { ++ return ~0; ++ } ++} ++ ++static uint32_t ++raddr_add_a_to_live_reg_index(uint64_t inst) ++{ ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ ++ if (add_a == QPU_MUX_A) ++ return raddr_a; ++ else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM) ++ return 32 + raddr_b; ++ else if (add_a <= QPU_MUX_R3) ++ return 64 + add_a; ++ else ++ return ~0; ++} ++ ++static bool ++is_tmu_submit(uint32_t waddr) ++{ ++ return (waddr == QPU_W_TMU0_S || ++ waddr == QPU_W_TMU1_S); ++} ++ ++static bool ++is_tmu_write(uint32_t waddr) ++{ ++ return (waddr >= QPU_W_TMU0_S && ++ waddr <= QPU_W_TMU1_B); ++} ++ ++static bool ++record_texture_sample(struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ int tmu) ++{ ++ uint32_t s = validated_shader->num_texture_samples; ++ int i; ++ struct vc4_texture_sample_info *temp_samples; ++ ++ temp_samples = krealloc(validated_shader->texture_samples, ++ (s + 1) * sizeof(*temp_samples), ++ GFP_KERNEL); ++ if (!temp_samples) ++ return false; ++ ++ memcpy(&temp_samples[s], ++ &validation_state->tmu_setup[tmu], ++ sizeof(*temp_samples)); ++ ++ validated_shader->num_texture_samples = s + 1; ++ validated_shader->texture_samples = temp_samples; ++ ++ for (i = 0; i < 4; i++) ++ validation_state->tmu_setup[tmu].p_offset[i] = ~0; ++ ++ return true; ++} ++ ++static bool ++check_tmu_write(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ bool is_mul) ++{ ++ uint32_t waddr = (is_mul ? ++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) : ++ QPU_GET_FIELD(inst, QPU_WADDR_ADD)); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ int tmu = waddr > QPU_W_TMU0_B; ++ bool submit = is_tmu_submit(waddr); ++ bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0; ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ if (is_direct) { ++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B); ++ uint32_t clamp_reg, clamp_offset; ++ ++ if (sig == QPU_SIG_SMALL_IMM) { ++ DRM_ERROR("direct TMU read used small immediate\n"); ++ return false; ++ } ++ ++ /* Make sure that this texture load is an add of the base ++ * address of the UBO to a clamped offset within the UBO. ++ */ ++ if (is_mul || ++ QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) { ++ DRM_ERROR("direct TMU load wasn't an add\n"); ++ return false; ++ } ++ ++ /* We assert that the the clamped address is the first ++ * argument, and the UBO base address is the second argument. ++ * This is arbitrary, but simpler than supporting flipping the ++ * two either way. ++ */ ++ clamp_reg = raddr_add_a_to_live_reg_index(inst); ++ if (clamp_reg == ~0) { ++ DRM_ERROR("direct TMU load wasn't clamped\n"); ++ return false; ++ } ++ ++ clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg]; ++ if (clamp_offset == ~0) { ++ DRM_ERROR("direct TMU load wasn't clamped\n"); ++ return false; ++ } ++ ++ /* Store the clamp value's offset in p1 (see reloc_tex() in ++ * vc4_validate.c). ++ */ ++ validation_state->tmu_setup[tmu].p_offset[1] = ++ clamp_offset; ++ ++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) && ++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) { ++ DRM_ERROR("direct TMU load didn't add to a uniform\n"); ++ return false; ++ } ++ ++ validation_state->tmu_setup[tmu].is_direct = true; ++ } else { ++ if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM && ++ raddr_b == QPU_R_UNIF)) { ++ DRM_ERROR("uniform read in the same instruction as " ++ "texture setup.\n"); ++ return false; ++ } ++ } ++ ++ if (validation_state->tmu_write_count[tmu] >= 4) { ++ DRM_ERROR("TMU%d got too many parameters before dispatch\n", ++ tmu); ++ return false; ++ } ++ validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] = ++ validated_shader->uniforms_size; ++ validation_state->tmu_write_count[tmu]++; ++ /* Since direct uses a RADDR uniform reference, it will get counted in ++ * check_instruction_reads() ++ */ ++ if (!is_direct) ++ validated_shader->uniforms_size += 4; ++ ++ if (submit) { ++ if (!record_texture_sample(validated_shader, ++ validation_state, tmu)) { ++ return false; ++ } ++ ++ validation_state->tmu_write_count[tmu] = 0; ++ } ++ ++ return true; ++} ++ ++static bool ++check_reg_write(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state, ++ bool is_mul) ++{ ++ uint32_t waddr = (is_mul ? ++ QPU_GET_FIELD(inst, QPU_WADDR_MUL) : ++ QPU_GET_FIELD(inst, QPU_WADDR_ADD)); ++ ++ switch (waddr) { ++ case QPU_W_UNIFORMS_ADDRESS: ++ /* XXX: We'll probably need to support this for reladdr, but ++ * it's definitely a security-related one. ++ */ ++ DRM_ERROR("uniforms address load unsupported\n"); ++ return false; ++ ++ case QPU_W_TLB_COLOR_MS: ++ case QPU_W_TLB_COLOR_ALL: ++ case QPU_W_TLB_Z: ++ /* These only interact with the tile buffer, not main memory, ++ * so they're safe. ++ */ ++ return true; ++ ++ case QPU_W_TMU0_S: ++ case QPU_W_TMU0_T: ++ case QPU_W_TMU0_R: ++ case QPU_W_TMU0_B: ++ case QPU_W_TMU1_S: ++ case QPU_W_TMU1_T: ++ case QPU_W_TMU1_R: ++ case QPU_W_TMU1_B: ++ return check_tmu_write(inst, validated_shader, validation_state, ++ is_mul); ++ ++ case QPU_W_HOST_INT: ++ case QPU_W_TMU_NOSWAP: ++ case QPU_W_TLB_ALPHA_MASK: ++ case QPU_W_MUTEX_RELEASE: ++ /* XXX: I haven't thought about these, so don't support them ++ * for now. ++ */ ++ DRM_ERROR("Unsupported waddr %d\n", waddr); ++ return false; ++ ++ case QPU_W_VPM_ADDR: ++ DRM_ERROR("General VPM DMA unsupported\n"); ++ return false; ++ ++ case QPU_W_VPM: ++ case QPU_W_VPMVCD_SETUP: ++ /* We allow VPM setup in general, even including VPM DMA ++ * configuration setup, because the (unsafe) DMA can only be ++ * triggered by QPU_W_VPM_ADDR writes. ++ */ ++ return true; ++ ++ case QPU_W_TLB_STENCIL_SETUP: ++ return true; ++ } ++ ++ return true; ++} ++ ++static void ++track_live_clamps(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state) ++{ ++ uint32_t op_add = QPU_GET_FIELD(inst, QPU_OP_ADD); ++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); ++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); ++ uint32_t cond_add = QPU_GET_FIELD(inst, QPU_COND_ADD); ++ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A); ++ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B); ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ bool ws = inst & QPU_WS; ++ uint32_t lri_add_a, lri_add, lri_mul; ++ bool add_a_is_min_0; ++ ++ /* Check whether OP_ADD's A argumennt comes from a live MAX(x, 0), ++ * before we clear previous live state. ++ */ ++ lri_add_a = raddr_add_a_to_live_reg_index(inst); ++ add_a_is_min_0 = (lri_add_a != ~0 && ++ validation_state->live_max_clamp_regs[lri_add_a]); ++ ++ /* Clear live state for registers written by our instruction. */ ++ lri_add = waddr_to_live_reg_index(waddr_add, ws); ++ lri_mul = waddr_to_live_reg_index(waddr_mul, !ws); ++ if (lri_mul != ~0) { ++ validation_state->live_max_clamp_regs[lri_mul] = false; ++ validation_state->live_min_clamp_offsets[lri_mul] = ~0; ++ } ++ if (lri_add != ~0) { ++ validation_state->live_max_clamp_regs[lri_add] = false; ++ validation_state->live_min_clamp_offsets[lri_add] = ~0; ++ } else { ++ /* Nothing further to do for live tracking, since only ADDs ++ * generate new live clamp registers. ++ */ ++ return; ++ } ++ ++ /* Now, handle remaining live clamp tracking for the ADD operation. */ ++ ++ if (cond_add != QPU_COND_ALWAYS) ++ return; ++ ++ if (op_add == QPU_A_MAX) { ++ /* Track live clamps of a value to a minimum of 0 (in either ++ * arg). ++ */ ++ if (sig != QPU_SIG_SMALL_IMM || raddr_b != 0 || ++ (add_a != QPU_MUX_B && add_b != QPU_MUX_B)) { ++ return; ++ } ++ ++ validation_state->live_max_clamp_regs[lri_add] = true; ++ } else if (op_add == QPU_A_MIN) { ++ /* Track live clamps of a value clamped to a minimum of 0 and ++ * a maximum of some uniform's offset. ++ */ ++ if (!add_a_is_min_0) ++ return; ++ ++ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) && ++ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF && ++ sig != QPU_SIG_SMALL_IMM)) { ++ return; ++ } ++ ++ validation_state->live_min_clamp_offsets[lri_add] = ++ validated_shader->uniforms_size; ++ } ++} ++ ++static bool ++check_instruction_writes(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader, ++ struct vc4_shader_validation_state *validation_state) ++{ ++ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD); ++ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL); ++ bool ok; ++ ++ if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) { ++ DRM_ERROR("ADD and MUL both set up textures\n"); ++ return false; ++ } ++ ++ ok = (check_reg_write(inst, validated_shader, validation_state, ++ false) && ++ check_reg_write(inst, validated_shader, validation_state, ++ true)); ++ ++ track_live_clamps(inst, validated_shader, validation_state); ++ ++ return ok; ++} ++ ++static bool ++check_instruction_reads(uint64_t inst, ++ struct vc4_validated_shader_info *validated_shader) ++{ ++ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A); ++ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B); ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ if (raddr_a == QPU_R_UNIF || ++ (raddr_b == QPU_R_UNIF && sig != QPU_SIG_SMALL_IMM)) { ++ /* This can't overflow the uint32_t, because we're reading 8 ++ * bytes of instruction to increment by 4 here, so we'd ++ * already be OOM. ++ */ ++ validated_shader->uniforms_size += 4; ++ } ++ ++ return true; ++} ++ ++struct vc4_validated_shader_info * ++vc4_validate_shader(struct drm_gem_cma_object *shader_obj) ++{ ++ bool found_shader_end = false; ++ int shader_end_ip = 0; ++ uint32_t ip, max_ip; ++ uint64_t *shader; ++ struct vc4_validated_shader_info *validated_shader; ++ struct vc4_shader_validation_state validation_state; ++ int i; ++ ++ memset(&validation_state, 0, sizeof(validation_state)); ++ ++ for (i = 0; i < 8; i++) ++ validation_state.tmu_setup[i / 4].p_offset[i % 4] = ~0; ++ for (i = 0; i < ARRAY_SIZE(validation_state.live_min_clamp_offsets); i++) ++ validation_state.live_min_clamp_offsets[i] = ~0; ++ ++ shader = shader_obj->vaddr; ++ max_ip = shader_obj->base.size / sizeof(uint64_t); ++ ++ validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL); ++ if (!validated_shader) ++ return NULL; ++ ++ for (ip = 0; ip < max_ip; ip++) { ++ uint64_t inst = shader[ip]; ++ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG); ++ ++ switch (sig) { ++ case QPU_SIG_NONE: ++ case QPU_SIG_WAIT_FOR_SCOREBOARD: ++ case QPU_SIG_SCOREBOARD_UNLOCK: ++ case QPU_SIG_COLOR_LOAD: ++ case QPU_SIG_LOAD_TMU0: ++ case QPU_SIG_LOAD_TMU1: ++ case QPU_SIG_PROG_END: ++ case QPU_SIG_SMALL_IMM: ++ if (!check_instruction_writes(inst, validated_shader, ++ &validation_state)) { ++ DRM_ERROR("Bad write at ip %d\n", ip); ++ goto fail; ++ } ++ ++ if (!check_instruction_reads(inst, validated_shader)) ++ goto fail; ++ ++ if (sig == QPU_SIG_PROG_END) { ++ found_shader_end = true; ++ shader_end_ip = ip; ++ } ++ ++ break; ++ ++ case QPU_SIG_LOAD_IMM: ++ if (!check_instruction_writes(inst, validated_shader, ++ &validation_state)) { ++ DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip); ++ goto fail; ++ } ++ break; ++ ++ default: ++ DRM_ERROR("Unsupported QPU signal %d at " ++ "instruction %d\n", sig, ip); ++ goto fail; ++ } ++ ++ /* 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 (ip == max_ip) { ++ DRM_ERROR("shader failed to terminate before " ++ "shader BO end at %zd\n", ++ shader_obj->base.size); ++ goto fail; ++ } ++ ++ /* Again, no chance of integer overflow here because the worst case ++ * scenario is 8 bytes of uniforms plus handles per 8-byte ++ * instruction. ++ */ ++ validated_shader->uniforms_src_size = ++ (validated_shader->uniforms_size + ++ 4 * validated_shader->num_texture_samples); ++ ++ return validated_shader; ++ ++fail: ++ if (validated_shader) { ++ kfree(validated_shader->texture_samples); ++ kfree(validated_shader); ++ } ++ return NULL; ++} +diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h +new file mode 100644 +index 0000000..eeb37e3 +--- /dev/null ++++ b/include/uapi/drm/vc4_drm.h +@@ -0,0 +1,279 @@ ++/* ++ * Copyright © 2014-2015 Broadcom ++ * ++ * 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, sublicense, ++ * 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 NONINFRINGEMENT. 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. ++ */ ++ ++#ifndef _UAPI_VC4_DRM_H_ ++#define _UAPI_VC4_DRM_H_ ++ ++#include "drm.h" ++ ++#define DRM_VC4_SUBMIT_CL 0x00 ++#define DRM_VC4_WAIT_SEQNO 0x01 ++#define DRM_VC4_WAIT_BO 0x02 ++#define DRM_VC4_CREATE_BO 0x03 ++#define DRM_VC4_MMAP_BO 0x04 ++#define DRM_VC4_CREATE_SHADER_BO 0x05 ++#define DRM_VC4_GET_HANG_STATE 0x06 ++ ++#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) ++#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) ++#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo) ++#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo) ++#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo) ++#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo) ++#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state) ++ ++struct drm_vc4_submit_rcl_surface { ++ __u32 hindex; /* Handle index, or ~0 if not present. */ ++ __u32 offset; /* Offset to start of buffer. */ ++ /* ++ * Bits for either render config (color_write) or load/store packet. ++ * Bits should all be 0 for MSAA load/stores. ++ */ ++ __u16 bits; ++ ++#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0) ++ __u16 flags; ++}; ++ ++/** ++ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D ++ * engine. ++ * ++ * Drivers typically use GPU BOs to store batchbuffers / command lists and ++ * their associated state. However, because the VC4 lacks an MMU, we have to ++ * do validation of memory accesses by the GPU commands. If we were to store ++ * our commands in BOs, we'd need to do uncached readback from them to do the ++ * validation process, which is too expensive. Instead, userspace accumulates ++ * commands and associated state in plain memory, then the kernel copies the ++ * data to its own address space, and then validates and stores it in a GPU ++ * BO. ++ */ ++struct drm_vc4_submit_cl { ++ /* Pointer to the binner command list. ++ * ++ * This is the first set of commands executed, which runs the ++ * coordinate shader to determine where primitives land on the screen, ++ * then writes out the state updates and draw calls necessary per tile ++ * to the tile allocation BO. ++ */ ++ __u64 bin_cl; ++ ++ /* Pointer to the shader records. ++ * ++ * Shader records are the structures read by the hardware that contain ++ * pointers to uniforms, shaders, and vertex attributes. The ++ * reference to the shader record has enough information to determine ++ * how many pointers are necessary (fixed number for shaders/uniforms, ++ * and an attribute count), so those BO indices into bo_handles are ++ * just stored as __u32s before each shader record passed in. ++ */ ++ __u64 shader_rec; ++ ++ /* Pointer to uniform data and texture handles for the textures ++ * referenced by the shader. ++ * ++ * For each shader state record, there is a set of uniform data in the ++ * order referenced by the record (FS, VS, then CS). Each set of ++ * uniform data has a __u32 index into bo_handles per texture ++ * sample operation, in the order the QPU_W_TMUn_S writes appear in ++ * the program. Following the texture BO handle indices is the actual ++ * uniform data. ++ * ++ * The individual uniform state blocks don't have sizes passed in, ++ * because the kernel has to determine the sizes anyway during shader ++ * code validation. ++ */ ++ __u64 uniforms; ++ __u64 bo_handles; ++ ++ /* Size in bytes of the binner command list. */ ++ __u32 bin_cl_size; ++ /* Size in bytes of the set of shader records. */ ++ __u32 shader_rec_size; ++ /* Number of shader records. ++ * ++ * This could just be computed from the contents of shader_records and ++ * the address bits of references to them from the bin CL, but it ++ * keeps the kernel from having to resize some allocations it makes. ++ */ ++ __u32 shader_rec_count; ++ /* Size in bytes of the uniform state. */ ++ __u32 uniforms_size; ++ ++ /* Number of BO handles passed in (size is that times 4). */ ++ __u32 bo_handle_count; ++ ++ /* RCL setup: */ ++ __u16 width; ++ __u16 height; ++ __u8 min_x_tile; ++ __u8 min_y_tile; ++ __u8 max_x_tile; ++ __u8 max_y_tile; ++ struct drm_vc4_submit_rcl_surface color_read; ++ struct drm_vc4_submit_rcl_surface color_write; ++ struct drm_vc4_submit_rcl_surface zs_read; ++ struct drm_vc4_submit_rcl_surface zs_write; ++ struct drm_vc4_submit_rcl_surface msaa_color_write; ++ struct drm_vc4_submit_rcl_surface msaa_zs_write; ++ __u32 clear_color[2]; ++ __u32 clear_z; ++ __u8 clear_s; ++ ++ __u32 pad:24; ++ ++#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0) ++ __u32 flags; ++ ++ /* Returned value of the seqno of this render job (for the ++ * wait ioctl). ++ */ ++ __u64 seqno; ++}; ++ ++/** ++ * struct drm_vc4_wait_seqno - ioctl argument for waiting for ++ * DRM_VC4_SUBMIT_CL completion using its returned seqno. ++ * ++ * timeout_ns is the timeout in nanoseconds, where "0" means "don't ++ * block, just return the status." ++ */ ++struct drm_vc4_wait_seqno { ++ __u64 seqno; ++ __u64 timeout_ns; ++}; ++ ++/** ++ * struct drm_vc4_wait_bo - ioctl argument for waiting for ++ * completion of the last DRM_VC4_SUBMIT_CL on a BO. ++ * ++ * This is useful for cases where multiple processes might be ++ * rendering to a BO and you want to wait for all rendering to be ++ * completed. ++ */ ++struct drm_vc4_wait_bo { ++ __u32 handle; ++ __u32 pad; ++ __u64 timeout_ns; ++}; ++ ++/** ++ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_vc4_create_bo { ++ __u32 size; ++ __u32 flags; ++ /** Returned GEM handle for the BO. */ ++ __u32 handle; ++ __u32 pad; ++}; ++ ++/** ++ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs. ++ * ++ * This doesn't actually perform an mmap. Instead, it returns the ++ * offset you need to use in an mmap on the DRM device node. This ++ * means that tools like valgrind end up knowing about the mapped ++ * memory. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_vc4_mmap_bo { ++ /** Handle for the object being mapped. */ ++ __u32 handle; ++ __u32 flags; ++ /** offset into the drm node to use for subsequent mmap call. */ ++ __u64 offset; ++}; ++ ++/** ++ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4 ++ * shader BOs. ++ * ++ * Since allowing a shader to be overwritten while it's also being ++ * executed from would allow privlege escalation, shaders must be ++ * created using this ioctl, and they can't be mmapped later. ++ */ ++struct drm_vc4_create_shader_bo { ++ /* Size of the data argument. */ ++ __u32 size; ++ /* Flags, currently must be 0. */ ++ __u32 flags; ++ ++ /* Pointer to the data. */ ++ __u64 data; ++ ++ /** Returned GEM handle for the BO. */ ++ __u32 handle; ++ /* Pad, must be 0. */ ++ __u32 pad; ++}; ++ ++struct drm_vc4_get_hang_state_bo { ++ __u32 handle; ++ __u32 paddr; ++ __u32 size; ++ __u32 pad; ++}; ++ ++/** ++ * struct drm_vc4_hang_state - ioctl argument for collecting state ++ * from a GPU hang for analysis. ++*/ ++struct drm_vc4_get_hang_state { ++ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */ ++ __u64 bo; ++ /** ++ * On input, the size of the bo array. Output is the number ++ * of bos to be returned. ++ */ ++ __u32 bo_count; ++ ++ __u32 start_bin, start_render; ++ ++ __u32 ct0ca, ct0ea; ++ __u32 ct1ca, ct1ea; ++ __u32 ct0cs, ct1cs; ++ __u32 ct0ra0, ct1ra0; ++ ++ __u32 bpca, bpcs; ++ __u32 bpoa, bpos; ++ ++ __u32 vpmbase; ++ ++ __u32 dbge; ++ __u32 fdbgo; ++ __u32 fdbgb; ++ __u32 fdbgr; ++ __u32 fdbgs; ++ __u32 errstat; ++ ++ /* Pad that we may save more registers into in the future. */ ++ __u32 pad[16]; ++}; ++ ++#endif /* _UAPI_VC4_DRM_H_ */ + +From d3449ad0cd9603d192fbcb70ac395844e43ec1a1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 20 Oct 2015 15:56:56 +0100 +Subject: [PATCH 244/278] Add vc4-kms-v3d overlay + +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 88 ++++++++++++++++++++++ + 2 files changed, 89 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index 1a60e9c..75692d0 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -59,6 +59,7 @@ dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += spi-dma-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += vc4-kms-v3d-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += vga666-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +new file mode 100644 +index 0000000..32043e0 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -0,0 +1,88 @@ ++/* ++ * vc4-kms-v3d-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "dt-bindings/clock/bcm2835.h" ++#include "dt-bindings/gpio/gpio.h" ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&i2c2>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&cprman>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&fb>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&soc>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pixelvalve@7e206000 { ++ compatible = "brcm,bcm2835-pixelvalve0"; ++ reg = <0x7e206000 0x100>; ++ interrupts = <2 13>; /* pwa0 */ ++ }; ++ ++ pixelvalve@7e207000 { ++ compatible = "brcm,bcm2835-pixelvalve1"; ++ reg = <0x7e207000 0x100>; ++ interrupts = <2 14>; /* pwa1 */ ++ }; ++ ++ hvs@7e400000 { ++ compatible = "brcm,bcm2835-hvs"; ++ reg = <0x7e400000 0x6000>; ++ interrupts = <2 1>; ++ }; ++ ++ pixelvalve@7e807000 { ++ compatible = "brcm,bcm2835-pixelvalve2"; ++ reg = <0x7e807000 0x100>; ++ interrupts = <2 10>; /* pixelvalve */ ++ }; ++ ++ hdmi@7e902000 { ++ compatible = "brcm,bcm2835-hdmi"; ++ reg = <0x7e902000 0x600>, ++ <0x7e808000 0x100>; ++ interrupts = <2 8>, <2 9>; ++ ddc = <&i2c2>; ++ hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>; ++ clocks = <&cprman BCM2835_PLLH_PIX>, ++ <&cprman BCM2835_CLOCK_HSM>; ++ clock-names = "pixel", "hdmi"; ++ }; ++ ++ v3d@7ec00000 { ++ compatible = "brcm,vc4-v3d"; ++ reg = <0x7ec00000 0x1000>; ++ interrupts = <1 10>; ++ }; ++ ++ gpu@7e4c0000 { ++ compatible = "brcm,bcm2835-vc4"; ++ }; ++ }; ++ }; ++}; + +From 3ce28fac1cba8e3d5663cb2c0915fc6852a2cb90 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 2 Nov 2015 17:07:33 +0000 +Subject: [PATCH 245/278] drm/vc4: Enable VC4 modules, and increase CMA size + with overlay + +If using the overlay, be careful not to boot to GUI or run startx, +or the Pi will almost hang, reporting stalls in kernel threads. +--- + arch/arm/boot/dts/overlays/README | 8 ++++++++ + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 7 +++++++ + arch/arm/configs/bcm2709_defconfig | 2 ++ + arch/arm/configs/bcmrpi_defconfig | 2 ++ + 4 files changed, 19 insertions(+) + diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README -index 3276312..42a5876 100644 +index cb7c359..e651bf3 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README -@@ -178,7 +178,7 @@ Load: dtoverlay=at86rf233,= - Params: interrupt GPIO used for INT (default 23) - reset GPIO used for Reset (default 24) - sleep GPIO used for Sleep (default 25) -- speed SPI bus speed in Hz (default 750000) -+ speed SPI bus speed in Hz (default 6000000) - trim Fine tuning of the internal capacitance - arrays (0=+0pF, 15=+4.5pF, default 15) +@@ -691,6 +691,14 @@ Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) + rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + ++Name: vc4-kms-v3d ++Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or ++ booting to GUI while this overlay is in use will cause interesting ++ lockups. ++Load: dtoverlay=vc4-kms-v3d ++Params: ++ ++ + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board + This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds +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 32043e0..419b53d 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -85,4 +85,11 @@ + }; + }; + }; ++ ++ fragment@4 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "cma=0x4000000"; ++ }; ++ }; + }; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 5a61222..d61f42a 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -805,6 +805,8 @@ CONFIG_VIDEO_TW9903=m + CONFIG_VIDEO_TW9906=m + CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m ++CONFIG_DRM=m ++CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + CONFIG_FB_UDL=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 20a26f0..ccdde92 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -798,6 +798,8 @@ CONFIG_VIDEO_TW9903=m + CONFIG_VIDEO_TW9906=m + CONFIG_VIDEO_OV7640=m + CONFIG_VIDEO_MT9V011=m ++CONFIG_DRM=m ++CONFIG_DRM_VC4=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + CONFIG_FB_UDL=m + +From 65229f88bc73d44dea5d0325f5960d03e60d358d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 5 Nov 2015 11:05:09 +0000 +Subject: [PATCH 246/278] drm/vc4: Increase CMA size to 256M aligned to 256M + boundary + +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 419b53d..cf5d5c9 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -89,7 +89,7 @@ + fragment@4 { + target-path = "/chosen"; + __overlay__ { +- bootargs = "cma=0x4000000"; ++ bootargs = "cma=256M@512M"; + }; + }; + }; + +From 9475887297d3e6af66295695fa0db73884cfb8a1 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 8 Dec 2015 14:02:27 -0800 +Subject: [PATCH 247/278] drm/vc4: Use "hpd-gpios" for HDMI GPIO, like what + landed upstream. + +Signed-off-by: Eric Anholt +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 cf5d5c9..da37483 100644 +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -68,7 +68,7 @@ + <0x7e808000 0x100>; + interrupts = <2 8>, <2 9>; + ddc = <&i2c2>; +- hpd-gpio = <&gpio 46 GPIO_ACTIVE_HIGH>; ++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + clocks = <&cprman BCM2835_PLLH_PIX>, + <&cprman BCM2835_CLOCK_HSM>; + clock-names = "pixel", "hdmi"; + +From e3d395a16a2f957002049a2e7f4d8fabc08d5227 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 20 Jan 2016 17:50:09 +0000 +Subject: [PATCH 248/278] smsx95xx: Add option to disable the crimes against + truesize fix + +It may improve iperf numbers on Pi 1, but may generate dmesg warnings and possibly cause network issues +See issue 1248. +--- + drivers/net/usb/smsc95xx.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + mode change 100755 => 100644 drivers/net/usb/smsc95xx.c + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +old mode 100755 +new mode 100644 +index 08a8a8c..f664c1b +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -75,6 +75,10 @@ static bool turbo_mode = false; + module_param(turbo_mode, bool, 0644); + MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + ++static bool truesize_mode = false; ++module_param(truesize_mode, bool, 0644); ++MODULE_PARM_DESC(truesize_mode, "Report larger truesize value"); ++ + static char *macaddr = ":"; + module_param(macaddr, charp, 0); + MODULE_PARM_DESC(macaddr, "MAC address"); +@@ -1841,6 +1845,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(skb); + skb_trim(skb, skb->len - 4); /* remove fcs */ ++ if (truesize_mode) ++ skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } +@@ -1858,6 +1864,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(ax_skb); + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ++ if (truesize_mode) ++ ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + +From dd141ddde242e1dbeeca78cf97cf3d33d34c324b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 25 Jan 2016 09:12:06 +0000 +Subject: [PATCH 249/278] BCM270X_DT: Add sdio_overclock parameter to sdio + overlay + +The sdio_overclock parameter is like the overclock_50 parameter, i.e. +it sets an alternate frequency (in MHz) to use when the MMC framework +requests 50MHz, except that it applies to the SDIO bus. + +Be aware that the actual frequencies achievable are limited to even integer +divisions of 250MHz, and that the driver will round up to include fractions +(e.g. 62 will include 62.5) but then round down to the nearest frequency. +In other words, the chosen frequency is the highest possible that is less than +the parameter value + 1. In practise this means that 62 is the only sensible +value. + +Examples: + 250MHz/4 = 62.5MHz (sdio_overclock=62) + 250MHz/2 = 125MHz (sdio_overclock=125) # Too fast +--- + arch/arm/boot/dts/overlays/README | 9 ++++++--- + arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 ++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index e651bf3..0cf7997 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -53,8 +53,8 @@ have its contents deleted (or commented out). + Using Overlays + ============== + +-Overlays are loaded using the "dtoverlay" directive. As an example, consider the +-popular lirc-rpi module, the Linux Infrared Remote Control driver. In the ++Overlays are loaded using the "dtoverlay" directive. As an example, consider ++the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the + pre-DT world this would be loaded from /etc/modules, with an explicit + "modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled, + this becomes a line in config.txt: +@@ -600,9 +600,12 @@ Name: sdio + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, + and enables SDIO via GPIOs 22-27. + Load: dtoverlay=sdio,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework + requests 50MHz + ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz ++ + force_pio Disable DMA support (default off) + + pio_limit Number of blocks above which to use DMA +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 7935e7a..398bd81 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -12,6 +12,7 @@ + pinctrl-0 = <&sdio_pins>; + non-removable; + bus-width = <4>; ++ brcm,overclock-50 = <0>; + status = "okay"; + }; + }; +@@ -30,5 +31,6 @@ + __overrides__ { + poll_once = <&sdio_mmc>,"non-removable?"; + bus_width = <&sdio_mmc>,"bus-width:0"; ++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0"; + }; + }; + +From ee5ff3eac369b112886261a909b4306dea898b14 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 11 Dec 2015 19:45:03 -0800 +Subject: [PATCH 250/278] drm: Use the driver's gem_object_free function from + CMA helpers. + +VC4 wraps the CMA objects in its own structures, so it needs to do its +own teardown (waiting for GPU to finish, updating bo_stats tracking). +The other CMA drivers are using drm_gem_cma_free_object as their +gem_free_object, so this should be a no-op for them. + +Signed-off-by: Eric Anholt +(cherry picked from commit a8812101ce0faa865c1b75e461d5f05d8a43b9e3) +--- + drivers/gpu/drm/drm_fb_cma_helper.c | 6 +++--- + drivers/gpu/drm/drm_gem_cma_helper.c | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c +index 5c1aca4..99b5673 100644 +--- a/drivers/gpu/drm/drm_fb_cma_helper.c ++++ b/drivers/gpu/drm/drm_fb_cma_helper.c +@@ -279,7 +279,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, + if (!fbi) { + dev_err(dev->dev, "Failed to allocate framebuffer info.\n"); + ret = -ENOMEM; +- goto err_drm_gem_cma_free_object; ++ goto err_gem_free_object; + } + + fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1); +@@ -322,8 +322,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, + drm_fb_cma_destroy(fb); + err_framebuffer_release: + framebuffer_release(fbi); +-err_drm_gem_cma_free_object: +- drm_gem_cma_free_object(&obj->base); ++err_gem_free_object: ++ dev->driver->gem_free_object(&obj->base); + return ret; + } + +diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c +index a2f13aa..27cc420 100644 +--- a/drivers/gpu/drm/drm_gem_cma_helper.c ++++ b/drivers/gpu/drm/drm_gem_cma_helper.c +@@ -121,7 +121,7 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, + return cma_obj; + + error: +- drm_gem_cma_free_object(&cma_obj->base); ++ drm->driver->gem_free_object(&cma_obj->base); + return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(drm_gem_cma_create); +@@ -171,7 +171,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv, + return cma_obj; + + err_handle_create: +- drm_gem_cma_free_object(gem_obj); ++ drm->driver->gem_free_object(gem_obj); + + return ERR_PTR(ret); + } + +From d94f206f5e395d8d4dbbbce658985b221c8795f5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 22 Jan 2016 13:06:39 -0800 +Subject: [PATCH 251/278] drm/vc4: Add a debugfs node for tracking execution + state. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_gem.c | 14 ++++++++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c +index d76ad10..a99aa86 100644 +--- a/drivers/gpu/drm/vc4/vc4_debugfs.c ++++ b/drivers/gpu/drm/vc4/vc4_debugfs.c +@@ -17,6 +17,7 @@ + + static const struct drm_info_list vc4_debugfs_list[] = { + {"bo_stats", vc4_bo_stats_debugfs, 0}, ++ {"gem_exec", vc4_gem_exec_debugfs, 0}, + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, + {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 03e037e..d3850e8 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -403,6 +403,7 @@ void vc4_job_handle_completed(struct vc4_dev *vc4); + int vc4_queue_seqno_cb(struct drm_device *dev, + struct vc4_seqno_cb *cb, uint64_t seqno, + void (*func)(struct vc4_seqno_cb *cb)); ++int vc4_gem_exec_debugfs(struct seq_file *m, void *arg); + + /* vc4_hdmi.c */ + extern struct platform_driver vc4_hdmi_driver; +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 39f29e7..1243f4e 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -31,6 +31,20 @@ + #include "vc4_regs.h" + #include "vc4_trace.h" + ++#ifdef CONFIG_DEBUG_FS ++int vc4_gem_exec_debugfs(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); ++ ++ seq_printf(m, "Emitted seqno: 0x%016llx\n", vc4->emit_seqno); ++ seq_printf(m, "Finished seqno: 0x%016llx\n", vc4->finished_seqno); ++ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ + static void + vc4_queue_hangcheck(struct drm_device *dev) + { + +From 69680d2967d46ba507b468e662630bb54e25126a Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:03:33 -0800 +Subject: [PATCH 252/278] drm/vc4: Include vc4_drm.h in uapi in downstream + build. + +Signed-off-by: Eric Anholt +--- + include/uapi/drm/Kbuild | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild +index 2d9a25d..8cb3dbb 100644 +--- a/include/uapi/drm/Kbuild ++++ b/include/uapi/drm/Kbuild +@@ -14,6 +14,7 @@ header-y += radeon_drm.h + header-y += savage_drm.h + header-y += sis_drm.h + header-y += tegra_drm.h ++header-y += vc4_drm.h + header-y += via_drm.h + header-y += vmwgfx_drm.h + header-y += msm_drm.h + +From fd03f679dd87b612d2d018c3426da9359987d0c0 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:05:00 -0800 +Subject: [PATCH 253/278] drm/vc4: Validate that WAIT_BO padding is cleared. + +This is ABI future-proofing if we ever want to extend the pad to mean +something. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 1243f4e..849d374 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -761,6 +761,9 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data, + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + ++ if (args->pad != 0) ++ return -EINVAL; ++ + gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (!gem_obj) { + DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); + +From 6f43eea3834c75fabfe868b03d3154fd73c12d5d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 13:52:41 -0800 +Subject: [PATCH 254/278] drm/vc4: Fix the clear color for the first tile + rendered. + +Apparently in hardware (as opposed to simulation), the clear colors +need to be uploaded before the render config, otherwise they won't +take effect. Fixes igt's vc4_wait_bo/used-bo-* subtests. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_render_cl.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index 8a2a312..dea97f4 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -321,15 +321,6 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, + &exec->unref_list); + +- rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); +- rcl_u32(setup, +- (setup->color_write ? (setup->color_write->paddr + +- args->color_write.offset) : +- 0)); +- rcl_u16(setup, args->width); +- rcl_u16(setup, args->height); +- rcl_u16(setup, args->color_write.bits); +- + /* The tile buffer gets cleared when the previous tile is stored. If + * the clear values changed between frames, then the tile buffer has + * stale clear values in it, so we have to do a store in None mode (no +@@ -349,6 +340,15 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + rcl_u32(setup, 0); /* no address, since we're in None mode */ + } + ++ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); ++ rcl_u32(setup, ++ (setup->color_write ? (setup->color_write->paddr + ++ args->color_write.offset) : ++ 0)); ++ rcl_u16(setup, args->width); ++ rcl_u16(setup, args->height); ++ rcl_u16(setup, args->color_write.bits); ++ + for (y = min_y_tile; y <= max_y_tile; y++) { + for (x = min_x_tile; x <= max_x_tile; x++) { + bool first = (x == min_x_tile && y == min_y_tile); + +From 2e5c374e7d27cb403f6de594bc8358dfb35755be Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:13:12 -0800 +Subject: [PATCH 255/278] drm/vc4: Return an ERR_PTR from BO creation instead + of NULL. + +Fixes igt vc4_create_bo/create-bo-0 by returning -EINVAL from the +ioctl instead of -ENOMEM. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_bo.c | 23 +++++++++++++---------- + drivers/gpu/drm/vc4/vc4_gem.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_irq.c | 2 +- + drivers/gpu/drm/vc4/vc4_render_cl.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_validate.c | 4 ++-- + 5 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index 6247ff8..8477579 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -213,10 +213,10 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, + size_t size = roundup(unaligned_size, PAGE_SIZE); + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_gem_cma_object *cma_obj; +- int pass; ++ int pass, ret; + + if (size == 0) +- return NULL; ++ return ERR_PTR(-EINVAL); + + /* First, try to get a vc4_bo from the kernel BO cache. */ + if (from_cache) { +@@ -247,14 +247,17 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, + * unreferenced BOs to the cache, and then + * free the cache. + */ +- vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, true); ++ ret = vc4_wait_for_seqno(dev, vc4->emit_seqno, ~0ull, ++ true); ++ if (ret) ++ return ERR_PTR(ret); + vc4_job_handle_completed(vc4); + vc4_bo_cache_purge(dev); + break; + case 3: + DRM_ERROR("Failed to allocate from CMA:\n"); + vc4_bo_stats_dump(vc4); +- return NULL; ++ return ERR_PTR(-ENOMEM); + } + } + +@@ -276,8 +279,8 @@ int vc4_dumb_create(struct drm_file *file_priv, + args->size = args->pitch * args->height; + + bo = vc4_bo_create(dev, args->size, false); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_unreference_unlocked(&bo->base.base); +@@ -460,8 +463,8 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data, + * get zeroed, and that might leak data between users. + */ + bo = vc4_bo_create(dev, args->size, false); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_unreference_unlocked(&bo->base.base); +@@ -513,8 +516,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, + } + + bo = vc4_bo_create(dev, args->size, true); +- if (!bo) +- return -ENOMEM; ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); + + ret = copy_from_user(bo->base.vaddr, + (void __user *)(uintptr_t)args->data, +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index 849d374..f8c003a 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -593,9 +593,9 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) + } + + bo = vc4_bo_create(dev, exec_size, true); +- if (!bo) { ++ if (IS_ERR(bo)) { + DRM_ERROR("Couldn't allocate BO for binning\n"); +- ret = PTR_ERR(exec->exec_bo); ++ ret = PTR_ERR(bo); + goto fail; + } + exec->exec_bo = &bo->base; +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +index b68060e..78a2135 100644 +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -57,7 +57,7 @@ vc4_overflow_mem_work(struct work_struct *work) + struct vc4_bo *bo; + + bo = vc4_bo_create(dev, 256 * 1024, true); +- if (!bo) { ++ if (IS_ERR(bo)) { + DRM_ERROR("Couldn't allocate binner overflow mem\n"); + return; + } +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index dea97f4..0f12418 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -316,8 +316,8 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + size += xtiles * ytiles * loop_body_size; + + setup->rcl = &vc4_bo_create(dev, size, true)->base; +- if (!setup->rcl) +- return -ENOMEM; ++ if (IS_ERR(setup->rcl)) ++ return PTR_ERR(setup->rcl); + list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, + &exec->unref_list); + +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 0fb5b99..8396960 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -401,8 +401,8 @@ validate_tile_binning_config(VALIDATE_ARGS) + tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, + true); + exec->tile_bo = &tile_bo->base; +- if (!exec->tile_bo) +- return -ENOMEM; ++ if (IS_ERR(exec->tile_bo)) ++ return PTR_ERR(exec->tile_bo); + list_add_tail(&tile_bo->unref_head, &exec->unref_list); + + /* tile alloc address. */ + +From 39bbb00a1740b4d54f587a25ba82bada1ae98ba5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:32:41 -0800 +Subject: [PATCH 256/278] drm/vc4: Fix -ERESTARTSYS error return from BO waits. + +This caused the wait ioctls to claim that waiting had completed when +we actually got interrupted by a signal before it was done. Fixes +broken rendering throttling that produced serious lag in X window +dragging. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index f8c003a..dc3044d 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -352,12 +352,10 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, + finish_wait(&vc4->job_wait_queue, &wait); + trace_vc4_wait_for_seqno_end(dev, seqno); + +- if (ret && ret != -ERESTARTSYS) { ++ if (ret && ret != -ERESTARTSYS) + DRM_ERROR("timeout waiting for render thread idle\n"); +- return ret; +- } + +- return 0; ++ return ret; + } + + static void + +From fde284c88f2260e63cfcb5c053d3eaced109d363 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 25 Jan 2016 14:33:50 -0800 +Subject: [PATCH 257/278] drm/vc4: Drop error message on seqno wait timeouts. + +These ioctls end up getting exposed to userspace, and having normal +user requests print DRM errors is obviously wrong. The message was +originally to give us some idea of what happened when a hang occurred, +but we have a DRM_INFO from reset for that. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_gem.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index dc3044d..a6fa63f 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -352,9 +352,6 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, + finish_wait(&vc4->job_wait_queue, &wait); + trace_vc4_wait_for_seqno_end(dev, seqno); + +- if (ret && ret != -ERESTARTSYS) +- DRM_ERROR("timeout waiting for render thread idle\n"); +- + return ret; + } + + +From 1b1c474d92849d740d67ad30514df3ae198ede58 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 1 Feb 2016 11:44:47 +0000 +Subject: [PATCH 258/278] Revert "bcm270x_dt: Use the sdhost MMC controller by + default" + +This reverts commit aad4e7c34665e3f2fd4e7cb613aeca231e09ac5c. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 11 ++---- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 11 ++---- + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 14 ++------ + arch/arm/boot/dts/bcm2708_common.dtsi | 13 ------- + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 11 ++---- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 22 +----------- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 49 +++++++++++++++++++++------ + arch/arm/boot/dts/overlays/sdio-overlay.dts | 1 + + 8 files changed, 48 insertions(+), 84 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index bb8c075..d41d31c 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 8030401..684852f 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 91ec483c..713e5a2 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,12 +1,5 @@ + /include/ "bcm2708.dtsi" + +-&gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +-}; +- + &leds { + act_led: act { + label = "led0"; +@@ -15,12 +8,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; +- non-removable; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 0425419..924edc8 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,7 +14,6 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; +- sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -127,18 +126,6 @@ + status = "disabled"; + }; + +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,pio-limit = <1>; +- status = "disabled"; +- }; +- + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index 747f859..a8e8b7c 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,11 +8,6 @@ + }; + + &gpio { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -34,11 +29,9 @@ + }; + }; + +-&sdhost { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- bus-width = <4>; ++&mmc { + status = "okay"; ++ bus-width = <4>; + }; + + &fb { +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 00a22be..4579ff2 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,29 +6,9 @@ + + fragment@0 { + target = <&mmc>; ++ + frag0: __overlay__ { +- pinctrl-names = "default"; +- pinctrl-0 = <&mmc_pins>; +- bus-width = <4>; + brcm,overclock-50 = <0>; +- status = "okay"; +- }; +- }; +- +- fragment@1 { +- target = <&gpio>; +- __overlay__ { +- mmc_pins: mmc_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <7>; /* alt3 */ +- }; +- }; +- }; +- +- fragment@2 { +- target = <&sdhost>; +- __overlay__ { +- status = "disabled"; + }; + }; + +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 85f0725..2da14a4 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -5,25 +5,52 @@ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&mmc>; ++ target = <&soc>; + __overlay__ { +- status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,delay-after-stop = <0>; ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; ++ }; + }; + }; + + fragment@1 { +- target = <&sdhost>; +- frag1: __overlay__ { +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; ++ target = <&gpio>; ++ __overlay__ { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&mmc>; ++ __overlay__ { ++ /* Find a way to disable the other driver */ ++ compatible = ""; ++ status = "disabled"; + }; + }; + + __overrides__ { +- overclock_50 = <&frag1>,"brcm,overclock-50:0"; +- force_pio = <&frag1>,"brcm,force-pio?"; +- pio_limit = <&frag1>,"brcm,pio-limit:0"; +- debug = <&frag1>,"brcm,debug?"; ++ overclock_50 = <&sdhost>,"brcm,overclock-50:0"; ++ force_pio = <&sdhost>,"brcm,force-pio?"; ++ pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ debug = <&sdhost>,"brcm,debug?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts +index 398bd81..d6a812d 100644 +--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts +@@ -8,6 +8,7 @@ + fragment@3 { + target = <&mmc>; + sdio_mmc: __overlay__ { ++ compatible = "brcm,bcm2835-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + non-removable; + +From 9552fbc94e0ed0a52c9cb5249c1642a9eb2e9810 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 8 Feb 2016 09:51:08 +0000 +Subject: [PATCH 259/278] BCM270X_DT: Adjust overlay README formatting + +--- + arch/arm/boot/dts/overlays/README | 396 +++++++++++++++++++------------------- + 1 file changed, 198 insertions(+), 198 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 0cf7997..734be606 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -83,58 +83,58 @@ Name: + Info: Configures the base Raspberry Pi hardware + Load: + Params: +- audio Set to "on" to enable the onboard ALSA audio +- interface (default "off") ++ audio Set to "on" to enable the onboard ALSA audio ++ interface (default "off") + +- i2c_arm Set to "on" to enable the ARM's i2c interface +- (default "off") ++ i2c_arm Set to "on" to enable the ARM's i2c interface ++ (default "off") + +- i2c_vc Set to "on" to enable the i2c interface +- usually reserved for the VideoCore processor +- (default "off") ++ i2c_vc Set to "on" to enable the i2c interface ++ usually reserved for the VideoCore processor ++ (default "off") + +- i2c An alias for i2c_arm ++ i2c An alias for i2c_arm + +- i2c_arm_baudrate Set the baudrate of the ARM's i2c interface +- (default "100000") ++ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface ++ (default "100000") + +- i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface +- (default "100000") ++ i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface ++ (default "100000") + +- i2c_baudrate An alias for i2c_arm_baudrate ++ i2c_baudrate An alias for i2c_arm_baudrate + +- i2s Set to "on" to enable the i2s interface +- (default "off") ++ i2s Set to "on" to enable the i2s interface ++ (default "off") + +- spi Set to "on" to enable the spi interfaces +- (default "off") ++ spi Set to "on" to enable the spi interfaces ++ (default "off") + +- random Set to "on" to enable the hardware random +- number generator (default "on") ++ random Set to "on" to enable the hardware random ++ number generator (default "on") + +- uart0 Set to "off" to disable uart0 (default "on") ++ uart0 Set to "off" to disable uart0 (default "on") + +- watchdog Set to "on" to enable the hardware watchdog +- (default "off") ++ watchdog Set to "on" to enable the hardware watchdog ++ (default "off") + +- act_led_trigger Choose which activity the LED tracks. +- Use "heartbeat" for a nice load indicator. +- (default "mmc") ++ act_led_trigger Choose which activity the LED tracks. ++ Use "heartbeat" for a nice load indicator. ++ (default "mmc") + +- act_led_activelow Set to "on" to invert the sense of the LED +- (default "off") ++ act_led_activelow Set to "on" to invert the sense of the LED ++ (default "off") + +- act_led_gpio Set which GPIO to use for the activity LED +- (in case you want to connect it to an external +- device) +- (default "16" on a non-Plus board, "47" on a +- Plus or Pi 2) ++ act_led_gpio Set which GPIO to use for the activity LED ++ (in case you want to connect it to an external ++ device) ++ (default "16" on a non-Plus board, "47" on a ++ Plus or Pi 2) + + pwr_led_trigger + pwr_led_activelow + pwr_led_gpio +- As for act_led_*, but using the PWR LED. +- Not available on Model A/B boards. ++ As for act_led_*, but using the PWR LED. ++ Not available on Model A/B boards. + + N.B. It is recommended to only enable those interfaces that are needed. + Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc +@@ -149,19 +149,19 @@ Params: + Name: ads7846 + Info: ADS7846 Touch controller + Load: dtoverlay=ads7846,= +-Params: cs SPI bus Chip Select (default 1) +- speed SPI bus speed (default 2MHz, max 3.25MHz) +- penirq GPIO used for PENIRQ. REQUIRED +- penirq_pull Set GPIO pull (default 0=none, 2=pullup) +- swapxy Swap x and y axis +- xmin Minimum value on the X axis (default 0) +- ymin Minimum value on the Y axis (default 0) +- xmax Maximum value on the X axis (default 4095) +- ymax Maximum value on the Y axis (default 4095) +- pmin Minimum reported pressure value (default 0) +- pmax Maximum reported pressure value (default 65535) +- xohms Touchpanel sensitivity (X-plate resistance) +- (default 400) ++Params: cs SPI bus Chip Select (default 1) ++ speed SPI bus speed (default 2MHz, max 3.25MHz) ++ penirq GPIO used for PENIRQ. REQUIRED ++ penirq_pull Set GPIO pull (default 0=none, 2=pullup) ++ swapxy Swap x and y axis ++ xmin Minimum value on the X axis (default 0) ++ ymin Minimum value on the Y axis (default 0) ++ xmax Maximum value on the X axis (default 4095) ++ ymax Maximum value on the Y axis (default 4095) ++ pmin Minimum reported pressure value (default 0) ++ pmax Maximum reported pressure value (default 65535) ++ xohms Touchpanel sensitivity (X-plate resistance) ++ (default 400) + + penirq is required and usually xohms (60-100) has to be set as well. + Apart from that, pmax (255) and swapxy are also common. +@@ -175,12 +175,12 @@ Name: at86rf233 + Info: Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver, + connected to spi0.0 + Load: dtoverlay=at86rf233,= +-Params: interrupt GPIO used for INT (default 23) +- reset GPIO used for Reset (default 24) +- sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 6000000) +- trim Fine tuning of the internal capacitance +- arrays (0=+0pF, 15=+4.5pF, default 15) ++Params: interrupt GPIO used for INT (default 23) ++ reset GPIO used for Reset (default 24) ++ sleep GPIO used for Sleep (default 25) ++ speed SPI bus speed in Hz (default 6000000) ++ trim Fine tuning of the internal capacitance ++ arrays (0=+0pF, 15=+4.5pF, default 15) + + + Name: bmp085_i2c-sensor +@@ -194,8 +194,8 @@ Name: dht11 + Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors + Also sometimes found with the part number(s) AM230x. + Load: dtoverlay=dht11,= +-Params: gpiopin GPIO connected to the sensor's DATA output. +- (default 4) ++Params: gpiopin GPIO connected to the sensor's DATA output. ++ (default 4) + + + [ The ds1307-rtc overlay has been deleted. See i2c-rtc. ] +@@ -204,9 +204,9 @@ Params: gpiopin GPIO connected to the sensor's DATA output. + Name: enc28j60 + Info: Overlay for the Microchip ENC28J60 Ethernet Controller (SPI) + Load: dtoverlay=enc28j60,= +-Params: int_pin GPIO used for INT (default 25) ++Params: int_pin GPIO used for INT (default 25) + +- speed SPI bus speed (default 12000000) ++ speed SPI bus speed (default 12000000) + + + Name: gpio-ir +@@ -216,26 +216,26 @@ Info: Use GPIO pin as rc-core style infrared receiver input. The rc-core- + not required! The key mapping and other decoding parameters can be + configured by "ir-keytable" tool. + Load: dtoverlay=gpio-ir,= +-Params: gpio_pin Input pin number. Default is 18. ++Params: gpio_pin Input pin number. Default is 18. + +- gpio_pull Desired pull-up/down state (off, down, up) +- Default is "down". ++ gpio_pull Desired pull-up/down state (off, down, up) ++ Default is "down". + +- rc-map-name Default rc keymap (can also be changed by +- ir-keytable), defaults to "rc-rc6-mce" ++ rc-map-name Default rc keymap (can also be changed by ++ ir-keytable), defaults to "rc-rc6-mce" + + + Name: gpio-poweroff + Info: Drives a GPIO high or low on reboot + Load: dtoverlay=gpio-poweroff,= +-Params: gpiopin GPIO for signalling (default 26) ++Params: gpiopin GPIO for signalling (default 26) + +- active_low Set if the power control device requires a +- high->low transition to trigger a power-down. +- Note that this will require the support of a +- custom dt-blob.bin to prevent a power-down +- during the boot process, and that a reboot +- will also cause the pin to go low. ++ active_low Set if the power control device requires a ++ high->low transition to trigger a power-down. ++ Note that this will require the support of a ++ custom dt-blob.bin to prevent a power-down ++ during the boot process, and that a reboot ++ will also cause the pin to go low. + + + Name: hifiberry-amp +@@ -266,65 +266,65 @@ Name: hy28a + Info: HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics + Default values match Texy's display shield + Load: dtoverlay=hy28a,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + +- resetgpio GPIO used to reset controller ++ resetgpio GPIO used to reset controller + +- ledgpio GPIO used to control backlight ++ ledgpio GPIO used to control backlight + + + Name: hy28b + Info: HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics + Default values match Texy's display shield + Load: dtoverlay=hy28b,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + +- resetgpio GPIO used to reset controller ++ resetgpio GPIO used to reset controller + +- ledgpio GPIO used to control backlight ++ ledgpio GPIO used to control backlight + + + Name: i2c-gpio + Info: Adds support for software i2c controller on gpio pins + Load: dtoverlay=i2c-gpio,= +-Params: i2c_gpio_sda GPIO used for I2C data (default "23") ++Params: i2c_gpio_sda GPIO used for I2C data (default "23") + +- i2c_gpio_scl GPIO used for I2C clock (default "24") ++ i2c_gpio_scl GPIO used for I2C clock (default "24") + +- i2c_gpio_delay_us Clock delay in microseconds +- (default "2" = ~100kHz) ++ i2c_gpio_delay_us Clock delay in microseconds ++ (default "2" = ~100kHz) + + + Name: i2c-rtc + Info: Adds support for a number of I2C Real Time Clock devices + Load: dtoverlay=i2c-rtc,= +-Params: ds1307 Select the DS1307 device ++Params: ds1307 Select the DS1307 device + +- ds3231 Select the DS3231 device ++ ds3231 Select the DS3231 device + +- mcp7941x Select the MCP7941x device ++ mcp7941x Select the MCP7941x device + +- pcf2127 Select the PCF2127 device ++ pcf2127 Select the PCF2127 device + +- pcf8523 Select the PCF8523 device ++ pcf8523 Select the PCF8523 device + +- pcf8563 Select the PCF8563 device ++ pcf8563 Select the PCF8563 device + + + Name: i2s-mmap +@@ -349,70 +349,70 @@ Name: lirc-rpi + Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi) + Consult the module documentation for more details. + Load: dtoverlay=lirc-rpi,= +-Params: gpio_out_pin GPIO for output (default "17") ++Params: gpio_out_pin GPIO for output (default "17") + +- gpio_in_pin GPIO for input (default "18") ++ gpio_in_pin GPIO for input (default "18") + +- gpio_in_pull Pull up/down/off on the input pin +- (default "down") ++ gpio_in_pull Pull up/down/off on the input pin ++ (default "down") + +- sense Override the IR receive auto-detection logic: +- "0" = force active-high +- "1" = force active-low +- "-1" = use auto-detection +- (default "-1") ++ sense Override the IR receive auto-detection logic: ++ "0" = force active-high ++ "1" = force active-low ++ "-1" = use auto-detection ++ (default "-1") + +- softcarrier Turn the software carrier "on" or "off" +- (default "on") ++ softcarrier Turn the software carrier "on" or "off" ++ (default "on") + +- invert "on" = invert the output pin (default "off") ++ invert "on" = invert the output pin (default "off") + +- debug "on" = enable additional debug messages +- (default "off") ++ debug "on" = enable additional debug messages ++ (default "off") + + + Name: mcp2515-can0 + Info: Configures the MCP2515 CAN controller on spi0.0 + Load: dtoverlay=mcp2515-can0,= +-Params: oscillator Clock frequency for the CAN controller (Hz) ++Params: oscillator Clock frequency for the CAN controller (Hz) + +- spimaxfrequency Maximum SPI frequence (Hz) ++ spimaxfrequency Maximum SPI frequence (Hz) + +- interrupt GPIO for interrupt signal ++ interrupt GPIO for interrupt signal + + + Name: mcp2515-can1 + Info: Configures the MCP2515 CAN controller on spi0.1 + Load: dtoverlay=mcp2515-can1,= +-Params: oscillator Clock frequency for the CAN controller (Hz) ++Params: oscillator Clock frequency for the CAN controller (Hz) + +- spimaxfrequency Maximum SPI frequence (Hz) ++ spimaxfrequency Maximum SPI frequence (Hz) + +- interrupt GPIO for interrupt signal ++ interrupt GPIO for interrupt signal + + + Name: mmc + Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock + Load: dtoverlay=mmc,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework +- requests 50MHz +- force_pio Disable DMA support ++Params: overclock_50 Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ force_pio Disable DMA support + + + Name: mz61581 + Info: MZ61581 display by Tontec + Load: dtoverlay=mz61581,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- txbuflen Transmit buffer length (default 32768) ++ txbuflen Transmit buffer length (default 32768) + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ] +@@ -427,69 +427,69 @@ Params: speed Display SPI bus speed + Name: piscreen + Info: PiScreen display by OzzMaker.com + Load: dtoverlay=piscreen,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com + Load: dtoverlay=piscreen2r,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: pitft28-capacitive + Info: Adafruit PiTFT 2.8" capacitive touch screen + Load: dtoverlay=pitft28-capacitive,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- touch-sizex Touchscreen size x (default 240) ++ touch-sizex Touchscreen size x (default 240) + +- touch-sizey Touchscreen size y (default 320) ++ touch-sizey Touchscreen size y (default 320) + +- touch-invx Touchscreen inverted x axis ++ touch-invx Touchscreen inverted x axis + +- touch-invy Touchscreen inverted y axis ++ touch-invy Touchscreen inverted y axis + +- touch-swapxy Touchscreen swapped x y axis ++ touch-swapxy Touchscreen swapped x y axis + + + Name: pitft28-resistive + Info: Adafruit PiTFT 2.8" resistive touch screen + Load: dtoverlay=pitft28-resistive,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + + + Name: pps-gpio + Info: Configures the pps-gpio (pulse-per-second time signal via GPIO). + Load: dtoverlay=pps-gpio,= +-Params: gpiopin Input GPIO (default "18") ++Params: gpiopin Input GPIO (default "18") + + + Name: pwm +@@ -503,12 +503,12 @@ Info: Configures a single PWM channel + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clock must have been enabled and configured ++ 4) Currently the clockmust have been enabled and configured + by other means. + Load: dtoverlay=pwm,= +-Params: pin Output pin (default 18) - see table +- func Pin function (default 2 = Alt5) - see above +- clock PWM clock frequency (informational) ++Params: pin Output pin (default 18) - see table ++ func Pin function (default 2 = Alt5) - see above ++ clock PWM clock frequency (informational) + + + Name: pwm-2chan +@@ -522,14 +522,14 @@ Info: Configures both PWM channels + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clock must have been enabled and configured ++ 4) Currently the clockmust have been enabled and configured + by other means. + Load: dtoverlay=pwm-2chan,= +-Params: pin Output pin (default 18) - see table +- pin2 Output pin for other channel (default 19) +- func Pin function (default 2 = Alt5) - see above +- func2 Function for pin2 (default 2 = Alt5) +- clock PWM clock frequency (informational) ++Params: pin Output pin (default 18) - see table ++ pin2 Output pin for other channel (default 19) ++ func Pin function (default 2 = Alt5) - see above ++ func2 Function for pin2 (default 2 = Alt5) ++ clock PWM clock frequency (informational) + + + Name: raspidac3 +@@ -553,15 +553,15 @@ Params: + Name: rpi-display + Info: RPi-Display - 2.8" Touch Display by Watterott + Load: dtoverlay=rpi-display,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- xohms Touchpanel sensitivity (X-plate resistance) ++ xohms Touchpanel sensitivity (X-plate resistance) + + + Name: rpi-ft5406 +@@ -585,38 +585,38 @@ Params: + Name: sdhost + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock + Load: dtoverlay=sdhost,= +-Params: overclock_50 Clock (in MHz) to use when the MMC framework +- requests 50MHz ++Params: overclock_50 Clock (in MHz) to use when the MMC framework ++ requests 50MHz + +- force_pio Disable DMA support (default off) ++ force_pio Disable DMA support (default off) + +- pio_limit Number of blocks above which to use DMA +- (default 1) ++ pio_limit Number of blocks above which to use DMA ++ (default 1) + +- debug Enable debug output (default off) ++ debug Enable debug output (default off) + + + Name: sdio + Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, + and enables SDIO via GPIOs 22-27. + Load: dtoverlay=sdio,= +-Params: overclock_50 SD Clock (in MHz) to use when the MMC framework +- requests 50MHz ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework ++ requests 50MHz + +- sdio_overclock SDIO Clock (in MHz) to use when the MMC +- framework requests 50MHz ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz + +- force_pio Disable DMA support (default off) ++ force_pio Disable DMA support (default off) + +- pio_limit Number of blocks above which to use DMA +- (default 1) ++ pio_limit Number of blocks above which to use DMA ++ (default 1) + +- debug Enable debug output (default off) ++ debug Enable debug output (default off) + +- poll_once Disable SDIO-device polling every second +- (default on: polling once at boot-time) ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) + +- bus_width Set the SDIO host bus width (default 4 bits) ++ bus_width Set the SDIO host bus width (default 4 bits) + + + Name: smi +@@ -659,25 +659,25 @@ Name: tinylcd35 + Info: 3.5" Color TFT Display by www.tinylcd.com + Options: Touch, RTC, keypad + Load: dtoverlay=tinylcd35,= +-Params: speed Display SPI bus speed ++Params: speed Display SPI bus speed + +- rotate Display rotation {0,90,180,270} ++ rotate Display rotation {0,90,180,270} + +- fps Delay between frame updates ++ fps Delay between frame updates + +- debug Debug output level {0-7} ++ debug Debug output level {0-7} + +- touch Enable touch panel ++ touch Enable touch panel + +- touchgpio Touch controller IRQ GPIO ++ touchgpio Touch controller IRQ GPIO + +- xohms Touchpanel: Resistance of X-plate in ohms ++ xohms Touchpanel: Resistance of X-plate in ohms + +- rtc-pcf PCF8563 Real Time Clock ++ rtc-pcf PCF8563 Real Time Clock + +- rtc-ds DS1307 Real Time Clock ++ rtc-ds DS1307 Real Time Clock + +- keypad Enable keypad ++ keypad Enable keypad + + Examples: + Display with touchpanel, PCF8563 RTC and keypad: +@@ -689,9 +689,9 @@ Params: speed Display SPI bus speed + Name: uart1 + Info: Enable uart1 in place of uart0 + Load: dtoverlay=uart1,= +-Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) ++Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14) + +- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) ++ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + + + Name: vc4-kms-v3d +@@ -704,7 +704,7 @@ Params: + + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board +- This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds ++ This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds + after the kernel has started. + Load: dtoverlay=vga666 + Params: +@@ -714,22 +714,22 @@ Name: w1-gpio + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *don't* need a GPIO to drive an external pullup. + Load: dtoverlay=w1-gpio,= +-Params: gpiopin GPIO for I/O (default "4") ++Params: gpiopin GPIO for I/O (default "4") + +- pullup Non-zero, "on", or "y" to enable the parasitic +- power (2-wire, power-on-data) feature ++ pullup Non-zero, "on", or "y" to enable the parasitic ++ power (2-wire, power-on-data) feature + + + Name: w1-gpio-pullup + Info: Configures the w1-gpio Onewire interface module. + Use this overlay if you *do* need a GPIO to drive an external pullup. + Load: dtoverlay=w1-gpio-pullup,= +-Params: gpiopin GPIO for I/O (default "4") ++Params: gpiopin GPIO for I/O (default "4") + +- pullup Non-zero, "on", or "y" to enable the parasitic +- power (2-wire, power-on-data) feature ++ pullup Non-zero, "on", or "y" to enable the parasitic ++ power (2-wire, power-on-data) feature + +- extpullup GPIO for external pullup (default "5") ++ extpullup GPIO for external pullup (default "5") + + + Troubleshooting + +From 1cd0ef61452ad01f02a39060df4aaba98a8b6845 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 8 Feb 2016 12:53:44 +0000 +Subject: [PATCH 260/278] FIXUP: Overlay README - Restore spaces deleted in + error + +--- + arch/arm/boot/dts/overlays/README | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 734be606..b657512 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -503,7 +503,7 @@ Info: Configures a single PWM channel + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clockmust have been enabled and configured ++ 4) Currently the clock must have been enabled and configured + by other means. + Load: dtoverlay=pwm,= + Params: pin Output pin (default 18) - see table +@@ -522,7 +522,7 @@ Info: Configures both PWM channels + Pins 12 and 13 might be better choices on an A+, B+ or Pi2. + 2) The onboard analogue audio output uses both PWM channels. + 3) So be careful mixing audio and PWM. +- 4) Currently the clockmust have been enabled and configured ++ 4) Currently the clock must have been enabled and configured + by other means. + Load: dtoverlay=pwm-2chan,= + Params: pin Output pin (default 18) - see table +@@ -704,7 +704,7 @@ Params: + + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board +- This uses GPIOs 2-21 (sono I2C), and activates the output 2-3 seconds ++ This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds + after the kernel has started. + Load: dtoverlay=vga666 + Params: + +From 17e9af6feddde2b08a224868a099307a577c4cde Mon Sep 17 00:00:00 2001 +From: Digital Dreamtime +Date: Thu, 4 Feb 2016 14:14:44 +0000 +Subject: [PATCH 261/278] Allow up to 24dB digital gain to be applied when + using IQAudIO DAC+ + +24db_digital_gain DT param can be used to specify that PCM512x +codec "Digital" volume control should not be limited to 0dB gain, +and if specified will allow the full 24dB gain. +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++++++++-- + .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 6 +++++- + sound/soc/bcm/iqaudio-dac.c | 22 +++++++++++++++------- + 3 files changed, 35 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index b657512..7f1ef9b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -341,8 +341,21 @@ Params: + + Name: iqaudio-dacplus + Info: Configures the IQaudio DAC+ audio card +-Load: dtoverlay=iqaudio-dacplus +-Params: ++Load: dtoverlay=iqaudio-dacplus,= ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ Digital volume control. Enable with ++ "dtoverlay=iqaudio-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: lirc-rpi +diff --git a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +index 735d8ab..e0aaf8f 100644 +--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +@@ -7,7 +7,7 @@ + + fragment@0 { + target = <&sound>; +- __overlay__ { ++ frag0: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; + i2s-controller = <&i2s>; + status = "okay"; +@@ -36,4 +36,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag0>,"iqaudio,24db_digital_gain?"; ++ }; + }; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index a38e874..5ade006 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -23,15 +23,20 @@ + #include + #include + ++static bool digital_gain_0db_limit = true; ++ + static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) + { +- int ret; +- struct snd_soc_card *card = rtd->card; +- struct snd_soc_codec *codec = rtd->codec; +- +- ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); +- if (ret < 0) +- dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ if (digital_gain_0db_limit) ++ { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } + + return 0; + } +@@ -95,6 +100,9 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) + dai->platform_name = NULL; + dai->platform_of_node = i2s_node; + } ++ ++ digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node, ++ "iqaudio,24db_digital_gain"); + } + + ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); + +From e1e2fab9e43a933c6efc8d28350064d2cba1a010 Mon Sep 17 00:00:00 2001 +From: Digital Dreamtime +Date: Thu, 4 Feb 2016 20:04:00 +0000 +Subject: [PATCH 262/278] Limit PCM512x "Digital" gain to 0dB by default with + HiFiBerry DAC+ + +24db_digital_gain DT param can be used to specify that PCM512x +codec "Digital" volume control should not be limited to 0dB gain, +and if specified will allow the full 24dB gain. +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++++++++-- + .../arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 6 +++++- + sound/soc/bcm/hifiberry_dacplus.c | 15 +++++++++++++++ + 3 files changed, 35 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 7f1ef9b..3f7a25d 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -252,8 +252,21 @@ Params: + + Name: hifiberry-dacplus + Info: Configures the HifiBerry DAC+ audio card +-Load: dtoverlay=hifiberry-dacplus +-Params: ++Load: dtoverlay=hifiberry-dacplus,= ++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: hifiberry-digi +diff --git a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +index f923a48..42a0194 100644 +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -17,7 +17,7 @@ + + fragment@1 { + target = <&sound>; +- __overlay__ { ++ frag1: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; + i2s-controller = <&i2s>; + status = "okay"; +@@ -47,4 +47,8 @@ + }; + }; + }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag1>,"hifiberry,24db_digital_gain?"; ++ }; + }; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index a6b651c..50b66a1 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -48,6 +48,7 @@ struct pcm512x_priv { + #define CLK_48EN_RATE 24576000UL + + static bool snd_rpi_hifiberry_is_dacpro; ++static bool digital_gain_0db_limit = true; + + static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_codec *codec, + int clk_id) +@@ -167,6 +168,17 @@ static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd) + snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); + snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + ++ if (digital_gain_0db_limit) ++ { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ + return 0; + } + +@@ -299,6 +311,9 @@ static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev) + dai->platform_name = NULL; + dai->platform_of_node = i2s_node; + } ++ ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "hifiberry,24db_digital_gain"); + } + + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus); + +From 0361429f25d77226e1e254f67bc06cd2537fa094 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 9 Feb 2016 09:52:13 +0000 +Subject: [PATCH 263/278] pinctrl-bcm2835: Fix cut-and-paste error in "pull" + parsing + +The DT bindings for pinctrl-bcm2835 allow both the function and pull +to contain either one entry or one per pin. However, an error in the +DT parsing can cause failures if the number of pulls differs from the +number of functions. +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +index 61ef002..5821f46 100644 +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -818,7 +818,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + } + if (num_pulls) { + err = of_property_read_u32_index(np, "brcm,pull", +- (num_funcs > 1) ? i : 0, &pull); ++ (num_pulls > 1) ? i : 0, &pull); + if (err) + goto out; + err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin, + +From 699dc6932548e83d9a52bed5e8bf17233cc14d30 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 11 Feb 2016 15:25:17 +0000 +Subject: [PATCH 264/278] bcm2835-sdhost: Major revision + +This is a significant revision of the bcm2835-sdhost driver. It +improves on the original in a number of ways: + +1) Through the use of CMD23 for reads it appears to avoid problems + reading some sectors on certain high speed cards. +2) Better atomicity to prevent crashes. +3) Higher performance. +4) Activity logging included, for easier diagnosis in the event + of a problem. +--- + drivers/mmc/host/bcm2835-sdhost.c | 1263 ++++++++++++++++++++----------------- + 1 file changed, 696 insertions(+), 567 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 44d61c3..84d120f 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -2,7 +2,7 @@ + * BCM2835 SD host driver. + * + * Author: Phil Elwell +- * Copyright 2015 ++ * Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd. + * + * Based on + * mmc-bcm2835.c by Gellert Weisz +@@ -24,12 +24,13 @@ + * along with this program. If not, see . + */ + +-#define SAFE_READ_THRESHOLD 4 +-#define SAFE_WRITE_THRESHOLD 4 +-#define ALLOW_DMA 1 +-#define ALLOW_CMD23 0 +-#define ALLOW_FAST 1 +-#define USE_BLOCK_IRQ 1 ++#define FIFO_READ_THRESHOLD 4 ++#define FIFO_WRITE_THRESHOLD 4 ++#define ALLOW_CMD23_READ 1 ++#define ALLOW_CMD23_WRITE 0 ++#define ENABLE_LOG 1 ++#define SDDATA_FIFO_PIO_BURST 8 ++#define CMD_DALLY_US 1 + + #include + #include +@@ -48,6 +49,7 @@ + #include + #include + #include ++#include + + #define DRIVER_NAME "sdhost-bcm2835" + +@@ -110,6 +112,28 @@ + #define SDEDM_READ_THRESHOLD_SHIFT 14 + #define SDEDM_THRESHOLD_MASK 0x1f + ++#define SDEDM_FSM_MASK 0xf ++#define SDEDM_FSM_IDENTMODE 0x0 ++#define SDEDM_FSM_DATAMODE 0x1 ++#define SDEDM_FSM_READDATA 0x2 ++#define SDEDM_FSM_WRITEDATA 0x3 ++#define SDEDM_FSM_READWAIT 0x4 ++#define SDEDM_FSM_READCRC 0x5 ++#define SDEDM_FSM_WRITECRC 0x6 ++#define SDEDM_FSM_WRITEWAIT1 0x7 ++#define SDEDM_FSM_POWERDOWN 0x8 ++#define SDEDM_FSM_POWERUP 0x9 ++#define SDEDM_FSM_WRITESTART1 0xa ++#define SDEDM_FSM_WRITESTART2 0xb ++#define SDEDM_FSM_GENPULSES 0xc ++#define SDEDM_FSM_WRITEWAIT2 0xd ++#define SDEDM_FSM_STARTPOWDOWN 0xf ++ ++#define SDDATA_FIFO_WORDS 16 ++ ++#define USE_CMD23_FLAGS ((ALLOW_CMD23_READ * MMC_DATA_READ) | \ ++ (ALLOW_CMD23_WRITE * MMC_DATA_WRITE)) ++ + #define MHZ 1000000 + + #ifndef BCM2708_PERI_BASE +@@ -138,15 +162,17 @@ struct bcm2835_host { + + struct tasklet_struct finish_tasklet; /* Tasklet structures */ + +- struct timer_list timer; /* Timer for timeouts */ ++ struct work_struct cmd_wait_wq; /* Workqueue function */ + +- struct timer_list pio_timer; /* PIO error detection timer */ ++ struct timer_list timer; /* Timer for timeouts */ + + struct sg_mapping_iter sg_miter; /* SG state for PIO */ + unsigned int blocks; /* remaining PIO blocks */ + + int irq; /* Device IRQ */ + ++ u32 cmd_quick_poll_retries; ++ u32 ns_per_fifo_word; + + /* cached registers */ + u32 hcfg; +@@ -161,16 +187,21 @@ struct bcm2835_host { + + unsigned int use_busy:1; /* Wait for busy interrupt */ + +- unsigned int debug:1; /* Enable debug output */ ++ unsigned int use_sbc:1; /* Send CMD23 */ + +- u32 thread_isr; ++ unsigned int debug:1; /* Enable debug output */ + + /*DMA part*/ + struct dma_chan *dma_chan_rx; /* DMA channel for reads */ + struct dma_chan *dma_chan_tx; /* DMA channel for writes */ ++ struct dma_chan *dma_chan; /* Channel in used */ ++ struct dma_async_tx_descriptor *dma_desc; ++ u32 dma_dir; ++ u32 drain_words; ++ struct page *drain_page; ++ u32 drain_offset; + + bool allow_dma; +- bool have_dma; + bool use_dma; + /*end of DMA part*/ + +@@ -182,6 +213,96 @@ struct bcm2835_host { + u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */ + }; + ++#if ENABLE_LOG ++ ++struct log_entry_struct { ++ char event[4]; ++ u32 timestamp; ++ u32 param1; ++ u32 param2; ++}; ++ ++typedef struct log_entry_struct LOG_ENTRY_T; ++ ++LOG_ENTRY_T *sdhost_log_buf; ++dma_addr_t sdhost_log_addr; ++static u32 sdhost_log_idx; ++static spinlock_t log_lock; ++static void __iomem *timer_base; ++ ++#define LOG_ENTRIES (256*1) ++#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES) ++ ++static void log_init(void) ++{ ++ spin_lock_init(&log_lock); ++ sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr, ++ GFP_KERNEL); ++ if (sdhost_log_buf) { ++ pr_err("sdhost: log_buf @ %p (%x)\n", ++ sdhost_log_buf, sdhost_log_addr); ++ timer_base = ioremap_nocache(BCM2708_PERI_BASE + 0x3000, SZ_4K); ++ if (!timer_base) ++ pr_err("sdhost: failed to remap timer\n"); ++ } ++ else ++ pr_err("sdhost: failed to allocate log buf\n"); ++} ++ ++static void log_event_impl(const char *event, u32 param1, u32 param2) ++{ ++ if (sdhost_log_buf) { ++ LOG_ENTRY_T *entry; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&log_lock, flags); ++ ++ entry = sdhost_log_buf + sdhost_log_idx; ++ memcpy(entry->event, event, 4); ++ entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) + ++ (smp_processor_id()<<30); ++ entry->param1 = param1; ++ entry->param2 = param2; ++ sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES; ++ ++ spin_unlock_irqrestore(&log_lock, flags); ++ } ++} ++ ++static void log_dump(void) ++{ ++ if (sdhost_log_buf) { ++ LOG_ENTRY_T *entry; ++ unsigned long flags; ++ int idx; ++ ++ spin_lock_irqsave(&log_lock, flags); ++ ++ idx = sdhost_log_idx; ++ do { ++ entry = sdhost_log_buf + idx; ++ if (entry->event[0] != '\0') ++ pr_err("[%08x] %.4s %x %x\n", ++ entry->timestamp, ++ entry->event, ++ entry->param1, ++ entry->param2); ++ idx = (idx + 1) % LOG_ENTRIES; ++ } while (idx != sdhost_log_idx); ++ ++ spin_unlock_irqrestore(&log_lock, flags); ++ } ++} ++ ++#define log_event(event, param1, param2) log_event_impl(event, param1, param2) ++ ++#else ++ ++#define log_init() (void)0 ++#define log_event(event, param1, param2) (void)0 ++#define log_dump() (void)0 ++ ++#endif + + static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg) + { +@@ -203,7 +324,7 @@ static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host, + const char *label) + { + if (cmd) +- pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n", ++ pr_err("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n", + mmc_hostname(host->mmc), + (cmd == host->cmd) ? '>' : ' ', + label, cmd->opcode, cmd->arg, cmd->flags, +@@ -213,77 +334,81 @@ static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host, + + static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host) + { +- bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc"); +- bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd"); +- if (host->mrq->data) +- pr_err("%s: data blocks %x blksz %x - err %d\n", +- mmc_hostname(host->mmc), +- host->mrq->data->blocks, +- host->mrq->data->blksz, +- host->mrq->data->error); +- bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop"); ++ if (host->mrq) ++ { ++ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc"); ++ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd"); ++ if (host->mrq->data) ++ pr_err("%s: data blocks %x blksz %x - err %d\n", ++ mmc_hostname(host->mmc), ++ host->mrq->data->blocks, ++ host->mrq->data->blksz, ++ host->mrq->data->error); ++ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop"); ++ } + +- pr_info("%s: =========== REGISTER DUMP ===========\n", ++ pr_err("%s: =========== REGISTER DUMP ===========\n", + mmc_hostname(host->mmc)); + +- pr_info("%s: SDCMD 0x%08x\n", ++ pr_err("%s: SDCMD 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDCMD)); +- pr_info("%s: SDARG 0x%08x\n", ++ pr_err("%s: SDARG 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDARG)); +- pr_info("%s: SDTOUT 0x%08x\n", ++ pr_err("%s: SDTOUT 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDTOUT)); +- pr_info("%s: SDCDIV 0x%08x\n", ++ pr_err("%s: SDCDIV 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDCDIV)); +- pr_info("%s: SDRSP0 0x%08x\n", ++ pr_err("%s: SDRSP0 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP0)); +- pr_info("%s: SDRSP1 0x%08x\n", ++ pr_err("%s: SDRSP1 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP1)); +- pr_info("%s: SDRSP2 0x%08x\n", ++ pr_err("%s: SDRSP2 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP2)); +- pr_info("%s: SDRSP3 0x%08x\n", ++ pr_err("%s: SDRSP3 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDRSP3)); +- pr_info("%s: SDHSTS 0x%08x\n", ++ pr_err("%s: SDHSTS 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHSTS)); +- pr_info("%s: SDVDD 0x%08x\n", ++ pr_err("%s: SDVDD 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDVDD)); +- pr_info("%s: SDEDM 0x%08x\n", ++ pr_err("%s: SDEDM 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDEDM)); +- pr_info("%s: SDHCFG 0x%08x\n", ++ pr_err("%s: SDHCFG 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHCFG)); +- pr_info("%s: SDHBCT 0x%08x\n", ++ pr_err("%s: SDHBCT 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHBCT)); +- pr_info("%s: SDHBLC 0x%08x\n", ++ pr_err("%s: SDHBLC 0x%08x\n", + mmc_hostname(host->mmc), + bcm2835_sdhost_read(host, SDHBLC)); + +- pr_info("%s: ===========================================\n", ++ pr_err("%s: ===========================================\n", + mmc_hostname(host->mmc)); + } + +- + static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on) + { + bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD); + } + +- + static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host) + { + u32 temp; + ++ if (host->debug) ++ pr_info("%s: reset\n", mmc_hostname(host->mmc)); ++ + bcm2835_sdhost_set_power(host, false); + + bcm2835_sdhost_write(host, 0, SDCMD); +@@ -299,8 +424,8 @@ static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host) + temp = bcm2835_sdhost_read(host, SDEDM); + temp &= ~((SDEDM_THRESHOLD_MASK<debug) +- pr_info("%s: reset\n", mmc_hostname(mmc)); + spin_lock_irqsave(&host->lock, flags); ++ log_event("RST<", 0, 0); + + bcm2835_sdhost_reset_internal(host); + +@@ -343,82 +466,48 @@ static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft) + } + } + +-static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host) ++static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host) + { +- bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1); +- +- if (!write_complete) { +- /* Request an IRQ for the last block */ +- host->hcfg |= SDHCFG_BLOCK_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) { +- /* The write has now completed. Disable the interrupt +- and clear the status flag */ +- host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS); +- write_complete = true; +- } +- } ++ int timediff; ++ u32 alternate_idle; ++ u32 edm; + +- return write_complete; +-} ++ alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ? ++ SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1; + +-static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host) +-{ +- int timediff; +-#ifdef DEBUG +- static struct timeval start_time; +- static int max_stall_time = 0; +- static int total_stall_time = 0; +- struct timeval before, after; ++ edm = bcm2835_sdhost_read(host, SDEDM); + +- do_gettimeofday(&before); +- if (max_stall_time == 0) +- start_time = before; +-#endif ++ log_event("WTC<", edm, 0); + + timediff = 0; + + while (1) { +- u32 edm = bcm2835_sdhost_read(host, SDEDM); +- if ((edm & 0xf) == 1) ++ u32 fsm = edm & SDEDM_FSM_MASK; ++ if ((fsm == SDEDM_FSM_IDENTMODE) || ++ (fsm == SDEDM_FSM_DATAMODE)) + break; +- timediff++; +- if (timediff > 5000000) { +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + +- (after.tv_usec - before.tv_usec); ++ if (fsm == alternate_idle) { ++ bcm2835_sdhost_write(host, ++ edm | SDEDM_FORCE_DATA_MODE, ++ SDEDM); ++ break; ++ } + +- pr_err(" wait_write_complete - still waiting after %dus\n", +- timediff); +-#else +- pr_err(" wait_write_complete - still waiting after %d retries\n", ++ timediff++; ++ if (timediff == 100000) { ++ pr_err("%s: wait_transfer_complete - still waiting after %d retries\n", ++ mmc_hostname(host->mmc), + timediff); +-#endif ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- host->data->error = -ETIMEDOUT; ++ host->mrq->data->error = -ETIMEDOUT; ++ log_event("WTC!", edm, 0); + return; + } ++ cpu_relax(); ++ edm = bcm2835_sdhost_read(host, SDEDM); + } +- +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec); +- +- total_stall_time += timediff; +- if (timediff > max_stall_time) +- max_stall_time = timediff; +- +- if ((after.tv_sec - start_time.tv_sec) > 10) { +- pr_debug(" wait_write_complete - max wait %dus, total %dus\n", +- max_stall_time, total_stall_time); +- start_time = after; +- max_stall_time = 0; +- total_stall_time = 0; +- } +-#endif ++ log_event("WTC>", edm, 0); + } + + static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); +@@ -426,65 +515,44 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host); + static void bcm2835_sdhost_dma_complete(void *param) + { + struct bcm2835_host *host = param; +- struct dma_chan *dma_chan; ++ struct mmc_data *data = host->data; + unsigned long flags; +- u32 dir_data; + + spin_lock_irqsave(&host->lock, flags); ++ log_event("DMA<", (u32)host->data, bcm2835_sdhost_read(host, SDHSTS)); ++ log_event("DMA ", bcm2835_sdhost_read(host, SDCMD), ++ bcm2835_sdhost_read(host, SDEDM)); + +- if (host->data) { +- bool write_complete; +- if (USE_BLOCK_IRQ) +- write_complete = bcm2835_sdhost_is_write_complete(host); +- else { +- bcm2835_sdhost_wait_write_complete(host); +- write_complete = true; +- } +- pr_debug("dma_complete() - write_complete=%d\n", +- write_complete); +- +- if (write_complete || (host->data->flags & MMC_DATA_READ)) +- { +- if (write_complete) { +- dma_chan = host->dma_chan_tx; +- dir_data = DMA_TO_DEVICE; +- } else { +- dma_chan = host->dma_chan_rx; +- dir_data = DMA_FROM_DEVICE; +- } ++ if (host->dma_chan) { ++ dma_unmap_sg(host->dma_chan->device->dev, ++ data->sg, data->sg_len, ++ host->dma_dir); + +- dma_unmap_sg(dma_chan->device->dev, +- host->data->sg, host->data->sg_len, +- dir_data); +- +- bcm2835_sdhost_finish_data(host); +- } ++ host->dma_chan = NULL; + } + +- spin_unlock_irqrestore(&host->lock, flags); +-} ++ if (host->drain_words) { ++ void *page; ++ u32 *buf; + +-static bool data_transfer_wait(struct bcm2835_host *host) +-{ +- unsigned long timeout = 1000000; +- while (timeout) +- { +- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); +- if (sdhsts & SDHSTS_DATA_FLAG) { +- bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS); +- break; ++ page = kmap_atomic(host->drain_page); ++ buf = page + host->drain_offset; ++ ++ while (host->drain_words) { ++ u32 edm = bcm2835_sdhost_read(host, SDEDM); ++ if ((edm >> 4) & 0x1f) ++ *(buf++) = bcm2835_sdhost_read(host, ++ SDDATA); ++ host->drain_words--; + } +- timeout--; +- } +- if (timeout == 0) { +- pr_err("%s: Data %s timeout\n", +- mmc_hostname(host->mmc), +- (host->data->flags & MMC_DATA_READ) ? "read" : "write"); +- bcm2835_sdhost_dumpregs(host); +- host->data->error = -ETIMEDOUT; +- return false; ++ ++ kunmap_atomic(page); + } +- return true; ++ ++ bcm2835_sdhost_finish_data(host); ++ ++ log_event("DMA>", (u32)host->data, 0); ++ spin_unlock_irqrestore(&host->lock, flags); + } + + static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) +@@ -492,32 +560,83 @@ static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) + unsigned long flags; + size_t blksize, len; + u32 *buf; ++ unsigned long wait_max; + + blksize = host->data->blksz; + ++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout); ++ + local_irq_save(flags); + + while (blksize) { +- if (!sg_miter_next(&host->sg_miter)) +- BUG(); ++ int copy_words; ++ u32 hsts = 0; ++ ++ if (!sg_miter_next(&host->sg_miter)) { ++ host->data->error = -EINVAL; ++ break; ++ } + + len = min(host->sg_miter.length, blksize); +- BUG_ON(len % 4); ++ if (len % 4) { ++ host->data->error = -EINVAL; ++ break; ++ } + + blksize -= len; + host->sg_miter.consumed = len; + + buf = (u32 *)host->sg_miter.addr; + +- while (len) { +- if (!data_transfer_wait(host)) +- break; ++ copy_words = len/4; ++ ++ while (copy_words) { ++ int burst_words, words; ++ u32 edm; ++ ++ burst_words = SDDATA_FIFO_PIO_BURST; ++ if (burst_words > copy_words) ++ burst_words = copy_words; ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ words = ((edm >> 4) & 0x1f); ++ ++ if (words < burst_words) { ++ int fsm_state = (edm & SDEDM_FSM_MASK); ++ if ((fsm_state != SDEDM_FSM_READDATA) && ++ (fsm_state != SDEDM_FSM_READWAIT) && ++ (fsm_state != SDEDM_FSM_READCRC)) { ++ hsts = bcm2835_sdhost_read(host, ++ SDHSTS); ++ pr_err("%s: fsm %x, hsts %x\n", ++ mmc_hostname(host->mmc), ++ fsm_state, hsts); ++ if (hsts & SDHSTS_ERROR_MASK) ++ break; ++ } ++ ++ if (time_after(jiffies, wait_max)) { ++ pr_err("%s: PIO read timeout - EDM %x\n", ++ mmc_hostname(host->mmc), ++ edm); ++ hsts = SDHSTS_REW_TIME_OUT; ++ break; ++ } ++ ndelay((burst_words - words) * ++ host->ns_per_fifo_word); ++ continue; ++ } else if (words > copy_words) { ++ words = copy_words; ++ } + +- *(buf++) = bcm2835_sdhost_read(host, SDDATA); +- len -= 4; ++ copy_words -= words; ++ ++ while (words) { ++ *(buf++) = bcm2835_sdhost_read(host, SDDATA); ++ words--; ++ } + } + +- if (host->data->error) ++ if (hsts & SDHSTS_ERROR_MASK) + break; + } + +@@ -531,32 +650,83 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) + unsigned long flags; + size_t blksize, len; + u32 *buf; ++ unsigned long wait_max; + + blksize = host->data->blksz; + ++ wait_max = jiffies + msecs_to_jiffies(host->pio_timeout); ++ + local_irq_save(flags); + + while (blksize) { +- if (!sg_miter_next(&host->sg_miter)) +- BUG(); ++ int copy_words; ++ u32 hsts = 0; ++ ++ if (!sg_miter_next(&host->sg_miter)) { ++ host->data->error = -EINVAL; ++ break; ++ } + + len = min(host->sg_miter.length, blksize); +- BUG_ON(len % 4); ++ if (len % 4) { ++ host->data->error = -EINVAL; ++ break; ++ } + + blksize -= len; + host->sg_miter.consumed = len; + +- buf = host->sg_miter.addr; ++ buf = (u32 *)host->sg_miter.addr; + +- while (len) { +- if (!data_transfer_wait(host)) +- break; ++ copy_words = len/4; ++ ++ while (copy_words) { ++ int burst_words, words; ++ u32 edm; ++ ++ burst_words = SDDATA_FIFO_PIO_BURST; ++ if (burst_words > copy_words) ++ burst_words = copy_words; ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f); ++ ++ if (words < burst_words) { ++ int fsm_state = (edm & SDEDM_FSM_MASK); ++ if ((fsm_state != SDEDM_FSM_WRITEDATA) && ++ (fsm_state != SDEDM_FSM_WRITESTART1) && ++ (fsm_state != SDEDM_FSM_WRITESTART2)) { ++ hsts = bcm2835_sdhost_read(host, ++ SDHSTS); ++ pr_err("%s: fsm %x, hsts %x\n", ++ mmc_hostname(host->mmc), ++ fsm_state, hsts); ++ if (hsts & SDHSTS_ERROR_MASK) ++ break; ++ } + +- bcm2835_sdhost_write(host, *(buf++), SDDATA); +- len -= 4; ++ if (time_after(jiffies, wait_max)) { ++ pr_err("%s: PIO write timeout - EDM %x\n", ++ mmc_hostname(host->mmc), ++ edm); ++ hsts = SDHSTS_REW_TIME_OUT; ++ break; ++ } ++ ndelay((burst_words - words) * ++ host->ns_per_fifo_word); ++ continue; ++ } else if (words > copy_words) { ++ words = copy_words; ++ } ++ ++ copy_words -= words; ++ ++ while (words) { ++ bcm2835_sdhost_write(host, *(buf++), SDDATA); ++ words--; ++ } + } + +- if (host->data->error) ++ if (hsts & SDHSTS_ERROR_MASK) + break; + } + +@@ -565,12 +735,12 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host) + local_irq_restore(flags); + } + +- + static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) + { + u32 sdhsts; + bool is_read; + BUG_ON(!host->data); ++ log_event("XFP<", (u32)host->data, host->blocks); + + is_read = (host->data->flags & MMC_DATA_READ) != 0; + if (is_read) +@@ -594,28 +764,21 @@ static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host) + is_read ? "read" : "write", + sdhsts); + host->data->error = -ETIMEDOUT; +- } else if (!is_read && !host->data->error) { +- /* Start a timer in case a transfer error occurs because +- there is no error interrupt */ +- mod_timer(&host->pio_timer, jiffies + host->pio_timeout); + } ++ log_event("XFP>", (u32)host->data, host->blocks); + } + +- +-static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) ++static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host, ++ struct mmc_data *data) + { +- u32 len, dir_data, dir_slave; ++ int len, dir_data, dir_slave; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *dma_chan; + +- pr_debug("bcm2835_sdhost_transfer_dma()\n"); +- +- WARN_ON(!host->data); ++ log_event("PRD<", (u32)data, 0); ++ pr_debug("bcm2835_sdhost_prepare_dma()\n"); + +- if (!host->data) +- return; +- +- if (host->data->flags & MMC_DATA_READ) { ++ if (data->flags & MMC_DATA_READ) { + dma_chan = host->dma_chan_rx; + dir_data = DMA_FROM_DEVICE; + dir_slave = DMA_DEV_TO_MEM; +@@ -624,35 +787,71 @@ static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host) + dir_data = DMA_TO_DEVICE; + dir_slave = DMA_MEM_TO_DEV; + } ++ log_event("PRD1", (u32)dma_chan, 0); + + BUG_ON(!dma_chan->device); + BUG_ON(!dma_chan->device->dev); +- BUG_ON(!host->data->sg); ++ BUG_ON(!data->sg); ++ ++ /* The block doesn't manage the FIFO DREQs properly for multi-block ++ transfers, so don't attempt to DMA the final few words. ++ Unfortunately this requires the final sg entry to be trimmed. ++ N.B. This code demands that the overspill is contained in ++ a single sg entry. ++ */ ++ ++ host->drain_words = 0; ++ if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) { ++ struct scatterlist *sg; ++ u32 len; ++ int i; ++ ++ len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4, ++ (u32)data->blocks * data->blksz); ++ ++ for_each_sg(data->sg, sg, data->sg_len, i) { ++ if (sg_is_last(sg)) { ++ BUG_ON(sg->length < len); ++ sg->length -= len; ++ host->drain_page = (struct page *)sg->page_link; ++ host->drain_offset = sg->offset + sg->length; ++ } ++ } ++ host->drain_words = len/4; ++ } ++ ++ len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len, ++ dir_data); + +- len = dma_map_sg(dma_chan->device->dev, host->data->sg, +- host->data->sg_len, dir_data); +- if (len > 0) { +- desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg, ++ log_event("PRD2", len, 0); ++ if (len > 0) ++ desc = dmaengine_prep_slave_sg(dma_chan, data->sg, + len, dir_slave, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +- } else { +- dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); +- } ++ log_event("PRD3", (u32)desc, 0); ++ + if (desc) { + desc->callback = bcm2835_sdhost_dma_complete; + desc->callback_param = host; +- dmaengine_submit(desc); +- dma_async_issue_pending(dma_chan); ++ host->dma_desc = desc; ++ host->dma_chan = dma_chan; ++ host->dma_dir = dir_data; + } +- ++ log_event("PDM>", (u32)data, 0); + } + ++static void bcm2835_sdhost_start_dma(struct bcm2835_host *host) ++{ ++ log_event("SDMA", (u32)host->data, (u32)host->dma_chan); ++ dmaengine_submit(host->dma_desc); ++ dma_async_issue_pending(host->dma_chan); ++} + + static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) + { + u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | + SDHCFG_BUSY_IRPT_EN; +- if (host->use_dma) ++ if (host->dma_desc) + host->hcfg = (host->hcfg & ~all_irqs) | + SDHCFG_BUSY_IRPT_EN; + else +@@ -663,13 +862,13 @@ static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host) + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + } + +- + static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd) + { + struct mmc_data *data = cmd->data; + + WARN_ON(host->data); + ++ host->data = data; + if (!data) + return; + +@@ -678,20 +877,19 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > 65535); + +- host->data = data; + host->data_complete = 0; + host->flush_fifo = 0; + host->data->bytes_xfered = 0; + +- host->use_dma = host->have_dma && (data->blocks > host->pio_limit); +- if (!host->use_dma) { ++ ++ if (!host->dma_desc) { ++ /* Use PIO */ + int flags; + +- flags = SG_MITER_ATOMIC; + if (data->flags & MMC_DATA_READ) +- flags |= SG_MITER_TO_SG; ++ flags = SG_MITER_TO_SG; + else +- flags |= SG_MITER_FROM_SG; ++ flags = SG_MITER_FROM_SG; + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); + host->blocks = data->blocks; + } +@@ -699,19 +897,20 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + bcm2835_sdhost_set_transfer_irqs(host); + + bcm2835_sdhost_write(host, data->blksz, SDHBCT); +- bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC); ++ bcm2835_sdhost_write(host, data->blocks, SDHBLC); + + BUG_ON(!host->data); + } + +- +-void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd) ++bool bcm2835_sdhost_send_command(struct bcm2835_host *host, ++ struct mmc_command *cmd) + { + u32 sdcmd, sdhsts; + unsigned long timeout; + int delay; + + WARN_ON(host->cmd); ++ log_event("CMD<", cmd->opcode, cmd->arg); + + if (cmd->data) + pr_debug("%s: send_command %d 0x%x " +@@ -734,9 +933,9 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + pr_err("%s: previous command never completed.\n", + mmc_hostname(host->mmc)); + bcm2835_sdhost_dumpregs(host); +- cmd->error = -EIO; ++ cmd->error = -EILSEQ; + tasklet_schedule(&host->finish_tasklet); +- return; ++ return false; + } + timeout--; + udelay(10); +@@ -764,23 +963,24 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + if (sdhsts & SDHSTS_ERROR_MASK) + bcm2835_sdhost_write(host, sdhsts, SDHSTS); + +- bcm2835_sdhost_prepare_data(host, cmd); +- +- bcm2835_sdhost_write(host, cmd->arg, SDARG); +- + if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { + pr_err("%s: unsupported response type!\n", + mmc_hostname(host->mmc)); + cmd->error = -EINVAL; + tasklet_schedule(&host->finish_tasklet); +- return; ++ return false; + } + ++ bcm2835_sdhost_prepare_data(host, cmd); ++ ++ bcm2835_sdhost_write(host, cmd->arg, SDARG); ++ + sdcmd = cmd->opcode & SDCMD_CMD_MASK; + +- if (!(cmd->flags & MMC_RSP_PRESENT)) ++ host->use_busy = 0; ++ if (!(cmd->flags & MMC_RSP_PRESENT)) { + sdcmd |= SDCMD_NO_RESPONSE; +- else { ++ } else { + if (cmd->flags & MMC_RSP_136) + sdcmd |= SDCMD_LONG_RESPONSE; + if (cmd->flags & MMC_RSP_BUSY) { +@@ -790,6 +990,7 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + } + + if (cmd->data) { ++ log_event("CMDD", cmd->data->blocks, cmd->data->blksz); + if (host->delay_after_stop) { + struct timeval now; + int time_since_stop; +@@ -812,10 +1013,12 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command * + } + + bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD); +-} + ++ return true; ++} + +-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host); ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host, ++ unsigned long *irq_flags); + static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host); + + static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) +@@ -825,6 +1028,7 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + data = host->data; + BUG_ON(!data); + ++ log_event("FDA<", (u32)host->mrq, (u32)host->cmd); + pr_debug("finish_data(error %d, stop %d, sbc %d)\n", + data->error, data->stop ? 1 : 0, + host->mrq->sbc ? 1 : 0); +@@ -832,10 +1036,7 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); + +- if (data->error) { +- data->bytes_xfered = 0; +- } else +- data->bytes_xfered = data->blksz * data->blocks; ++ data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks); + + host->data_complete = 1; + +@@ -850,9 +1051,9 @@ static void bcm2835_sdhost_finish_data(struct bcm2835_host *host) + } + else + bcm2835_sdhost_transfer_complete(host); ++ log_event("FDA>", (u32)host->mrq, (u32)host->cmd); + } + +- + static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + { + struct mmc_data *data; +@@ -864,6 +1065,7 @@ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + data = host->data; + host->data = NULL; + ++ log_event("TCM<", (u32)data, data->error); + pr_debug("transfer_complete(error %d, stop %d)\n", + data->error, data->stop ? 1 : 0); + +@@ -872,88 +1074,114 @@ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host) + * a) open-ended multiblock transfer (no CMD23) + * b) error in multiblock transfer + */ +- if (data->stop && +- (data->error || +- !host->mrq->sbc)) { +- host->flush_fifo = 1; +- bcm2835_sdhost_send_command(host, data->stop); +- if (host->delay_after_stop) +- do_gettimeofday(&host->stop_time); +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); ++ if (host->mrq->stop && (data->error || !host->use_sbc)) { ++ if (bcm2835_sdhost_send_command(host, host->mrq->stop)) { ++ /* No busy, so poll for completion */ ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, NULL); ++ ++ if (host->delay_after_stop) ++ do_gettimeofday(&host->stop_time); ++ } + } else { ++ bcm2835_sdhost_wait_transfer_complete(host); + tasklet_schedule(&host->finish_tasklet); + } ++ log_event("TCM>", (u32)data, 0); + } + +-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) ++/* If irq_flags is valid, the caller is in a thread context and is allowed ++ to sleep */ ++static void bcm2835_sdhost_finish_command(struct bcm2835_host *host, ++ unsigned long *irq_flags) + { + u32 sdcmd; +- unsigned long timeout; ++ u32 retries; + #ifdef DEBUG + struct timeval before, after; + int timediff = 0; + #endif + ++ log_event("FCM<", (u32)host->mrq, (u32)host->cmd); + pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD)); + + BUG_ON(!host->cmd || !host->mrq); + +-#ifdef DEBUG +- do_gettimeofday(&before); +-#endif +- /* Wait max 100 ms */ +- timeout = 10000; ++ /* Poll quickly at first */ ++ ++ retries = host->cmd_quick_poll_retries; ++ if (!retries) { ++ /* Work out how many polls take 1us by timing 10us */ ++ struct timeval start, now; ++ int us_diff; ++ ++ retries = 1; ++ do { ++ int i; ++ ++ retries *= 2; ++ ++ do_gettimeofday(&start); ++ ++ for (i = 0; i < retries; i++) { ++ cpu_relax(); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ } ++ ++ do_gettimeofday(&now); ++ us_diff = (now.tv_sec - start.tv_sec) * 1000000 + ++ (now.tv_usec - start.tv_usec); ++ } while (us_diff < 10); ++ ++ host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1; ++ retries = 1; // We've already waited long enough this time ++ } ++ ++ retries = host->cmd_quick_poll_retries; + for (sdcmd = bcm2835_sdhost_read(host, SDCMD); +- (sdcmd & SDCMD_NEW_FLAG) && timeout; +- timeout--) { +- if (host->flush_fifo) { +- while (bcm2835_sdhost_read(host, SDHSTS) & +- SDHSTS_DATA_FLAG) +- (void)bcm2835_sdhost_read(host, SDDATA); +- } +- udelay(10); ++ (sdcmd & SDCMD_NEW_FLAG) && !(sdcmd & SDCMD_FAIL_FLAG) && retries; ++ retries--) { ++ cpu_relax(); + sdcmd = bcm2835_sdhost_read(host, SDCMD); + } +-#ifdef DEBUG +- do_gettimeofday(&after); +- timediff = (after.tv_sec - before.tv_sec)*1000000 + +- (after.tv_usec - before.tv_usec); + +- pr_debug(" finish_command - waited %dus\n", timediff); +-#endif ++ if (!retries) { ++ unsigned long wait_max; ++ ++ if (!irq_flags) { ++ /* Schedule the work */ ++ log_event("CWWQ", 0, 0); ++ schedule_work(&host->cmd_wait_wq); ++ return; ++ } ++ ++ /* Wait max 100 ms */ ++ wait_max = jiffies + msecs_to_jiffies(100); ++ while (time_before(jiffies, wait_max)) { ++ spin_unlock_irqrestore(&host->lock, *irq_flags); ++ usleep_range(1, 10); ++ spin_lock_irqsave(&host->lock, *irq_flags); ++ sdcmd = bcm2835_sdhost_read(host, SDCMD); ++ if (!(sdcmd & SDCMD_NEW_FLAG) || ++ (sdcmd & SDCMD_FAIL_FLAG)) ++ break; ++ } ++ } + +- if (timeout == 0) { ++ /* Check for errors */ ++ if (sdcmd & SDCMD_NEW_FLAG) { + pr_err("%s: command never completed.\n", + mmc_hostname(host->mmc)); + bcm2835_sdhost_dumpregs(host); + host->cmd->error = -EIO; + tasklet_schedule(&host->finish_tasklet); + return; +- } +- +- if (host->flush_fifo) { +- for (timeout = 100; +- (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout; +- timeout--) { +- (void)bcm2835_sdhost_read(host, SDDATA); +- } +- host->flush_fifo = 0; +- if (timeout == 0) { +- pr_err("%s: FIFO never drained.\n", +- mmc_hostname(host->mmc)); +- bcm2835_sdhost_dumpregs(host); +- host->cmd->error = -EIO; +- tasklet_schedule(&host->finish_tasklet); +- return; +- } +- } +- +- /* Check for errors */ +- if (sdcmd & SDCMD_FAIL_FLAG) +- { ++ } else if (sdcmd & SDCMD_FAIL_FLAG) { + u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); + ++ /* Clear the errors */ ++ bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS); ++ + if (host->debug) + pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", + mmc_hostname(host->mmc), sdcmd, sdhsts, +@@ -976,7 +1204,7 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + mmc_hostname(host->mmc), + host->cmd->opcode); + bcm2835_sdhost_dumpregs(host); +- host->cmd->error = -EIO; ++ host->cmd->error = -EILSEQ; + } + tasklet_schedule(&host->finish_tasklet); + return; +@@ -991,31 +1219,31 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + pr_debug("%s: finish_command %08x %08x %08x %08x\n", + mmc_hostname(host->mmc), + host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]); ++ log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]); + } else { + host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0); + pr_debug("%s: finish_command %08x\n", + mmc_hostname(host->mmc), + host->cmd->resp[0]); ++ log_event("RSP ", host->cmd->resp[0], 0); + } + } + +- host->cmd->error = 0; +- + if (host->cmd == host->mrq->sbc) { + /* Finished CMD23, now send actual command. */ + host->cmd = NULL; +- bcm2835_sdhost_send_command(host, host->mrq->cmd); ++ if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) { ++ if (host->data && host->dma_desc) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_start_dma(host); + +- if (host->cmd->data && host->use_dma) +- /* DMA transfer starts now, PIO starts after irq */ +- bcm2835_sdhost_transfer_dma(host); +- +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); +- } else if (host->cmd == host->mrq->stop) ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, NULL); ++ } ++ } else if (host->cmd == host->mrq->stop) { + /* Finished CMD12 */ + tasklet_schedule(&host->finish_tasklet); +- else { ++ } else { + /* Processed actual command. */ + host->cmd = NULL; + if (!host->data) +@@ -1023,6 +1251,7 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host) + else if (host->data_complete) + bcm2835_sdhost_transfer_complete(host); + } ++ log_event("FCM>", (u32)host->mrq, (u32)host->cmd); + } + + static void bcm2835_sdhost_timeout(unsigned long data) +@@ -1033,10 +1262,12 @@ static void bcm2835_sdhost_timeout(unsigned long data) + host = (struct bcm2835_host *)data; + + spin_lock_irqsave(&host->lock, flags); ++ log_event("TIM<", 0, 0); + + if (host->mrq) { + pr_err("%s: timeout waiting for hardware interrupt.\n", + mmc_hostname(host->mmc)); ++ log_dump(); + bcm2835_sdhost_dumpregs(host); + + if (host->data) { +@@ -1057,74 +1288,15 @@ static void bcm2835_sdhost_timeout(unsigned long data) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void bcm2835_sdhost_pio_timeout(unsigned long data) +-{ +- struct bcm2835_host *host; +- unsigned long flags; +- +- host = (struct bcm2835_host *)data; +- +- spin_lock_irqsave(&host->lock, flags); +- +- if (host->data) { +- u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); +- +- if (sdhsts & SDHSTS_REW_TIME_OUT) { +- pr_err("%s: transfer timeout\n", +- mmc_hostname(host->mmc)); +- if (host->debug) +- bcm2835_sdhost_dumpregs(host); +- } else { +- pr_err("%s: unexpected transfer timeout\n", +- mmc_hostname(host->mmc)); +- bcm2835_sdhost_dumpregs(host); +- } +- +- bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK, +- SDHSTS); +- +- host->data->error = -ETIMEDOUT; +- +- bcm2835_sdhost_finish_data(host); +- } +- +- mmiowb(); +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) ++static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + { +- if (enable) +- host->hcfg |= SDHCFG_SDIO_IRPT_EN; +- else +- host->hcfg &= ~SDHCFG_SDIO_IRPT_EN; +- bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- mmiowb(); +-} +- +-static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable) +-{ +- struct bcm2835_host *host = mmc_priv(mmc); +- unsigned long flags; +- +- pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable); +- spin_lock_irqsave(&host->lock, flags); +- bcm2835_sdhost_enable_sdio_irq_nolock(host, enable); +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) +-{ +- const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT | +- SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | +- SDHSTS_FIFO_ERROR); +- ++ log_event("IRQB", (u32)host->cmd, intmask); + if (!host->cmd) { + pr_err("%s: got command busy interrupt 0x%08x even " + "though no command operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return 0; ++ return; + } + + if (!host->use_busy) { +@@ -1132,7 +1304,7 @@ static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + "though not expecting one.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return 0; ++ return; + } + host->use_busy = 0; + +@@ -1155,28 +1327,23 @@ static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) + } else if (intmask & SDHSTS_CMD_TIME_OUT) + host->cmd->error = -ETIMEDOUT; + ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); + } + else +- bcm2835_sdhost_finish_command(host); +- +- return handled; ++ bcm2835_sdhost_finish_command(host, NULL); + } + +-static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) ++static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) + { +- const u32 handled = (SDHSTS_REW_TIME_OUT | +- SDHSTS_CRC16_ERROR | +- SDHSTS_FIFO_ERROR); +- + /* There are no dedicated data/space available interrupt + status bits, so it is necessary to use the single shared + data/space available FIFO status bits. It is therefore not + an error to get here when there is no data transfer in + progress. */ ++ log_event("IRQD", (u32)host->data, intmask); + if (!host->data) +- return 0; ++ return; + + if (intmask & (SDHSTS_CRC16_ERROR | + SDHSTS_FIFO_ERROR | +@@ -1187,46 +1354,37 @@ static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) + else + host->data->error = -ETIMEDOUT; + +- bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); +- return handled; ++ if (host->debug) { ++ log_dump(); ++ bcm2835_sdhost_dumpregs(host); ++ } + } + +- /* Use the block interrupt for writes after the first block */ +- if (host->data->flags & MMC_DATA_WRITE) { ++ if (host->data->error) { ++ bcm2835_sdhost_finish_data(host); ++ } else if (host->data->flags & MMC_DATA_WRITE) { ++ /* Use the block interrupt for writes after the first block */ + host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); + host->hcfg |= SDHCFG_BLOCK_IRPT_EN; + bcm2835_sdhost_write(host, host->hcfg, SDHCFG); +- if (host->data->error) +- bcm2835_sdhost_finish_data(host); +- else +- bcm2835_sdhost_transfer_pio(host); ++ bcm2835_sdhost_transfer_pio(host); + } else { +- if (!host->data->error) { +- bcm2835_sdhost_transfer_pio(host); +- host->blocks--; +- } ++ bcm2835_sdhost_transfer_pio(host); ++ host->blocks--; + if ((host->blocks == 0) || host->data->error) + bcm2835_sdhost_finish_data(host); + } +- +- return handled; + } + +-static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) ++static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) + { +- struct dma_chan *dma_chan; +- u32 dir_data; +- const u32 handled = (SDHSTS_REW_TIME_OUT | +- SDHSTS_CRC16_ERROR | +- SDHSTS_FIFO_ERROR); +- ++ log_event("IRQK", (u32)host->data, intmask); + if (!host->data) { + pr_err("%s: got block interrupt 0x%08x even " + "though no data operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); + bcm2835_sdhost_dumpregs(host); +- return handled; ++ return; + } + + if (intmask & (SDHSTS_CRC16_ERROR | +@@ -1238,158 +1396,69 @@ static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask) + else + host->data->error = -ETIMEDOUT; + +- if (host->debug) ++ if (host->debug) { ++ log_dump(); + bcm2835_sdhost_dumpregs(host); +- tasklet_schedule(&host->finish_tasklet); +- return handled; ++ } + } + +- if (!host->use_dma) { ++ if (!host->dma_desc) { + BUG_ON(!host->blocks); +- host->blocks--; +- if ((host->blocks == 0) || host->data->error) { +- /* Cancel the timer */ +- del_timer(&host->pio_timer); +- ++ if (host->data->error || (--host->blocks == 0)) { + bcm2835_sdhost_finish_data(host); + } else { + bcm2835_sdhost_transfer_pio(host); +- +- /* Reset the timer */ +- mod_timer(&host->pio_timer, +- jiffies + host->pio_timeout); + } + } else if (host->data->flags & MMC_DATA_WRITE) { +- dma_chan = host->dma_chan_tx; +- dir_data = DMA_TO_DEVICE; +- dma_unmap_sg(dma_chan->device->dev, +- host->data->sg, host->data->sg_len, +- dir_data); +- + bcm2835_sdhost_finish_data(host); + } +- +- return handled; + } + +- + static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id) + { + irqreturn_t result = IRQ_NONE; + struct bcm2835_host *host = dev_id; +- u32 unexpected = 0, early = 0; +- int loops = 0; +-#ifndef CONFIG_ARCH_BCM2835 +- int cardint = 0; +-#endif +- spin_lock(&host->lock); ++ u32 intmask; + +- for (loops = 0; loops < 1; loops++) { +- u32 intmask, handled; +- +- intmask = bcm2835_sdhost_read(host, SDHSTS); +- handled = intmask & (SDHSTS_BUSY_IRPT | +- SDHSTS_BLOCK_IRPT | +- SDHSTS_SDIO_IRPT | +- SDHSTS_DATA_FLAG); +- if ((handled == SDHSTS_DATA_FLAG) && +- (loops == 0) && !host->data) { +- pr_err("%s: sdhost_irq data interrupt 0x%08x even " +- "though no data operation was in progress.\n", +- mmc_hostname(host->mmc), +- (unsigned)intmask); +- +- bcm2835_sdhost_dumpregs(host); +- } ++ spin_lock(&host->lock); + +- if (!handled) +- break; ++ intmask = bcm2835_sdhost_read(host, SDHSTS); ++ log_event("IRQ<", intmask, 0); + +- if (loops) +- early |= handled; ++ bcm2835_sdhost_write(host, ++ SDHSTS_BUSY_IRPT | ++ SDHSTS_BLOCK_IRPT | ++ SDHSTS_SDIO_IRPT | ++ SDHSTS_DATA_FLAG, ++ SDHSTS); + ++ if (intmask & SDHSTS_BLOCK_IRPT) { ++ bcm2835_sdhost_block_irq(host, intmask); + result = IRQ_HANDLED; ++ } + +- /* Clear all interrupts and notifications */ +- bcm2835_sdhost_write(host, intmask, SDHSTS); +- +- if (intmask & SDHSTS_BUSY_IRPT) +- handled |= bcm2835_sdhost_busy_irq(host, intmask); +- +- /* There is no true data interrupt status bit, so it is +- necessary to qualify the data flag with the interrupt +- enable bit */ +- if ((intmask & SDHSTS_DATA_FLAG) && +- (host->hcfg & SDHCFG_DATA_IRPT_EN)) +- handled |= bcm2835_sdhost_data_irq(host, intmask); +- +- if (intmask & SDHSTS_BLOCK_IRPT) +- handled |= bcm2835_sdhost_block_irq(host, intmask); +- +- if (intmask & SDHSTS_SDIO_IRPT) { +-#ifndef CONFIG_ARCH_BCM2835 +- cardint = 1; +-#else +- bcm2835_sdhost_enable_sdio_irq_nolock(host, false); +- host->thread_isr |= SDHSTS_SDIO_IRPT; +- result = IRQ_WAKE_THREAD; +-#endif +- } ++ if (intmask & SDHSTS_BUSY_IRPT) { ++ bcm2835_sdhost_busy_irq(host, intmask); ++ result = IRQ_HANDLED; ++ } + +- unexpected |= (intmask & ~handled); ++ /* There is no true data interrupt status bit, so it is ++ necessary to qualify the data flag with the interrupt ++ enable bit */ ++ if ((intmask & SDHSTS_DATA_FLAG) && ++ (host->hcfg & SDHCFG_DATA_IRPT_EN)) { ++ bcm2835_sdhost_data_irq(host, intmask); ++ result = IRQ_HANDLED; + } + + mmiowb(); + ++ log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0); + spin_unlock(&host->lock); + +- if (early) +- pr_debug("%s: early %x (loops %d)\n", +- mmc_hostname(host->mmc), early, loops); +- +- if (unexpected) { +- pr_err("%s: unexpected interrupt 0x%08x.\n", +- mmc_hostname(host->mmc), unexpected); +- bcm2835_sdhost_dumpregs(host); +- } +- +-#ifndef CONFIG_ARCH_BCM2835 +- if (cardint) +- mmc_signal_sdio_irq(host->mmc); +-#endif +- + return result; + } + +-#ifdef CONFIG_ARCH_BCM2835 +-static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id) +-{ +- struct bcm2835_host *host = dev_id; +- unsigned long flags; +- u32 isr; +- +- spin_lock_irqsave(&host->lock, flags); +- isr = host->thread_isr; +- host->thread_isr = 0; +- spin_unlock_irqrestore(&host->lock, flags); +- +- if (isr & SDHSTS_SDIO_IRPT) { +- sdio_run_irqs(host->mmc); +- +-/* Is this necessary? Why re-enable an interrupt which is enabled? +- spin_lock_irqsave(&host->lock, flags); +- if (host->flags & SDHSTS_SDIO_IRPT_ENABLED) +- bcm2835_sdhost_enable_sdio_irq_nolock(host, true); +- spin_unlock_irqrestore(&host->lock, flags); +-*/ +- } +- +- return isr ? IRQ_HANDLED : IRQ_NONE; +-} +-#endif +- +- +- + void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + { + int div = 0; /* Initialized for compiler warning */ +@@ -1399,9 +1468,8 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock); + + if ((host->overclock_50 > 50) && +- (clock == 50*MHZ)) { ++ (clock == 50*MHZ)) + clock = host->overclock_50 * MHZ + (MHZ - 1); +- } + + /* The SDCDIV register has 11 bits, and holds (div - 2). + But in data mode the max is 50MHz wihout a minimum, and only the +@@ -1448,6 +1516,11 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock) + clock = host->max_clk / (div + 2); + host->mmc->actual_clock = clock; + ++ /* Calibrate some delays */ ++ ++ host->ns_per_fifo_word = (1000000000/clock) * ++ ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); ++ + if (clock > input_clock) { + /* Save the closest value, to make it easier + to reduce in the event of error */ +@@ -1483,6 +1556,7 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + { + struct bcm2835_host *host; + unsigned long flags; ++ u32 edm, fsm; + + host = mmc_priv(mmc); + +@@ -1503,6 +1577,8 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + } + + /* Reset the error statuses in case this is a retry */ ++ if (mrq->sbc) ++ mrq->sbc->error = 0; + if (mrq->cmd) + mrq->cmd->error = 0; + if (mrq->data) +@@ -1518,28 +1594,58 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq + return; + } + ++ if (host->use_dma && mrq->data && ++ (mrq->data->blocks > host->pio_limit)) ++ bcm2835_sdhost_prepare_dma(host, mrq->data); ++ + spin_lock_irqsave(&host->lock, flags); + + WARN_ON(host->mrq != NULL); +- + host->mrq = mrq; + +- if (mrq->sbc) +- bcm2835_sdhost_send_command(host, mrq->sbc); +- else +- bcm2835_sdhost_send_command(host, mrq->cmd); ++ edm = bcm2835_sdhost_read(host, SDEDM); ++ fsm = edm & SDEDM_FSM_MASK; + +- mmiowb(); +- spin_unlock_irqrestore(&host->lock, flags); ++ log_event("REQ<", (u32)mrq, edm); ++ if ((fsm != SDEDM_FSM_IDENTMODE) && ++ (fsm != SDEDM_FSM_DATAMODE)) { ++ pr_err("%s: previous command (%d) not complete (EDM %x)\n", ++ mmc_hostname(host->mmc), ++ bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK, ++ edm); ++ log_event("REQ!", (u32)mrq, edm); ++ log_dump(); ++ bcm2835_sdhost_dumpregs(host); ++ mrq->cmd->error = -EILSEQ; ++ tasklet_schedule(&host->finish_tasklet); ++ mmiowb(); ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } + +- if (!mrq->sbc && mrq->cmd->data && host->use_dma) +- /* DMA transfer starts now, PIO starts after irq */ +- bcm2835_sdhost_transfer_dma(host); ++ host->use_sbc = !!mrq->sbc && ++ (host->mrq->data->flags & USE_CMD23_FLAGS); ++ if (host->use_sbc) { ++ if (bcm2835_sdhost_send_command(host, mrq->sbc)) { ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, &flags); ++ } ++ } else if (bcm2835_sdhost_send_command(host, mrq->cmd)) { ++ if (host->data && host->dma_desc) ++ /* DMA transfer starts now, PIO starts after irq */ ++ bcm2835_sdhost_start_dma(host); + +- if (!host->use_busy) +- bcm2835_sdhost_finish_command(host); +-} ++ if (!host->use_busy) ++ bcm2835_sdhost_finish_command(host, &flags); ++ } ++ ++ log_event("CMD ", (u32)mrq->cmd->opcode, ++ mrq->data ? (u32)mrq->data->blksz : 0); ++ mmiowb(); + ++ log_event("REQ>", (u32)mrq, 0); ++ spin_unlock_irqrestore(&host->lock, flags); ++} + + static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { +@@ -1556,6 +1662,8 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + spin_lock_irqsave(&host->lock, flags); + ++ log_event("IOS<", ios->clock, 0); ++ + if (!ios->clock || ios->clock != host->clock) { + bcm2835_sdhost_set_clock(host, ios->clock); + host->clock = ios->clock; +@@ -1578,44 +1686,53 @@ static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, int blk_size) +-{ +- /* There is a bug in the host controller hardware that makes +- reading the final sector of the card as part of a multiple read +- problematic. Detect that case and shorten the read accordingly. +- */ +- /* csd.capacity is in weird units - convert to sectors */ +- u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9)); +- +- if ((direction == MMC_DATA_READ) && +- ((blk_pos + blk_size) == card_sectors)) +- blk_size--; +- +- return blk_size; +-} +- +- + static struct mmc_host_ops bcm2835_sdhost_ops = { + .request = bcm2835_sdhost_request, + .set_ios = bcm2835_sdhost_set_ios, +- .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, + .hw_reset = bcm2835_sdhost_reset, +- .multi_io_quirk = bcm2835_sdhost_multi_io_quirk, + }; + ++static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work) ++{ ++ struct bcm2835_host *host; ++ unsigned long flags; ++ ++ host = container_of(work, struct bcm2835_host, cmd_wait_wq); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ log_event("CWK<", (u32)host->cmd, (u32)host->mrq); ++ ++ /* ++ * If this tasklet gets rescheduled while running, it will ++ * be run again afterwards but without any active request. ++ */ ++ if (!host->mrq) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ ++ bcm2835_sdhost_finish_command(host, &flags); ++ ++ mmiowb(); ++ ++ log_event("CWK>", (u32)host->cmd, 0); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} + + static void bcm2835_sdhost_tasklet_finish(unsigned long param) + { + struct bcm2835_host *host; + unsigned long flags; + struct mmc_request *mrq; ++ struct dma_chan *terminate_chan = NULL; + + host = (struct bcm2835_host *)param; + + spin_lock_irqsave(&host->lock, flags); + ++ log_event("TSK<", (u32)host->mrq, 0); + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. +@@ -1650,11 +1767,23 @@ static void bcm2835_sdhost_tasklet_finish(unsigned long param) + + mmiowb(); + ++ host->dma_desc = NULL; ++ terminate_chan = host->dma_chan; ++ host->dma_chan = NULL; ++ + spin_unlock_irqrestore(&host->lock, flags); +- mmc_request_done(host->mmc, mrq); +-} + ++ if (terminate_chan) ++ { ++ int err = dmaengine_terminate_all(terminate_chan); ++ if (err) ++ pr_err("%s: failed to terminate DMA (%d)\n", ++ mmc_hostname(host->mmc), err); ++ } + ++ mmc_request_done(host->mmc, mrq); ++ log_event("TSK>", (u32)mrq, 0); ++} + + int bcm2835_sdhost_add_host(struct bcm2835_host *host) + { +@@ -1676,10 +1805,10 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc->f_max, mmc->f_min, mmc->max_busy_timeout); + + /* host controller capabilities */ +- mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | ++ mmc->caps |= + MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE | +- (ALLOW_CMD23 * MMC_CAP_CMD23); ++ ((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23); + + spin_lock_init(&host->lock); + +@@ -1689,9 +1818,9 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + pr_err("%s: unable to initialise DMA channels. " + "Falling back to PIO\n", + mmc_hostname(mmc)); +- host->have_dma = false; ++ host->use_dma = false; + } else { +- host->have_dma = true; ++ host->use_dma = true; + + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +@@ -1708,7 +1837,7 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); + } + } else { +- host->have_dma = false; ++ host->use_dma = false; + } + + mmc->max_segs = 128; +@@ -1723,21 +1852,15 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + tasklet_init(&host->finish_tasklet, + bcm2835_sdhost_tasklet_finish, (unsigned long)host); + +- setup_timer(&host->timer, bcm2835_sdhost_timeout, +- (unsigned long)host); ++ INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work); + +- setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout, ++ setup_timer(&host->timer, bcm2835_sdhost_timeout, + (unsigned long)host); + + bcm2835_sdhost_init(host, 0); +-#ifndef CONFIG_ARCH_BCM2835 ++ + ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/, + mmc_hostname(mmc), host); +-#else +- ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, +- bcm2835_sdhost_thread_irq, +- IRQF_SHARED, mmc_hostname(mmc), host); +-#endif + if (ret) { + pr_err("%s: failed to request IRQ %d: %d\n", + mmc_hostname(mmc), host->irq, ret); +@@ -1748,11 +1871,11 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host) + mmc_add_host(mmc); + + pio_limit_string[0] = '\0'; +- if (host->have_dma && (host->pio_limit > 0)) ++ if (host->use_dma && (host->pio_limit > 0)) + sprintf(pio_limit_string, " (>%d)", host->pio_limit); + pr_info("%s: %s loaded - DMA %s%s\n", + mmc_hostname(mmc), DRIVER_NAME, +- host->have_dma ? "enabled" : "disabled", ++ host->use_dma ? "enabled" : "disabled", + pio_limit_string); + + return 0; +@@ -1774,6 +1897,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + int ret; + + pr_debug("bcm2835_sdhost_probe\n"); ++ log_init(); + mmc = mmc_alloc_host(sizeof(*host), dev); + if (!mmc) + return -ENOMEM; +@@ -1781,8 +1905,11 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + mmc->ops = &bcm2835_sdhost_ops; + host = mmc_priv(mmc); + host->mmc = mmc; ++ host->cmd_quick_poll_retries = 0; + host->pio_timeout = msecs_to_jiffies(500); ++ host->pio_limit = 1; + host->max_delay = 1; /* Warn if over 1ms */ ++ host->allow_dma = 1; + spin_lock_init(&host->lock); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1798,8 +1925,6 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + (unsigned long)iomem->start, + (unsigned long)host->phys_addr); + +- host->allow_dma = ALLOW_DMA; +- + if (node) { + /* Read any custom properties */ + of_property_read_u32(node, +@@ -1811,11 +1936,18 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev) + of_property_read_u32(node, + "brcm,pio-limit", + &host->pio_limit); +- host->allow_dma = ALLOW_DMA && ++ host->allow_dma = + !of_property_read_bool(node, "brcm,force-pio"); + host->debug = of_property_read_bool(node, "brcm,debug"); + } + ++ host->dma_chan = NULL; ++ host->dma_desc = NULL; ++ ++ /* Formally recognise the other way of disabling DMA */ ++ if (host->pio_limit == 0x7fffffff) ++ host->allow_dma = false; ++ + if (host->allow_dma) { + if (node) { + host->dma_chan_tx = +@@ -1900,15 +2032,12 @@ static int bcm2835_sdhost_remove(struct platform_device *pdev) + return 0; + } + +- + static const struct of_device_id bcm2835_sdhost_match[] = { + { .compatible = "brcm,bcm2835-sdhost" }, + { } + }; + MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match); + +- +- + static struct platform_driver bcm2835_sdhost_driver = { + .probe = bcm2835_sdhost_probe, + .remove = bcm2835_sdhost_remove, + +From b6b2c6595459c46765517f681901a6b31dfb4d47 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 12 Feb 2016 15:38:00 +0000 +Subject: [PATCH 265/278] BCM270X_DT: Use bcm2835-sdhost as standard + +Also add new base dtparams sd_overclock, sd_force_pio, +sd_pio_limit and sd_debug. +--- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 15 +++++++-- + arch/arm/boot/dts/bcm2708-rpi-b.dts | 15 +++++++-- + arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 - + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 20 ++++++++++-- + arch/arm/boot/dts/bcm2708_common.dtsi | 17 +++++++++- + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 15 +++++++-- + arch/arm/boot/dts/overlays/README | 11 ++++++- + arch/arm/boot/dts/overlays/mmc-overlay.dts | 32 ++++++++++++++++-- + arch/arm/boot/dts/overlays/sdhost-overlay.dts | 47 +++++++-------------------- + 9 files changed, 124 insertions(+), 49 deletions(-) + +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +index d41d31c..f75f771 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -128,5 +135,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts +index 684852f..26e968f 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -118,5 +125,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +index ec4bfef..b776f4c 100755 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +@@ -91,6 +91,5 @@ + i2c0_baudrate = <&i2c0>,"clock-frequency:0"; + i2c1_baudrate = <&i2c1>,"clock-frequency:0"; + i2c2_baudrate = <&i2c2>,"clock-frequency:0"; +- core_freq = <&clk_core>,"clock-frequency:0"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +index 713e5a2..a85d9d6 100644 +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +@@ -1,5 +1,12 @@ + /include/ "bcm2708.dtsi" + ++&gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++}; ++ + &leds { + act_led: act { + label = "led0"; +@@ -8,9 +15,12 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ non-removable; ++ status = "okay"; + }; + + &fb { +@@ -19,6 +29,8 @@ + + / { + __overrides__ { ++ core_freq = <&clk_core>,"clock-frequency:0"; ++ + act_led_gpio = <&act_led>,"gpios:4"; + act_led_activelow = <&act_led>,"gpios:8"; + act_led_trigger = <&act_led>,"linux,default-trigger"; +@@ -26,5 +38,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi +index 924edc8..4c8ce77 100644 +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -14,6 +14,7 @@ + mailbox = &mailbox; + gpio = &gpio; + uart0 = &uart0; ++ sdhost = &sdhost; + i2s = &i2s; + spi0 = &spi0; + i2c0 = &i2c0; +@@ -65,7 +66,7 @@ + brcm,dma-channel-mask = <0x0f35>; + }; + +- intc: interrupt-controller { ++ intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2708-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; +@@ -126,6 +127,19 @@ + status = "disabled"; + }; + ++ sdhost: sdhost@7e202000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7e202000 0x100>; ++ interrupts = <2 24>; ++ clocks = <&clk_core>; ++ dmas = <&dma 13>, ++ <&dma 13>; ++ dma-names = "tx", "rx"; ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "disabled"; ++ }; ++ + i2s: i2s@7e203000 { + compatible = "brcm,bcm2708-i2s"; + reg = <0x7e203000 0x24>, +@@ -191,6 +205,7 @@ + dmas = <&dma 11>, + <&dma 11>; + dma-names = "tx", "rx"; ++ brcm,overclock-50 = <0>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +index a8e8b7c..24aa53a 100644 +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -8,6 +8,11 @@ + }; + + &gpio { ++ sdhost_pins: sdhost_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <4>; /* alt0 */ ++ }; ++ + spi0_pins: spi0_pins { + brcm,pins = <7 8 9 10 11>; + brcm,function = <4>; /* alt0 */ +@@ -29,9 +34,11 @@ + }; + }; + +-&mmc { +- status = "okay"; ++&sdhost { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdhost_pins>; + bus-width = <4>; ++ status = "okay"; + }; + + &fb { +@@ -128,5 +135,9 @@ + audio = <&audio>,"status"; + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 3f7a25d..3aaa3da 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -112,6 +112,16 @@ Params: + random Set to "on" to enable the hardware random + number generator (default "on") + ++ sd_overclock Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ ++ sd_force_pio Disable DMA support for SD driver (default off) ++ ++ sd_pio_limit Number of blocks above which to use DMA for ++ SD card (default 1) ++ ++ sd_debug Enable debug output from SD driver (default off) ++ + uart0 Set to "off" to disable uart0 (default "on") + + watchdog Set to "on" to enable the hardware watchdog +@@ -422,7 +432,6 @@ Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock + Load: dtoverlay=mmc,= + Params: overclock_50 Clock (in MHz) to use when the MMC framework + requests 50MHz +- force_pio Disable DMA support + + + Name: mz61581 +diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts +index 4579ff2..2222fd8 100644 +--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts +@@ -6,14 +6,42 @@ + + fragment@0 { + target = <&mmc>; +- + frag0: __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc_pins>; ++ bus-width = <4>; + brcm,overclock-50 = <0>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ mmc_pins: mmc_pins { ++ brcm,pins = <48 49 50 51 52 53>; ++ brcm,function = <7>; /* alt3 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sdhost>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ /* Redirect the existing sd_overclock and sd_force_pio dtparams */ ++ fragment@3 { ++ target-path = "/__overrides__"; ++ ++ __overlay__ { ++ sd_overclock = <&mmc>,"brcm,overclock-50:0"; + }; + }; + + __overrides__ { + overclock_50 = <&frag0>,"brcm,overclock-50:0"; +- force_pio = <&frag0>,"brcm,force-pio?"; + }; + }; +diff --git a/arch/arm/boot/dts/overlays/sdhost-overlay.dts b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +index 2da14a4..de3d1b0 100644 +--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts +@@ -1,56 +1,31 @@ + /dts-v1/; + /plugin/; + ++/* Provide backwards compatible aliases for the old sdhost dtparams. */ ++ + /{ + compatible = "brcm,bcm2708"; + + fragment@0 { +- target = <&soc>; +- __overlay__ { +- #address-cells = <1>; +- #size-cells = <1>; +- +- sdhost: sdhost@7e202000 { +- compatible = "brcm,bcm2835-sdhost"; +- reg = <0x7e202000 0x100>; +- pinctrl-names = "default"; +- pinctrl-0 = <&sdhost_pins>; +- interrupts = <2 24>; +- clocks = <&clk_core>; +- dmas = <&dma 13>, +- <&dma 13>; +- dma-names = "tx", "rx"; +- brcm,delay-after-stop = <0>; +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; +- status = "okay"; +- }; ++ target = <&sdhost>; ++ frag0: __overlay__ { ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++ status = "okay"; + }; + }; + + fragment@1 { +- target = <&gpio>; +- __overlay__ { +- sdhost_pins: sdhost_pins { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = <4>; /* alt0 */ +- }; +- }; +- }; +- +- fragment@2 { + target = <&mmc>; + __overlay__ { +- /* Find a way to disable the other driver */ +- compatible = ""; + status = "disabled"; + }; + }; + + __overrides__ { +- overclock_50 = <&sdhost>,"brcm,overclock-50:0"; +- force_pio = <&sdhost>,"brcm,force-pio?"; +- pio_limit = <&sdhost>,"brcm,pio-limit:0"; +- debug = <&sdhost>,"brcm,debug?"; ++ overclock_50 = <&frag0>,"brcm,overclock-50:0"; ++ force_pio = <&frag0>,"brcm,force-pio?"; ++ pio_limit = <&frag0>,"brcm,pio-limit:0"; ++ debug = <&frag0>,"brcm,debug?"; + }; + }; + +From 3fa93dd52f7a97f68efff0b96838eacc6e8de795 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 12 Feb 2016 14:50:25 +0000 +Subject: [PATCH 266/278] dcw_otg: trim xfer length when buffer larger than + allocated size is received + +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +index 8db3dfc..d672a76 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -737,6 +737,11 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, + DWC_OTG_HC_XFER_COMPLETE, + &short_read); + ++ if (urb->actual_length + xfer_length > urb->length) { ++ DWC_WARN("%s(): trimming xfer length\n", __func__); ++ xfer_length = urb->length - urb->actual_length; ++ } ++ + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && xfer_length && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, +@@ -1423,6 +1428,12 @@ static void update_urb_state_xfer_intr(dwc_hc_t * hc, + { + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd, + halt_status, NULL); ++ ++ if (urb->actual_length + bytes_transferred > urb->length) { ++ DWC_WARN("%s(): trimming xfer length\n", __func__); ++ bytes_transferred = urb->length - urb->actual_length; ++ } ++ + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && bytes_transferred && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, + +From bb93822cc5f82f48c32b2e01371f45ad2a006d9e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 15 Feb 2016 10:00:27 +0000 +Subject: [PATCH 267/278] bcm2835-sdhost: Restore ATOMIC flag to PIO sg mapping + +Allocation problems have been seen in a wireless driver, and +this is the only change which might have been responsible. +--- + drivers/mmc/host/bcm2835-sdhost.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 84d120f..13b9d38 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -881,15 +881,14 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co + host->flush_fifo = 0; + host->data->bytes_xfered = 0; + +- + if (!host->dma_desc) { + /* Use PIO */ +- int flags; ++ int flags = SG_MITER_ATOMIC; + + if (data->flags & MMC_DATA_READ) +- flags = SG_MITER_TO_SG; ++ flags |= SG_MITER_TO_SG; + else +- flags = SG_MITER_FROM_SG; ++ flags |= SG_MITER_FROM_SG; + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); + host->blocks = data->blocks; + } + +From 3a62fd51d873754d49b0ccbc525e5542a7554b15 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 16 Feb 2016 08:47:56 +0000 +Subject: [PATCH 268/278] Revert "Add blk_pos parameter to mmc multi_io_quirk + callback" + +This reverts commit aab95f9b10e8c3d32de2bf163b86f220c88214fe. + +The bcm2835-sdhost driver no longer needs this patch. +--- + drivers/mmc/card/block.c | 1 - + drivers/mmc/host/omap_hsmmc.c | 4 +--- + drivers/mmc/host/sh_mobile_sdhi.c | 4 +--- + drivers/mmc/host/tmio_mmc_pio.c | 4 +--- + include/linux/mmc/host.h | 4 +--- + 5 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index 8484ec9..31d2627 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1415,7 +1415,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + brq->data.blocks = card->host->ops->multi_io_quirk(card, + (rq_data_dir(req) == READ) ? + MMC_DATA_READ : MMC_DATA_WRITE, +- blk_rq_pos(req), + brq->data.blocks); + } + +diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c +index ebb6bf4..d0abdffb 100644 +--- a/drivers/mmc/host/omap_hsmmc.c ++++ b/drivers/mmc/host/omap_hsmmc.c +@@ -1749,9 +1749,7 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) + } + + static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + /* This controller can't do multiblock reads due to hw bugs */ + if (direction == MMC_DATA_READ) +diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c +index 4f1ccf3..354f4f3 100644 +--- a/drivers/mmc/host/sh_mobile_sdhi.c ++++ b/drivers/mmc/host/sh_mobile_sdhi.c +@@ -170,9 +170,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) + } + + static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + /* + * In Renesas controllers, when performing a +diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c +index 0c87f4f..dba7e1c 100644 +--- a/drivers/mmc/host/tmio_mmc_pio.c ++++ b/drivers/mmc/host/tmio_mmc_pio.c +@@ -1001,9 +1001,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) + } + + static int tmio_multi_io_quirk(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size) ++ unsigned int direction, int blk_size) + { + struct tmio_mmc_host *host = mmc_priv(card->host); + +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index d3cdad9..b0258e8 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -140,9 +140,7 @@ struct mmc_host_ops { + * I/O. Returns the number of supported blocks for the request. + */ + int (*multi_io_quirk)(struct mmc_card *card, +- unsigned int direction, +- u32 blk_pos, +- int blk_size); ++ unsigned int direction, int blk_size); + }; + + struct mmc_card; + +From 462c17a8e24cc362d233d674e84d1c7f9a937ced Mon Sep 17 00:00:00 2001 +From: Craig Roberts +Date: Tue, 16 Feb 2016 10:03:42 +0000 +Subject: [PATCH 269/278] Updated smsc95xx driver to check for a valid MAC + address in eeprom before using smsc95xx.macaddr parameter passed on command + line. + +The built-in RPi adaptor will still get a MAC address based on the parameter passed on the command line as the RPi hardware does not have an eeprom, +however usb->ethernet adaptors using the same driver should have an eeprom with MAC address as part of their hardware and therefore will use this +meaning they don't end up with the same MAC address as the built-in RPi adaptor. +--- + drivers/net/usb/smsc95xx.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index f664c1b..6dec199 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -821,10 +821,6 @@ static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac) + + static void smsc95xx_init_mac_address(struct usbnet *dev) + { +- /* Check module parameters */ +- if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) +- return; +- + /* try reading mac address from EEPROM */ + if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { +@@ -835,7 +831,11 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) + } + } + +- /* no eeprom, or eeprom values are invalid. generate random MAC */ ++ /* Check module parameters */ ++ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) ++ return; ++ ++ /* no eeprom, or eeprom values are invalid, and no module parameter specified to set MAC. Generate random MAC */ + eth_hw_addr_random(dev->net); + netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); + } + +From 041772c61aaedcda1f900d404d656041186a3f92 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 17 Feb 2016 19:02:31 +0000 +Subject: [PATCH 270/278] dcw_otg: Make trimming messages less noisy + +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +index d672a76..e6b38ac3 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -738,7 +738,8 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, + &short_read); + + if (urb->actual_length + xfer_length > urb->length) { +- DWC_WARN("%s(): trimming xfer length\n", __func__); ++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n", ++ hc->dev_addr, __func__, __LINE__); + xfer_length = urb->length - urb->actual_length; + } + +@@ -1430,7 +1431,8 @@ static void update_urb_state_xfer_intr(dwc_hc_t * hc, + halt_status, NULL); + + if (urb->actual_length + bytes_transferred > urb->length) { +- DWC_WARN("%s(): trimming xfer length\n", __func__); ++ printk_once(KERN_DEBUG "dwc_otg: DEVICE:%03d : %s:%d:trimming xfer length\n", ++ hc->dev_addr, __func__, __LINE__); + bytes_transferred = urb->length - urb->actual_length; + } + + +From 39af28b0dec15877e252808fe742ac5fe0fefc44 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 18 Feb 2016 15:28:14 +0000 +Subject: [PATCH 271/278] BCM270X_DT: at86rf233 overlay - drop to 3MHz + +The consensus is that 6MHz is too fast, but that 3MHz is OK. + +See: https://github.com/raspberrypi/linux/issues/1294 + https://github.com/raspberrypi/linux/issues/1151 +--- + arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + diff --git a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts -index 70f50ea..0460269 100644 +index 0460269..eab4052 100644 --- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts +++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts @@ -25,7 +25,7 @@ interrupts = <23 4>; /* active high */ reset-gpio = <&gpio 24 1>; sleep-gpio = <&gpio 25 1>; -- spi-max-frequency = <7500000>; -+ spi-max-frequency = <6000000>; +- spi-max-frequency = <6000000>; ++ spi-max-frequency = <3000000>; xtal-trim = /bits/ 8 <0xf>; }; }; -From 625d90e2f7b2de52e0ba82e66e076915402e9c8b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 1 Oct 2015 11:49:11 +0100 -Subject: [PATCH 201/204] config: Add CONFIG_UHID - ---- - 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 6f4021b..6a914fb 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -843,6 +843,7 @@ CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y -+CONFIG_UHID=m - CONFIG_HID_A4TECH=m - CONFIG_HID_ACRUX=m - CONFIG_HID_APPLE=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 015540b..7a477e3 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -836,6 +836,7 @@ CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y -+CONFIG_UHID=m - CONFIG_HID_A4TECH=m - CONFIG_HID_ACRUX=m - CONFIG_HID_APPLE=m - -From 7a8dc0c298b4619fe8658481d0b3ae0ac1231a5e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 4 Oct 2015 12:30:01 +0100 -Subject: [PATCH 202/204] config: Add CONFIG_CRYPTO_USER_API_SKCIPHER - ---- - 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 6a914fb..05383c0 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -1239,6 +1239,7 @@ CONFIG_CRYPTO_WP512=m - CONFIG_CRYPTO_CAST5=m - CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set -+CONFIG_CRYPTO_USER_API_SKCIPHER=m - # CONFIG_CRYPTO_HW is not set - CONFIG_ARM_CRYPTO=y - CONFIG_CRYPTO_SHA1_ARM_NEON=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 7a477e3..0f315d8 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -1235,6 +1235,7 @@ CONFIG_CRYPTO_WP512=m - CONFIG_CRYPTO_CAST5=m - CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set -+CONFIG_CRYPTO_USER_API_SKCIPHER=m - # CONFIG_CRYPTO_HW is not set - CONFIG_ARM_CRYPTO=y - CONFIG_CRYPTO_SHA1_ARM=m - -From c7158fd021cf31f5fb67768796aecabde5ff6727 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 4 Oct 2015 12:36:44 +0100 -Subject: [PATCH 203/204] config: Add options for supporting openlabs 802.15.4 - radio - ---- - arch/arm/configs/bcm2709_defconfig | 6 ++++++ - arch/arm/configs/bcmrpi_defconfig | 6 ++++++ - 2 files changed, 12 insertions(+) - -diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 05383c0..fb402e8 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -283,6 +283,9 @@ CONFIG_VLAN_8021Q=m - CONFIG_VLAN_8021Q_GVRP=y - CONFIG_ATALK=m - CONFIG_6LOWPAN=m -+CONFIG_IEEE802154=m -+CONFIG_IEEE802154_6LOWPAN=m -+CONFIG_MAC802154=m - CONFIG_NET_SCHED=y - CONFIG_NET_SCH_CBQ=m - CONFIG_NET_SCH_HTB=m -@@ -529,6 +532,9 @@ CONFIG_ZD1211RW=m - CONFIG_MWIFIEX=m - CONFIG_MWIFIEX_SDIO=m - CONFIG_WIMAX_I2400M_USB=m -+CONFIG_IEEE802154_AT86RF230=m -+CONFIG_IEEE802154_MRF24J40=m -+CONFIG_IEEE802154_CC2520=m - CONFIG_INPUT_POLLDEV=m - # CONFIG_INPUT_MOUSEDEV_PSAUX is not set - CONFIG_INPUT_JOYDEV=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 0f315d8..eb81555e 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -276,6 +276,9 @@ CONFIG_VLAN_8021Q=m - CONFIG_VLAN_8021Q_GVRP=y - CONFIG_ATALK=m - CONFIG_6LOWPAN=m -+CONFIG_IEEE802154=m -+CONFIG_IEEE802154_6LOWPAN=m -+CONFIG_MAC802154=m - CONFIG_NET_SCHED=y - CONFIG_NET_SCH_CBQ=m - CONFIG_NET_SCH_HTB=m -@@ -522,6 +525,9 @@ CONFIG_ZD1211RW=m - CONFIG_MWIFIEX=m - CONFIG_MWIFIEX_SDIO=m - CONFIG_WIMAX_I2400M_USB=m -+CONFIG_IEEE802154_AT86RF230=m -+CONFIG_IEEE802154_MRF24J40=m -+CONFIG_IEEE802154_CC2520=m - CONFIG_INPUT_POLLDEV=m - # CONFIG_INPUT_MOUSEDEV_PSAUX is not set - CONFIG_INPUT_JOYDEV=m - -From 6c1d6379ed6d95956ba255936da39f06543ddb7f Mon Sep 17 00:00:00 2001 +From 3d3db343497bb670583f20a835deb0c082f68ec0 Mon Sep 17 00:00:00 2001 From: Phil Elwell -Date: Thu, 8 Oct 2015 13:33:28 +0100 -Subject: [PATCH 204/204] scripts/mkknlimg: Improve ARCH_BCM2835 detection +Date: Thu, 18 Feb 2016 16:23:12 +0000 +Subject: [PATCH 272/278] SQUASH: Update overlay README for at86rf233 -The board support code contains sufficient strings to be able to -distinguish 2708 vs. 2835 builds, so remove the check for -bcm2835-pm-wdt which could exist in either. - -Also, since the canned configuration is no longer built in (it's -a module), remove the config string checking. - -See: https://github.com/raspberrypi/linux/issues/1157 --- - scripts/mkknlimg | 41 +++++------------------------------------ - 1 file changed, 5 insertions(+), 36 deletions(-) + arch/arm/boot/dts/overlays/README | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/scripts/mkknlimg b/scripts/mkknlimg -index 3dff948..3998d43 100755 ---- a/scripts/mkknlimg -+++ b/scripts/mkknlimg -@@ -50,12 +50,6 @@ if (! -r $kernel_file) - usage(); - } +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 3aaa3da..87db77e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -188,7 +188,7 @@ Load: dtoverlay=at86rf233,= + Params: interrupt GPIO used for INT (default 23) + reset GPIO used for Reset (default 24) + sleep GPIO used for Sleep (default 25) +- speed SPI bus speed in Hz (default 6000000) ++ speed SPI bus speed in Hz (default 3000000) + trim Fine tuning of the internal capacitance + arrays (0=+0pF, 15=+4.5pF, default 15) --my @wanted_config_lines = --( -- 'CONFIG_BCM2708_DT', -- 'CONFIG_ARCH_BCM2835' --); -- - my @wanted_strings = - ( - 'bcm2708_fb', -@@ -63,7 +57,8 @@ my @wanted_strings = - 'brcm,bcm2835-sdhost', - 'brcm,bcm2708-pinctrl', - 'brcm,bcm2835-gpio', -- 'brcm,bcm2835-pm-wdt' -+ 'brcm,bcm2835', -+ 'brcm,bcm2836' - ); + +From bed58e0b16c38a922ae64649ca945176812aeeee Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 19 Feb 2016 12:04:48 +0000 +Subject: [PATCH 273/278] bcm2835-sdhost: Downgrade log message status + +--- + drivers/mmc/host/bcm2835-sdhost.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c +index 13b9d38..eee313fa 100644 +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -239,8 +239,8 @@ static void log_init(void) + sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr, + GFP_KERNEL); + if (sdhost_log_buf) { +- pr_err("sdhost: log_buf @ %p (%x)\n", +- sdhost_log_buf, sdhost_log_addr); ++ pr_info("sdhost: log_buf @ %p (%x)\n", ++ sdhost_log_buf, sdhost_log_addr); + timer_base = ioremap_nocache(BCM2708_PERI_BASE + 0x3000, SZ_4K); + if (!timer_base) + pr_err("sdhost: failed to remap timer\n"); + +From b7c08e8a592a761cc957061513c0fe8e854ab612 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 15 Jan 2016 16:48:27 +0000 +Subject: [PATCH 274/278] config: Enable HCI over UARTs + +--- + arch/arm/configs/bcm2709_defconfig | 3 +++ + arch/arm/configs/bcmrpi_defconfig | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index d61f42a..4bcb1d8 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -375,6 +375,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m + CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_3WIRE=y ++CONFIG_BT_HCIUART_BCM=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m + CONFIG_BT_HCIBFUSB=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index ccdde92..e0035ac 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -368,6 +368,9 @@ CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m + CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_3WIRE=y ++CONFIG_BT_HCIUART_BCM=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m + CONFIG_BT_HCIBFUSB=m + +From 6b0a564e3f880441e4c7a26b9cc463bb7a474b29 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 17 Dec 2015 13:37:07 +0000 +Subject: [PATCH 275/278] 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. +--- + drivers/bluetooth/hci_h5.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c +index 3455cec..5350703 100644 +--- a/drivers/bluetooth/hci_h5.c ++++ b/drivers/bluetooth/hci_h5.c +@@ -314,7 +314,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_req, 2) == 0) { + h5_link_control(hu, conf_rsp, 2); +- h5_link_control(hu, conf_req, 3); ++ if (h5->state != H5_ACTIVE) ++ h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_rsp, 2) == 0) { + if (H5_HDR_LEN(hdr) > 2) + h5->tx_win = (data[2] & 7); + +From f26d6689baad3fcf8fa69479ec48997efe5aeb59 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 23 Feb 2016 17:26:48 +0000 +Subject: [PATCH 276/278] 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 +/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the +other serial port is provided by the 8250 driver which doesn't +use the same logic. +--- + drivers/tty/serial/amba-pl011.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 2585cd8..86ec446 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2220,7 +2220,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) + if (uap == NULL) + return -ENOMEM; - my $res = try_extract($kernel_file, $tmpfile1); -@@ -98,12 +93,11 @@ if ($res) - config_bool($res, 'brcm,bcm2835-mmc') || - config_bool($res, 'brcm,bcm2835-sdhost')) - { -- $dtok ||= config_bool($res, 'CONFIG_BCM2708_DT'); -- $dtok ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); - $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl'); - $dtok ||= config_bool($res, 'brcm,bcm2835-gpio'); -- $is_283x ||= config_bool($res, 'CONFIG_ARCH_BCM2835'); -- $is_283x ||= config_bool($res, 'brcm,bcm2835-pm-wdt'); -+ $is_283x ||= config_bool($res, 'brcm,bcm2835'); -+ $is_283x ||= config_bool($res, 'brcm,bcm2836'); -+ $dtok ||= $is_283x; - $append_trailer = 1; - } - else -@@ -205,31 +199,6 @@ sub try_extract - $res->{$match} = 1; - } ++ /* Don't use DT serial aliases - it causes the device to ++ be renumbered to ttyAMA1 if it is the second serial port in the ++ system, even though the other one is ttyS0. The 8250 driver ++ doesn't use this logic, so always remains ttyS0. + i = pl011_probe_dt_alias(i, &dev->dev); ++ */ -- my $config_pattern = '^('.join('|', @wanted_config_lines).')=(.*)$'; -- my $cf1 = 'IKCFG_ST\037\213\010'; -- my $cf2 = '0123456789'; -- -- my $pos = `tr "$cf1\n$cf2" "\n$cf2=" < "$knl" | grep -abo "^$cf2"`; -- if ($pos) -- { -- $pos =~ s/:.*[\r\n]*$//s; -- $pos += 8; -- my $err = (system("tail -c+$pos \"$knl\" | zcat > $tmp 2> /dev/null") >> 8); -- if (($err == 0) || ($err == 2)) -- { -- if (open(my $fh, '<', $tmp)) -- { -- while (my $line = <$fh>) -- { -- chomp($line); -- $res->{$1} = $2 if ($line =~ /$config_pattern/); -- } -- -- close($fh); -- } -- } -- } -- - return $res; - } + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); + +From cb5a6e22a60cd95da802c7767183b05fb7637f56 Mon Sep 17 00:00:00 2001 +From: campag +Date: Wed, 24 Feb 2016 16:45:42 +0000 +Subject: [PATCH 277/278] Add 1-bit SDIO with the minimum pins required for + that mode: GPIOs 22-25. + +--- + arch/arm/boot/dts/overlays/README | 21 ++++++++++++++ + arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts | 36 ++++++++++++++++++++++++ + 2 files changed, 57 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 87db77e..8b2d59e 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -654,6 +654,27 @@ Params: overclock_50 SD Clock (in MHz) to use when the MMC framework + bus_width Set the SDIO host bus width (default 4 bits) + ++Name: sdio-1bit ++Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock, ++ and enables 1-bit SDIO via GPIOs 22-25. ++Load: dtoverlay=sdio-1bit,= ++Params: overclock_50 SD Clock (in MHz) to use when the MMC framework ++ requests 50MHz ++ ++ sdio_overclock SDIO Clock (in MHz) to use when the MMC ++ framework requests 50MHz ++ ++ force_pio Disable DMA support (default off) ++ ++ pio_limit Number of blocks above which to use DMA ++ (default 1) ++ ++ debug Enable debug output (default off) ++ ++ poll_once Disable SDIO-device polling every second ++ (default on: polling once at boot-time) ++ ++ + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! + Load: dtoverlay=smi +diff --git a/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts b/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts +new file mode 100644 +index 0000000..46d4538 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts +@@ -0,0 +1,36 @@ ++/* Enable 1-bit SDIO from MMC interface via GPIOs 22-25. Includes sdhost overlay. */ ++ ++/include/ "sdhost-overlay.dts" ++ ++/{ ++ compatible = "brcm,bcm2708"; ++ ++ fragment@3 { ++ target = <&mmc>; ++ sdio_mmc: __overlay__ { ++ compatible = "brcm,bcm2835-mmc"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio_pins>; ++ non-removable; ++ bus-width = <1>; ++ brcm,overclock-50 = <0>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&gpio>; ++ __overlay__ { ++ sdio_pins: sdio_pins { ++ brcm,pins = <22 23 24 25>; ++ brcm,function = <7 7 7 7>; /* ALT3 = SD1 */ ++ brcm,pull = <0 2 2 2>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ poll_once = <&sdio_mmc>,"non-removable?"; ++ sdio_overclock = <&sdio_mmc>,"brcm,overclock-50:0"; ++ }; ++}; + +From ef4ef49f5d92fe9050b065f7ead913c3ab502300 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Tue, 23 Feb 2016 17:28:23 +0100 +Subject: [PATCH 278/278] ASoC: bcm: add missing .owner fields in sound card + drivers + +If snd_soc_card.owner is not set the kernel won't do usage refcounting +and one can remove the card driver module while it's in use (eg playback +active) - which leads to a kernel crash. + +The missing owner field also prevents ALSA slot ordering +(options snd slots=module-name1,module-name-2,...) from working with +the I2S cards as it has no module name to match against. + +Fix these issues by setting the .owner field in the snd_soc_card structs. + +Signed-off-by: Matthias Reichl +--- + sound/soc/bcm/hifiberry_amp.c | 1 + + sound/soc/bcm/hifiberry_dac.c | 1 + + sound/soc/bcm/hifiberry_dacplus.c | 1 + + sound/soc/bcm/hifiberry_digi.c | 1 + + sound/soc/bcm/iqaudio-dac.c | 1 + + sound/soc/bcm/raspidac3.c | 1 + + sound/soc/bcm/rpi-dac.c | 1 + + sound/soc/bcm/rpi-proto.c | 1 + + 8 files changed, 8 insertions(+) + +diff --git a/sound/soc/bcm/hifiberry_amp.c b/sound/soc/bcm/hifiberry_amp.c +index 5903915..0bb12e4 100644 +--- a/sound/soc/bcm/hifiberry_amp.c ++++ b/sound/soc/bcm/hifiberry_amp.c +@@ -61,6 +61,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = { + + static struct snd_soc_card snd_rpi_hifiberry_amp = { + .name = "snd_rpi_hifiberry_amp", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_amp_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_dac.c b/sound/soc/bcm/hifiberry_dac.c +index 3ab0f47..29ecc08 100644 +--- a/sound/soc/bcm/hifiberry_dac.c ++++ b/sound/soc/bcm/hifiberry_dac.c +@@ -63,6 +63,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_dac = { + .name = "snd_rpi_hifiberry_dac", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c +index 50b66a1..a3525f7 100644 +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -288,6 +288,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_dacplus = { + .name = "snd_rpi_hifiberry_dacplus", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_dacplus_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai), + }; +diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c +index 80732b8..9840e15 100644 +--- a/sound/soc/bcm/hifiberry_digi.c ++++ b/sound/soc/bcm/hifiberry_digi.c +@@ -164,6 +164,7 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_hifiberry_digi = { + .name = "snd_rpi_hifiberry_digi", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_hifiberry_digi_dai, + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai), + }; +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index 5ade006..2424b00 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -78,6 +78,7 @@ static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_iqaudio_dac = { + .name = "IQaudIODAC", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_iqaudio_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), + }; +diff --git a/sound/soc/bcm/raspidac3.c b/sound/soc/bcm/raspidac3.c +index fddaeec..c2936c5 100644 +--- a/sound/soc/bcm/raspidac3.c ++++ b/sound/soc/bcm/raspidac3.c +@@ -128,6 +128,7 @@ static struct snd_soc_dai_link snd_rpi_raspidac3_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_raspidac3 = { + .name = "RaspiDAC Rev.3x HiFi Audio Card", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_raspidac3_dai, + .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai), + }; +diff --git a/sound/soc/bcm/rpi-dac.c b/sound/soc/bcm/rpi-dac.c +index d5fac1b..59dc89e 100644 +--- a/sound/soc/bcm/rpi-dac.c ++++ b/sound/soc/bcm/rpi-dac.c +@@ -60,6 +60,7 @@ static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_rpi_dac = { + .name = "snd_rpi_rpi_dac", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_rpi_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai), + }; +diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c +index c6e45a0..9db678e 100644 +--- a/sound/soc/bcm/rpi-proto.c ++++ b/sound/soc/bcm/rpi-proto.c +@@ -91,6 +91,7 @@ static struct snd_soc_dai_link snd_rpi_proto_dai[] = { + /* audio machine driver */ + static struct snd_soc_card snd_rpi_proto = { + .name = "snd_rpi_proto", ++ .owner = THIS_MODULE, + .dai_link = snd_rpi_proto_dai, + .num_links = ARRAY_SIZE(snd_rpi_proto_dai), + };