diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt index 82f2acb3d374..0398aec488ac 100644 --- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt +++ b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt @@ -15,6 +15,13 @@ Required children nodes: to external devices using the OF graph reprensentation (see ../graph.txt). At least one port node is required. +Optional properties in grandchild nodes: + Any endpoint grandchild node may specify a desired video interface + according to ../../media/video-interfaces.txt, specifically + - bus-width: recognized values are <12>, <16>, <18> and <24>, and + override any output mode selection heuristic, forcing "rgb444", + "rgb565", "rgb666" and "rgb888" respectively. + Example: hlcdc: hlcdc@f0030000 { @@ -50,3 +57,19 @@ Example: #pwm-cells = <3>; }; }; + +Example 2: With a video interface override to force rgb565; as above +but with these changes/additions: + + &hlcdc { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + bus-width = <16>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index fd39ad34c383..50220190c203 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -22,7 +22,13 @@ among others. Required properties: -- compatible: Must be "lvds-encoder" +- compatible: Must be one or more of the following + - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer + - "lvds-encoder" for a generic LVDS encoder device + + When compatible with the generic version, nodes must list the + device-specific version corresponding to the device first + followed by the generic version. Required nodes: diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt new file mode 100644 index 000000000000..0a3fbb53a16e --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt @@ -0,0 +1,87 @@ +SN65DSI86 DSI to eDP bridge chip +-------------------------------- + +This is the binding for Texas Instruments SN65DSI86 bridge. +http://www.ti.com/general/docs/lit/getliterature.tsp?genericPartNumber=sn65dsi86&fileType=pdf + +Required properties: +- compatible: Must be "ti,sn65dsi86" +- reg: i2c address of the chip, 0x2d as per datasheet +- enable-gpios: gpio specification for bridge_en pin (active high) + +- vccio-supply: A 1.8V supply that powers up the digital IOs. +- vpll-supply: A 1.8V supply that powers up the displayport PLL. +- vcca-supply: A 1.2V supply that powers up the analog circuits. +- vcc-supply: A 1.2V supply that powers up the digital core. + +Optional properties: +- interrupts-extended: Specifier for the SN65DSI86 interrupt line. + +- gpio-controller: Marks the device has a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../../gpio/gpio.txt for more information. +- #pwm-cells : Should be one. See ../../pwm/pwm.txt for description of + the cell formats. + +- clock-names: should be "refclk" +- clocks: Specification for input reference clock. The reference + clock rate must be 12 MHz, 19.2 MHz, 26 MHz, 27 MHz or 38.4 MHz. + +- data-lanes: See ../../media/video-interface.txt +- lane-polarities: See ../../media/video-interface.txt + +- suspend-gpios: specification for GPIO1 pin on bridge (active low) + +Required nodes: +This device has two video ports. Their connections are modelled using the +OF graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for DSI input +- Video port 1 for eDP output + +Example +------- + +edp-bridge@2d { + compatible = "ti,sn65dsi86"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + + enable-gpios = <&msmgpio 33 GPIO_ACTIVE_HIGH>; + suspend-gpios = <&msmgpio 34 GPIO_ACTIVE_LOW>; + + interrupts-extended = <&gpio3 4 IRQ_TYPE_EDGE_FALLING>; + + vccio-supply = <&pm8916_l17>; + vcca-supply = <&pm8916_l6>; + vpll-supply = <&pm8916_l17>; + vcc-supply = <&pm8916_l6>; + + clock-names = "refclk"; + clocks = <&input_refclk>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + edp_bridge_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + edp_bridge_out: endpoint { + data-lanes = <2 1 3 0>; + lane-polarities = <0 1 0 1>; + remote-endpoint = <&edp_panel_in>; + }; + }; + }; +} diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt new file mode 100644 index 000000000000..8f9abf28a8fa --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt @@ -0,0 +1,35 @@ +TC358764 MIPI-DSI to LVDS panel bridge + +Required properties: + - compatible: "toshiba,tc358764" + - reg: the virtual channel number of a DSI peripheral + - vddc-supply: core voltage supply, 1.2V + - vddio-supply: I/O voltage supply, 1.8V or 3.3V + - vddlvds-supply: LVDS1/2 voltage supply, 3.3V + - reset-gpios: a GPIO spec for the reset pin + +The device node can contain following 'port' child nodes, +according to the OF graph bindings defined in [1]: + 0: DSI Input, not required, if the bridge is DSI controlled + 1: LVDS Output, mandatory + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + bridge@0 { + reg = <0>; + compatible = "toshiba,tc358764"; + vddc-supply = <&vcc_1v2_reg>; + vddio-supply = <&vcc_1v8_reg>; + vddlvds-supply = <&vcc_3v3_reg>; + reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + lvds_ep: endpoint { + remote-endpoint = <&panel_ep>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt index 973c27273772..a336599f6c03 100644 --- a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt +++ b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt @@ -16,7 +16,7 @@ The following assumes that only a single peripheral is connected to a DSI host. Experience shows that this is true for the large majority of setups. DSI host --------- +======== In addition to the standard properties and those defined by the parent bus of a DSI host, the following properties apply to a node representing a DSI host. @@ -29,12 +29,24 @@ Required properties: - #size-cells: Should be 0. There are cases where it makes sense to use a different value here. See below. -DSI peripheral --------------- +Optional properties: +- clock-master: boolean. Should be enabled if the host is being used in + conjunction with another DSI host to drive the same peripheral. Hardware + supporting such a configuration generally requires the data on both the busses + to be driven by the same clock. Only the DSI host instance controlling this + clock should contain this property. -Peripherals are represented as child nodes of the DSI host's node. Properties -described here apply to all DSI peripherals, but individual bindings may want -to define additional, device-specific properties. +DSI peripheral +============== + +Peripherals with DSI as control bus, or no control bus +------------------------------------------------------ + +Peripherals with the DSI bus as the primary control bus, or peripherals with +no control bus but use the DSI bus to transmit pixel data are represented +as child nodes of the DSI host's node. Properties described here apply to all +DSI peripherals, but individual bindings may want to define additional, +device-specific properties. Required properties: - reg: The virtual channel number of a DSI peripheral. Must be in the range @@ -49,9 +61,37 @@ case two alternative representations can be chosen: property is the number of the first virtual channel and the second cell is the number of consecutive virtual channels. -Example -------- +Peripherals with a different control bus +---------------------------------------- +There are peripherals that have I2C/SPI (or some other non-DSI bus) as the +primary control bus, but are also connected to a DSI bus (mostly for the data +path). Connections between such peripherals and a DSI host can be represented +using the graph bindings [1], [2]. + +Peripherals that support dual channel DSI +----------------------------------------- + +Peripherals with higher bandwidth requirements can be connected to 2 DSI +busses. Each DSI bus/channel drives some portion of the pixel data (generally +left/right half of each line of the display, or even/odd lines of the display). +The graph bindings should be used to represent the multiple DSI busses that are +connected to this peripheral. Each DSI host's output endpoint can be linked to +an input endpoint of the DSI peripheral. + +[1] Documentation/devicetree/bindings/graph.txt +[2] Documentation/devicetree/bindings/media/video-interfaces.txt + +Examples +======== +- (1), (2) and (3) are examples of a DSI host and peripheral on the DSI bus + with different virtual channel configurations. +- (4) is an example of a peripheral on a I2C control bus connected to a + DSI host using of-graph bindings. +- (5) is an example of 2 DSI hosts driving a dual-channel DSI peripheral, + which uses I2C as its primary control bus. + +1) dsi-host { ... @@ -67,6 +107,7 @@ Example ... }; +2) dsi-host { ... @@ -82,6 +123,7 @@ Example ... }; +3) dsi-host { ... @@ -96,3 +138,98 @@ Example ... }; + +4) + i2c-host { + ... + + dsi-bridge@35 { + compatible = "..."; + reg = <0x35>; + + ports { + ... + + port { + bridge_mipi_in: endpoint { + remote-endpoint = <&host_mipi_out>; + }; + }; + }; + }; + }; + + dsi-host { + ... + + ports { + ... + + port { + host_mipi_out: endpoint { + remote-endpoint = <&bridge_mipi_in>; + }; + }; + }; + }; + +5) + i2c-host { + dsi-bridge@35 { + compatible = "..."; + reg = <0x35>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_in: endpoint { + remote-endpoint = <&dsi1_out>; + }; + }; + }; + }; + }; + + dsi0-host { + ... + + /* + * this DSI instance drives the clock for both the host + * controllers + */ + clock-master; + + ports { + ... + + port { + dsi0_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + + dsi1-host { + ... + + ports { + ... + + port { + dsi1_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index eeda3597011e..b79e5769f0ae 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -8,6 +8,9 @@ Required properties: - compatible: value should be one of the following "rockchip,rk3036-vop"; "rockchip,rk3126-vop"; + "rockchip,px30-vop-lit"; + "rockchip,px30-vop-big"; + "rockchip,rk3188-vop"; "rockchip,rk3288-vop"; "rockchip,rk3368-vop"; "rockchip,rk3366-vop"; diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index f8773ecb7525..0bbb5d47f228 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -78,6 +78,7 @@ Required properties: - compatible: value must be one of: * "allwinner,sun8i-a83t-dw-hdmi" + * "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi" - reg: base address and size of memory-mapped region - reg-io-width: See dw_hdmi.txt. Shall be 1. - interrupts: HDMI interrupt number @@ -96,6 +97,9 @@ Required properties: first port should be the input endpoint. The second should be the output, usually to an HDMI connector. +Optional properties: + - hvcc-supply: the VCC power supply of the controller + DWC HDMI PHY ------------ @@ -151,6 +155,8 @@ Required properties: * allwinner,sun8i-v3s-tcon * allwinner,sun9i-a80-tcon-lcd * allwinner,sun9i-a80-tcon-tv + * "allwinner,sun50i-a64-tcon-lcd", "allwinner,sun8i-a83t-tcon-lcd" + * "allwinner,sun50i-a64-tcon-tv", "allwinner,sun8i-a83t-tcon-tv" - reg: base address and size of memory-mapped region - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the TCON. @@ -370,6 +376,8 @@ Required properties: * allwinner,sun8i-a83t-de2-mixer-1 * allwinner,sun8i-h3-de2-mixer-0 * allwinner,sun8i-v3s-de2-mixer + * allwinner,sun50i-a64-de2-mixer-0 + * allwinner,sun50i-a64-de2-mixer-1 - reg: base address and size of the memory-mapped region. - clocks: phandles to the clocks feeding the mixer * bus: the mixer interface clock @@ -403,6 +411,7 @@ Required properties: * allwinner,sun8i-r40-display-engine * allwinner,sun8i-v3s-display-engine * allwinner,sun9i-a80-display-engine + * allwinner,sun50i-a64-display-engine - allwinner,pipelines: list of phandle to the display engine frontends (DE 1.0) or mixers (DE 2.0) available. diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 5dee6b8a4c12..f8f5bf11a6ca 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -323,6 +323,12 @@ Frame Buffer Functions Reference DRM Format Handling =================== +.. kernel-doc:: include/uapi/drm/drm_fourcc.h + :doc: overview + +Format Functions Reference +-------------------------- + .. kernel-doc:: include/drm/drm_fourcc.h :internal: diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 21b6b72a9ba8..c3ae888b92ef 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -297,7 +297,7 @@ made up of several fields, the more interesting ones being: struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); - int (*fault)(struct vm_fault *vmf); + vm_fault_t (*fault)(struct vm_fault *vmf); }; diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 13a7c999c04a..f2ac672eb766 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 'u' 00-1F linux/smb_fs.h gone 'u' 20-3F linux/uvcvideo.h USB video class host driver +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device 'v' 00-1F linux/ext2_fs.h conflict! 'v' 00-1F linux/fs.h conflict! 'v' 00-0F linux/sonypi.h conflict! diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052aeac39..029baa270a11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15343,6 +15343,14 @@ F: arch/x86/um/ F: fs/hostfs/ F: fs/hppfs/ +USERSPACE DMA BUFFER DRIVER +M: Gerd Hoffmann +S: Maintained +L: dri-devel@lists.freedesktop.org +F: drivers/dma-buf/udmabuf.c +F: include/uapi/linux/udmabuf.h +T: git git://anongit.freedesktop.org/drm/drm-misc + USERSPACE I/O (UIO) M: Greg Kroah-Hartman S: Maintained diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index ed3b785bae37..338129eb126f 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -30,4 +30,12 @@ config SW_SYNC WARNING: improper use of this can result in deadlocking kernel drivers from userspace. Intended for test and debug only. +config UDMABUF + bool "userspace dmabuf misc driver" + default n + depends on DMA_SHARED_BUFFER + help + A driver to let userspace turn memfd regions into dma-bufs. + Qemu can use this to create host dmabufs for guest framebuffers. + endmenu diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index c33bf8863147..0913a6ccab5a 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,3 +1,4 @@ obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o obj-$(CONFIG_SYNC_FILE) += sync_file.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +obj-$(CONFIG_UDMABUF) += udmabuf.o diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 13884474d158..02f7f9a89979 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -405,7 +405,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) || !exp_info->ops->map_dma_buf || !exp_info->ops->unmap_dma_buf || !exp_info->ops->release - || !exp_info->ops->map || !exp_info->ops->mmap)) { return ERR_PTR(-EINVAL); } diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c new file mode 100644 index 000000000000..2e8502250afe --- /dev/null +++ b/drivers/dma-buf/udmabuf.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct udmabuf { + u32 pagecount; + struct page **pages; +}; + +static int udmabuf_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct udmabuf *ubuf = vma->vm_private_data; + + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) + return VM_FAULT_SIGBUS; + + vmf->page = ubuf->pages[vmf->pgoff]; + get_page(vmf->page); + return 0; +} + +static const struct vm_operations_struct udmabuf_vm_ops = { + .fault = udmabuf_vm_fault, +}; + +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) +{ + struct udmabuf *ubuf = buf->priv; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + vma->vm_ops = &udmabuf_vm_ops; + vma->vm_private_data = ubuf; + return 0; +} + +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, + enum dma_data_direction direction) +{ + struct udmabuf *ubuf = at->dmabuf->priv; + struct sg_table *sg; + + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + goto err1; + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, + 0, ubuf->pagecount << PAGE_SHIFT, + GFP_KERNEL) < 0) + goto err2; + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) + goto err3; + + return sg; + +err3: + sg_free_table(sg); +err2: + kfree(sg); +err1: + return ERR_PTR(-ENOMEM); +} + +static void unmap_udmabuf(struct dma_buf_attachment *at, + struct sg_table *sg, + enum dma_data_direction direction) +{ + sg_free_table(sg); + kfree(sg); +} + +static void release_udmabuf(struct dma_buf *buf) +{ + struct udmabuf *ubuf = buf->priv; + pgoff_t pg; + + for (pg = 0; pg < ubuf->pagecount; pg++) + put_page(ubuf->pages[pg]); + kfree(ubuf->pages); + kfree(ubuf); +} + +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) +{ + struct udmabuf *ubuf = buf->priv; + struct page *page = ubuf->pages[page_num]; + + return kmap(page); +} + +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, + void *vaddr) +{ + kunmap(vaddr); +} + +static struct dma_buf_ops udmabuf_ops = { + .map_dma_buf = map_udmabuf, + .unmap_dma_buf = unmap_udmabuf, + .release = release_udmabuf, + .map = kmap_udmabuf, + .unmap = kunmap_udmabuf, + .mmap = mmap_udmabuf, +}; + +#define SEALS_WANTED (F_SEAL_SHRINK) +#define SEALS_DENIED (F_SEAL_WRITE) + +static long udmabuf_create(struct udmabuf_create_list *head, + struct udmabuf_create_item *list) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct file *memfd = NULL; + struct udmabuf *ubuf; + struct dma_buf *buf; + pgoff_t pgoff, pgcnt, pgidx, pgbuf; + struct page *page; + int seals, ret = -EINVAL; + u32 i, flags; + + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); + if (!ubuf) + return -ENOMEM; + + for (i = 0; i < head->count; i++) { + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) + goto err_free_ubuf; + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) + goto err_free_ubuf; + ubuf->pagecount += list[i].size >> PAGE_SHIFT; + } + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), + GFP_KERNEL); + if (!ubuf->pages) { + ret = -ENOMEM; + goto err_free_ubuf; + } + + pgbuf = 0; + for (i = 0; i < head->count; i++) { + memfd = fget(list[i].memfd); + if (!memfd) + goto err_put_pages; + if (!shmem_mapping(file_inode(memfd)->i_mapping)) + goto err_put_pages; + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); + if (seals == -EINVAL || + (seals & SEALS_WANTED) != SEALS_WANTED || + (seals & SEALS_DENIED) != 0) + goto err_put_pages; + pgoff = list[i].offset >> PAGE_SHIFT; + pgcnt = list[i].size >> PAGE_SHIFT; + for (pgidx = 0; pgidx < pgcnt; pgidx++) { + page = shmem_read_mapping_page( + file_inode(memfd)->i_mapping, pgoff + pgidx); + if (IS_ERR(page)) { + ret = PTR_ERR(page); + goto err_put_pages; + } + ubuf->pages[pgbuf++] = page; + } + fput(memfd); + } + memfd = NULL; + + exp_info.ops = &udmabuf_ops; + exp_info.size = ubuf->pagecount << PAGE_SHIFT; + exp_info.priv = ubuf; + + buf = dma_buf_export(&exp_info); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto err_put_pages; + } + + flags = 0; + if (head->flags & UDMABUF_FLAGS_CLOEXEC) + flags |= O_CLOEXEC; + return dma_buf_fd(buf, flags); + +err_put_pages: + while (pgbuf > 0) + put_page(ubuf->pages[--pgbuf]); +err_free_ubuf: + if (memfd) + fput(memfd); + kfree(ubuf->pages); + kfree(ubuf); + return ret; +} + +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) +{ + struct udmabuf_create create; + struct udmabuf_create_list head; + struct udmabuf_create_item list; + + if (copy_from_user(&create, (void __user *)arg, + sizeof(struct udmabuf_create))) + return -EFAULT; + + head.flags = create.flags; + head.count = 1; + list.memfd = create.memfd; + list.offset = create.offset; + list.size = create.size; + + return udmabuf_create(&head, &list); +} + +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) +{ + struct udmabuf_create_list head; + struct udmabuf_create_item *list; + int ret = -EINVAL; + u32 lsize; + + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) + return -EFAULT; + if (head.count > 1024) + return -EINVAL; + lsize = sizeof(struct udmabuf_create_item) * head.count; + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); + if (IS_ERR(list)) + return PTR_ERR(list); + + ret = udmabuf_create(&head, list); + kfree(list); + return ret; +} + +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) +{ + long ret; + + switch (ioctl) { + case UDMABUF_CREATE: + ret = udmabuf_ioctl_create(filp, arg); + break; + case UDMABUF_CREATE_LIST: + ret = udmabuf_ioctl_create_list(filp, arg); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations udmabuf_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = udmabuf_ioctl, +}; + +static struct miscdevice udmabuf_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "udmabuf", + .fops = &udmabuf_fops, +}; + +static int __init udmabuf_dev_init(void) +{ + return misc_register(&udmabuf_misc); +} + +static void __exit udmabuf_dev_exit(void) +{ + misc_deregister(&udmabuf_misc); +} + +module_init(udmabuf_dev_init) +module_exit(udmabuf_dev_exit) + +MODULE_AUTHOR("Gerd Hoffmann "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8843a06360fa..6870909da926 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -785,28 +785,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist); static struct drm_driver kms_driver; -static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev) -{ - struct apertures_struct *ap; - bool primary = false; - - ap = alloc_apertures(1); - if (!ap) - return -ENOMEM; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - -#ifdef CONFIG_X86 - primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; -#endif - drm_fb_helper_remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary); - kfree(ap); - - return 0; -} - - static int amdgpu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -834,7 +812,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, return ret; /* Get rid of things like offb */ - ret = amdgpu_kick_out_firmware_fb(pdev); + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "amdgpudrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 800f481a6995..af6adffba788 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -896,6 +896,7 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector) aconnector->dc_sink = sink; if (sink->dc_edid.length == 0) { aconnector->edid = NULL; + drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); } else { aconnector->edid = (struct edid *) sink->dc_edid.raw_edid; @@ -903,10 +904,13 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector) drm_connector_update_edid_property(connector, aconnector->edid); + drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, + aconnector->edid); } amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid); } else { + drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); amdgpu_dm_remove_sink_from_freesync_module(connector); drm_connector_update_edid_property(connector, NULL); aconnector->num_modes = 0; @@ -1061,8 +1065,10 @@ static void handle_hpd_rx_irq(void *param) (dc_link->type == dc_connection_mst_branch)) dm_handle_hpd_rx_irq(aconnector); - if (dc_link->type != dc_connection_mst_branch) + if (dc_link->type != dc_connection_mst_branch) { + drm_dp_cec_irq(&aconnector->dm_dp_aux.aux); mutex_unlock(&aconnector->hpd_lock); + } } static void register_hpd_handlers(struct amdgpu_device *adev) @@ -2595,6 +2601,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .atomic_duplicate_state = dm_crtc_duplicate_state, .atomic_destroy_state = dm_crtc_destroy_state, .set_crc_source = amdgpu_dm_crtc_set_crc_source, + .verify_crc_source = amdgpu_dm_crtc_verify_crc_source, .enable_vblank = dm_enable_vblank, .disable_vblank = dm_disable_vblank, }; @@ -2730,6 +2737,7 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector) dm->backlight_dev = NULL; } #endif + drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux); drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(connector); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index a29dc35954c9..54056d180003 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -258,11 +258,14 @@ amdgpu_dm_remove_sink_from_freesync_module(struct drm_connector *connector); /* amdgpu_dm_crc.c */ #ifdef CONFIG_DEBUG_FS -int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, - size_t *values_cnt); +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name); +int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, + const char *src_name, + size_t *values_cnt); void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); #else #define amdgpu_dm_crtc_set_crc_source NULL +#define amdgpu_dm_crtc_verify_crc_source NULL #define amdgpu_dm_crtc_handle_crc_irq(x) #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 9bfb040352e9..01fc5717b657 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -46,8 +46,23 @@ static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source) return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID; } -int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, - size_t *values_cnt) +int +amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, + size_t *values_cnt) +{ + enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); + + if (source < 0) { + DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", + src_name, crtc->index); + return -EINVAL; + } + + *values_cnt = 3; + return 0; +} + +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); struct dc_stream_state *stream_state = crtc_state->stream; @@ -83,7 +98,6 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, return -EINVAL; } - *values_cnt = 3; /* Reset crc_skipped on dm state */ crtc_state->crc_skip_count = 0; return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 9a300732ba37..18a3a6e5ffa0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -496,6 +496,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc; drm_dp_aux_register(&aconnector->dm_dp_aux.aux); + drm_dp_cec_register_connector(&aconnector->dm_dp_aux.aux, + aconnector->base.name, dm->adev->dev); aconnector->mst_mgr.cbs = &dm_mst_cbs; drm_dp_mst_topology_mgr_init( &aconnector->mst_mgr, diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 29409a65d864..49c37f6dd63e 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -78,11 +78,8 @@ static void malidp_plane_reset(struct drm_plane *plane) kfree(state); plane->state = NULL; state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state) { - state->base.plane = plane; - state->base.rotation = DRM_MODE_ROTATE_0; - plane->state = &state->base; - } + if (state) + __drm_atomic_helper_plane_reset(plane, &state->base); } static struct diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index d73281095fac..9e34bce089d0 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -101,18 +101,34 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) (adj->crtc_hdisplay - 1) | ((adj->crtc_vdisplay - 1) << 16)); - cfg = 0; + cfg = ATMEL_HLCDC_CLKSEL; - prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); + prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk); mode_rate = adj->crtc_clock * 1000; - if ((prate / 2) < mode_rate) { - prate *= 2; - cfg |= ATMEL_HLCDC_CLKSEL; - } div = DIV_ROUND_UP(prate, mode_rate); - if (div < 2) + if (div < 2) { div = 2; + } else if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) { + /* The divider ended up too big, try a lower base rate. */ + cfg &= ~ATMEL_HLCDC_CLKSEL; + prate /= 2; + div = DIV_ROUND_UP(prate, mode_rate); + if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) + div = ATMEL_HLCDC_CLKDIV_MASK; + } else { + int div_low = prate / mode_rate; + + if (div_low >= 2 && + ((prate / div_low - mode_rate) < + 10 * (mode_rate - prate / div))) + /* + * At least 10 times better when using a higher + * frequency than requested, instead of a lower. + * So, go with that. + */ + div = div_low; + } cfg |= ATMEL_HLCDC_CLKDIV(div); @@ -226,6 +242,55 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c, #define ATMEL_HLCDC_RGB888_OUTPUT BIT(3) #define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0) +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state) +{ + struct drm_connector *connector = state->connector; + struct drm_display_info *info = &connector->display_info; + struct drm_encoder *encoder; + unsigned int supported_fmts = 0; + int j; + + encoder = state->best_encoder; + if (!encoder) + encoder = connector->encoder; + + switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) { + case 0: + break; + case MEDIA_BUS_FMT_RGB444_1X12: + return ATMEL_HLCDC_RGB444_OUTPUT; + case MEDIA_BUS_FMT_RGB565_1X16: + return ATMEL_HLCDC_RGB565_OUTPUT; + case MEDIA_BUS_FMT_RGB666_1X18: + return ATMEL_HLCDC_RGB666_OUTPUT; + case MEDIA_BUS_FMT_RGB888_1X24: + return ATMEL_HLCDC_RGB888_OUTPUT; + default: + return -EINVAL; + } + + for (j = 0; j < info->num_bus_formats; j++) { + switch (info->bus_formats[j]) { + case MEDIA_BUS_FMT_RGB444_1X12: + supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT; + break; + case MEDIA_BUS_FMT_RGB565_1X16: + supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT; + break; + default: + break; + } + } + + return supported_fmts; +} + static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state) { unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK; @@ -238,31 +303,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state) crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc); for_each_new_connector_in_state(state->state, connector, cstate, i) { - struct drm_display_info *info = &connector->display_info; unsigned int supported_fmts = 0; - int j; if (!cstate->crtc) continue; - for (j = 0; j < info->num_bus_formats; j++) { - switch (info->bus_formats[j]) { - case MEDIA_BUS_FMT_RGB444_1X12: - supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT; - break; - case MEDIA_BUS_FMT_RGB565_1X16: - supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT; - break; - case MEDIA_BUS_FMT_RGB666_1X18: - supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT; - break; - case MEDIA_BUS_FMT_RGB888_1X24: - supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT; - break; - default: - break; - } - } + supported_fmts = atmel_hlcdc_connector_output_mode(cstate); if (crtc->dc->desc->conflicting_output_formats) output_fmts &= supported_fmts; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h index 60c937f42114..4cc1e03f0aee 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h @@ -441,5 +441,6 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c); int atmel_hlcdc_crtc_create(struct drm_device *dev); int atmel_hlcdc_create_outputs(struct drm_device *dev); +int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder); #endif /* DRM_ATMEL_HLCDC_H */ diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index 8db51fb131db..f73d8a92274e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -27,33 +27,94 @@ #include "atmel_hlcdc_dc.h" +struct atmel_hlcdc_rgb_output { + struct drm_encoder encoder; + int bus_fmt; +}; + static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static struct atmel_hlcdc_rgb_output * +atmel_hlcdc_encoder_to_rgb_output(struct drm_encoder *encoder) +{ + return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder); +} + +int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder) +{ + struct atmel_hlcdc_rgb_output *output; + + output = atmel_hlcdc_encoder_to_rgb_output(encoder); + + return output->bus_fmt; +} + +static int atmel_hlcdc_of_bus_fmt(const struct device_node *ep) +{ + u32 bus_width; + int ret; + + ret = of_property_read_u32(ep, "bus-width", &bus_width); + if (ret == -EINVAL) + return 0; + if (ret) + return ret; + + switch (bus_width) { + case 12: + return MEDIA_BUS_FMT_RGB444_1X12; + case 16: + return MEDIA_BUS_FMT_RGB565_1X16; + case 18: + return MEDIA_BUS_FMT_RGB666_1X18; + case 24: + return MEDIA_BUS_FMT_RGB888_1X24; + default: + return -EINVAL; + } +} + static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) { - struct drm_encoder *encoder; + struct atmel_hlcdc_rgb_output *output; + struct device_node *ep; struct drm_panel *panel; struct drm_bridge *bridge; int ret; + ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint); + if (!ep) + return -ENODEV; + ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint, &panel, &bridge); - if (ret) + if (ret) { + of_node_put(ep); return ret; + } - encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL); - if (!encoder) + output = devm_kzalloc(dev->dev, sizeof(*output), GFP_KERNEL); + if (!output) { + of_node_put(ep); + return -ENOMEM; + } + + output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep); + of_node_put(ep); + if (output->bus_fmt < 0) { + dev_err(dev->dev, "endpoint %d: invalid bus width\n", endpoint); return -EINVAL; + } - ret = drm_encoder_init(dev, encoder, + ret = drm_encoder_init(dev, &output->encoder, &atmel_hlcdc_panel_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); if (ret) return ret; - encoder->possible_crtcs = 0x1; + output->encoder.possible_crtcs = 0x1; if (panel) { bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown); @@ -62,7 +123,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) } if (bridge) { - ret = drm_bridge_attach(encoder, bridge, NULL); + ret = drm_bridge_attach(&output->encoder, bridge, NULL); if (!ret) return 0; @@ -70,7 +131,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) drm_panel_bridge_remove(bridge); } - drm_encoder_cleanup(encoder); + drm_encoder_cleanup(&output->encoder); return ret; } @@ -78,12 +139,23 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) int atmel_hlcdc_create_outputs(struct drm_device *dev) { int endpoint, ret = 0; + int attached = 0; - for (endpoint = 0; !ret; endpoint++) + /* + * Always scan the first few endpoints even if we get -ENODEV, + * but keep going after that as long as we keep getting hits. + */ + for (endpoint = 0; !ret || endpoint < 4; endpoint++) { ret = atmel_hlcdc_attach_endpoint(dev, endpoint); + if (ret == -ENODEV) + continue; + if (ret) + break; + attached++; + } /* At least one device was successfully attached.*/ - if (ret == -ENODEV && endpoint) + if (ret == -ENODEV && attached) return 0; return ret; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 04440064b9b7..9330a076e15a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -942,10 +942,7 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p) "Failed to allocate initial plane state\n"); return; } - - p->state = &state->base; - p->state->alpha = DRM_BLEND_ALPHA_OPAQUE; - p->state->plane = p; + __drm_atomic_helper_plane_reset(p, &state->base); } } diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 7b20318483e4..c61b40c72b62 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -143,22 +143,6 @@ static const struct dev_pm_ops bochs_pm_ops = { /* ---------------------------------------------------------------------- */ /* pci interface */ -static int bochs_kick_out_firmware_fb(struct pci_dev *pdev) -{ - struct apertures_struct *ap; - - ap = alloc_apertures(1); - if (!ap) - return -ENOMEM; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - drm_fb_helper_remove_conflicting_framebuffers(ap, "bochsdrmfb", false); - kfree(ap); - - return 0; -} - static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -171,7 +155,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - ret = bochs_kick_out_firmware_fb(pdev); + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 39cd08416773..c9c7097030ca 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -430,7 +430,7 @@ static void bochs_bo_unref(struct bochs_bo **bo) return; tbo = &((*bo)->bo); - ttm_bo_unref(&tbo); + ttm_bo_put(tbo); *bo = NULL; } diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index bf6cad6c9178..9eeb8ef0b174 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -112,6 +112,14 @@ config DRM_THINE_THC63LVD1024 ---help--- Thine THC63LVD1024 LVDS/parallel converter driver. +config DRM_TOSHIBA_TC358764 + tristate "TC358764 DSI/LVDS bridge" + depends on DRM && DRM_PANEL + depends on OF + select DRM_MIPI_DSI + help + Toshiba TC358764 DSI/LVDS bridge driver. + config DRM_TOSHIBA_TC358767 tristate "Toshiba TC358767 eDP bridge" depends on OF @@ -128,6 +136,16 @@ config DRM_TI_TFP410 ---help--- Texas Instruments TFP410 DVI/HDMI Transmitter driver +config DRM_TI_SN65DSI86 + tristate "TI SN65DSI86 DSI to eDP bridge" + depends on OF + select DRM_KMS_HELPER + select REGMAP_I2C + select DRM_PANEL + select DRM_MIPI_DSI + help + Texas Instruments SN65DSI86 DSI to eDP Bridge driver + source "drivers/gpu/drm/bridge/analogix/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 35f88d48ec20..4934fcf5a6f8 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -10,8 +10,10 @@ obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o obj-$(CONFIG_DRM_SII902X) += sii902x.o obj-$(CONFIG_DRM_SII9234) += sii9234.o obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o +obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ +obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile index 5dad97d920be..3e1b1e3d9533 100644 --- a/drivers/gpu/drm/bridge/synopsys/Makefile +++ b/drivers/gpu/drm/bridge/synopsys/Makefile @@ -1,5 +1,3 @@ -#ccflags-y := -Iinclude/drm - obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c new file mode 100644 index 000000000000..ee6b98efa9c2 --- /dev/null +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Samsung Electronics Co., Ltd + * + * Authors: + * Andrzej Hajda + * Maciej Purski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include