From 26e08a6da54c575c69a113ab0c41c2890c0d613d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 4 Dec 2020 21:02:42 +0100 Subject: dma-buf: Fix kerneldoc formatting I wanted to look up something and noticed the hyperlink doesn't work. While fixing that also noticed a trivial kerneldoc comment typo in the same section, fix that too. Reviewed-by: Michael J. Ruhl Reviewed-by: Simon Ser Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20201204200242.2671481-1-daniel.vetter@ffwll.ch --- include/linux/dma-buf-map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h index 583a3a1f9447..278d489e4bdd 100644 --- a/include/linux/dma-buf-map.h +++ b/include/linux/dma-buf-map.h @@ -122,7 +122,7 @@ struct dma_buf_map { /** * DMA_BUF_MAP_INIT_VADDR - Initializes struct dma_buf_map to an address in system memory - * @vaddr: A system-memory address + * @vaddr_: A system-memory address */ #define DMA_BUF_MAP_INIT_VADDR(vaddr_) \ { \ -- cgit v1.2.3 From de9114ece5dfcc422164a24a687785843ed92c47 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 11 Dec 2020 16:58:40 +0100 Subject: dma-buf: Remove kmap kerneldoc vestiges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also try to clarify a bit when dma_buf_begin/end_cpu_access should be called. Acked-by: Christian König Signed-off-by: Daniel Vetter Cc: Thomas Zimmermann Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20201211155843.3348718-1-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-buf.c | 20 ++++++++++++++------ include/linux/dma-buf.h | 25 +++++++++---------------- 2 files changed, 23 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index e63684d4cd90..a12fdffa130f 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1001,15 +1001,15 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify); * vmalloc space might be limited and result in vmap calls failing. * * Interfaces:: + * * void \*dma_buf_vmap(struct dma_buf \*dmabuf) * void dma_buf_vunmap(struct dma_buf \*dmabuf, void \*vaddr) * * The vmap call can fail if there is no vmap support in the exporter, or if - * it runs out of vmalloc space. Fallback to kmap should be implemented. Note - * that the dma-buf layer keeps a reference count for all vmap access and - * calls down into the exporter's vmap function only when no vmapping exists, - * and only unmaps it once. Protection against concurrent vmap/vunmap calls is - * provided by taking the dma_buf->lock mutex. + * it runs out of vmalloc space. Note that the dma-buf layer keeps a reference + * count for all vmap access and calls down into the exporter's vmap function + * only when no vmapping exists, and only unmaps it once. Protection against + * concurrent vmap/vunmap calls is provided by taking the &dma_buf.lock mutex. * * - For full compatibility on the importer side with existing userspace * interfaces, which might already support mmap'ing buffers. This is needed in @@ -1098,6 +1098,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf, * dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is * it guaranteed to be coherent with other DMA access. * + * This function will also wait for any DMA transactions tracked through + * implicit synchronization in &dma_buf.resv. For DMA transactions with explicit + * synchronization this function will only ensure cache coherency, callers must + * ensure synchronization with such DMA transactions on their own. + * * Can return negative error values, returns 0 on success. */ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, @@ -1199,7 +1204,10 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap); * This call may fail due to lack of virtual mapping address space. * These calls are optional in drivers. The intended use for them * is for mapping objects linear in kernel space for high use objects. - * Please attempt to use kmap/kunmap before thinking about these interfaces. + * + * To ensure coherency users must call dma_buf_begin_cpu_access() and + * dma_buf_end_cpu_access() around any cpu access performed through this + * mapping. * * Returns 0 on success, or a negative errno code otherwise. */ diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index cf72699cb2bc..7eca37c8b10c 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -183,24 +183,19 @@ struct dma_buf_ops { * @begin_cpu_access: * * This is called from dma_buf_begin_cpu_access() and allows the - * exporter to ensure that the memory is actually available for cpu - * access - the exporter might need to allocate or swap-in and pin the - * backing storage. The exporter also needs to ensure that cpu access is - * coherent for the access direction. The direction can be used by the - * exporter to optimize the cache flushing, i.e. access with a different + * exporter to ensure that the memory is actually coherent for cpu + * access. The exporter also needs to ensure that cpu access is coherent + * for the access direction. The direction can be used by the exporter + * to optimize the cache flushing, i.e. access with a different * direction (read instead of write) might return stale or even bogus * data (e.g. when the exporter needs to copy the data to temporary * storage). * - * This callback is optional. + * Note that this is both called through the DMA_BUF_IOCTL_SYNC IOCTL + * command for userspace mappings established through @mmap, and also + * for kernel mappings established with @vmap. * - * FIXME: This is both called through the DMA_BUF_IOCTL_SYNC command - * from userspace (where storage shouldn't be pinned to avoid handing - * de-factor mlock rights to userspace) and for the kernel-internal - * users of the various kmap interfaces, where the backing storage must - * be pinned to guarantee that the atomic kmap calls can succeed. Since - * there's no in-kernel users of the kmap interfaces yet this isn't a - * real problem. + * This callback is optional. * * Returns: * @@ -216,9 +211,7 @@ struct dma_buf_ops { * * This is called from dma_buf_end_cpu_access() when the importer is * done accessing the CPU. The exporter can use this to flush caches and - * unpin any resources pinned in @begin_cpu_access. - * The result of any dma_buf kmap calls after end_cpu_access is - * undefined. + * undo anything else done in @begin_cpu_access. * * This callback is optional. * -- cgit v1.2.3 From 85804b70cca68d77bca419b493ab843bf710de68 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 11 Dec 2020 16:58:41 +0100 Subject: dma-buf: some kerneldoc formatting fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed while reviewing the output. Adds a bunch more links and fixes the function interface quoting. Acked-by: Christian König Signed-off-by: Daniel Vetter Cc: Thomas Zimmermann Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20201211155843.3348718-2-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-buf.c | 31 ++++++++++++++++++------------- include/linux/dma-buf.h | 6 +++--- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a12fdffa130f..e1fa6c6f02c4 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -480,7 +480,7 @@ err_alloc_file: * * 4. Once a driver is done with a shared buffer it needs to call * dma_buf_detach() (after cleaning up any mappings) and then release the - * reference acquired with dma_buf_get by calling dma_buf_put(). + * reference acquired with dma_buf_get() by calling dma_buf_put(). * * For the detailed semantics exporters are expected to implement see * &dma_buf_ops. @@ -496,9 +496,10 @@ err_alloc_file: * by the exporter. see &struct dma_buf_export_info * for further details. * - * Returns, on success, a newly created dma_buf object, which wraps the - * supplied private data and operations for dma_buf_ops. On either missing - * ops, or error in allocating struct dma_buf, will return negative error. + * Returns, on success, a newly created struct dma_buf object, which wraps the + * supplied private data and operations for struct dma_buf_ops. On either + * missing ops, or error in allocating struct dma_buf, will return negative + * error. * * For most cases the easiest way to create @exp_info is through the * %DEFINE_DMA_BUF_EXPORT_INFO macro. @@ -584,7 +585,7 @@ err_module: EXPORT_SYMBOL_GPL(dma_buf_export); /** - * dma_buf_fd - returns a file descriptor for the given dma_buf + * dma_buf_fd - returns a file descriptor for the given struct dma_buf * @dmabuf: [in] pointer to dma_buf for which fd is required. * @flags: [in] flags to give to fd * @@ -608,10 +609,10 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags) EXPORT_SYMBOL_GPL(dma_buf_fd); /** - * dma_buf_get - returns the dma_buf structure related to an fd - * @fd: [in] fd associated with the dma_buf to be returned + * dma_buf_get - returns the struct dma_buf related to an fd + * @fd: [in] fd associated with the struct dma_buf to be returned * - * On success, returns the dma_buf structure associated with an fd; uses + * On success, returns the struct dma_buf associated with an fd; uses * file's refcounting done by fget to increase refcount. returns ERR_PTR * otherwise. */ @@ -653,8 +654,7 @@ void dma_buf_put(struct dma_buf *dmabuf) EXPORT_SYMBOL_GPL(dma_buf_put); /** - * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list; optionally, - * calls attach() of dma_buf_ops to allow device-specific attach functionality + * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list * @dmabuf: [in] buffer to attach device to. * @dev: [in] device to be attached. * @importer_ops: [in] importer operations for the attachment @@ -663,6 +663,9 @@ EXPORT_SYMBOL_GPL(dma_buf_put); * Returns struct dma_buf_attachment pointer for this attachment. Attachments * must be cleaned up by calling dma_buf_detach(). * + * Optionally this calls &dma_buf_ops.attach to allow device-specific attach + * functionality. + * * Returns: * * A pointer to newly created &dma_buf_attachment on success, or a negative @@ -769,12 +772,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, EXPORT_SYMBOL_GPL(dma_buf_attach); /** - * dma_buf_detach - Remove the given attachment from dmabuf's attachments list; - * optionally calls detach() of dma_buf_ops for device-specific detach + * dma_buf_detach - Remove the given attachment from dmabuf's attachments list * @dmabuf: [in] buffer to detach from. * @attach: [in] attachment to be detached; is free'd after this call. * * Clean up a device attachment obtained by calling dma_buf_attach(). + * + * Optionally this calls &dma_buf_ops.detach for device-specific detach. */ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) { @@ -1061,11 +1065,12 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify); * shootdowns would increase the complexity quite a bit. * * Interface:: + * * int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*, * unsigned long); * * If the importing subsystem simply provides a special-purpose mmap call to - * set up a mapping in userspace, calling do_mmap with dma_buf->file will + * set up a mapping in userspace, calling do_mmap with &dma_buf.file will * equally achieve that for a dma-buf object. */ diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 7eca37c8b10c..43802a31b25d 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -85,10 +85,10 @@ struct dma_buf_ops { /** * @pin: * - * This is called by dma_buf_pin and lets the exporter know that the + * This is called by dma_buf_pin() and lets the exporter know that the * DMA-buf can't be moved any more. * - * This is called with the dmabuf->resv object locked and is mutual + * This is called with the &dmabuf.resv object locked and is mutual * exclusive with @cache_sgt_mapping. * * This callback is optional and should only be used in limited use @@ -103,7 +103,7 @@ struct dma_buf_ops { /** * @unpin: * - * This is called by dma_buf_unpin and lets the exporter know that the + * This is called by dma_buf_unpin() and lets the exporter know that the * DMA-buf can be moved again. * * This is called with the dmabuf->resv object locked and is mutual -- cgit v1.2.3 From c545781e1c55ab680dcc49c37212d5327b9d6812 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 11 Dec 2020 16:58:43 +0100 Subject: dma-buf: doc polish for pin/unpin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Motivated by a discussion with Christian and Thomas: Try to untangle a bit what's relevant for importers and what's relevant for exporters. Also add an assert that really only dynamic importers use the api function, anything else doesn't make sense. Acked-by: Christian König Signed-off-by: Daniel Vetter Cc: Thomas Zimmermann Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20201211155843.3348718-4-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-buf.c | 19 ++++++++++++++++--- include/linux/dma-buf.h | 8 +++++--- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a0a02ef888da..b8465243eca2 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -809,9 +809,15 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); /** * dma_buf_pin - Lock down the DMA-buf - * * @attach: [in] attachment which should be pinned * + * Only dynamic importers (who set up @attach with dma_buf_dynamic_attach()) may + * call this, and only for limited use cases like scanout and not for temporary + * pin operations. It is not permitted to allow userspace to pin arbitrary + * amounts of buffers through this interface. + * + * Buffers must be unpinned by calling dma_buf_unpin(). + * * Returns: * 0 on success, negative error code on failure. */ @@ -820,6 +826,8 @@ int dma_buf_pin(struct dma_buf_attachment *attach) struct dma_buf *dmabuf = attach->dmabuf; int ret = 0; + WARN_ON(!dma_buf_attachment_is_dynamic(attach)); + dma_resv_assert_held(dmabuf->resv); if (dmabuf->ops->pin) @@ -830,14 +838,19 @@ int dma_buf_pin(struct dma_buf_attachment *attach) EXPORT_SYMBOL_GPL(dma_buf_pin); /** - * dma_buf_unpin - Remove lock from DMA-buf - * + * dma_buf_unpin - Unpin a DMA-buf * @attach: [in] attachment which should be unpinned + * + * This unpins a buffer pinned by dma_buf_pin() and allows the exporter to move + * any mapping of @attach again and inform the importer through + * &dma_buf_attach_ops.move_notify. */ void dma_buf_unpin(struct dma_buf_attachment *attach) { struct dma_buf *dmabuf = attach->dmabuf; + WARN_ON(!dma_buf_attachment_is_dynamic(attach)); + dma_resv_assert_held(dmabuf->resv); if (dmabuf->ops->unpin) diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 43802a31b25d..628681bf6c99 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -86,13 +86,15 @@ struct dma_buf_ops { * @pin: * * This is called by dma_buf_pin() and lets the exporter know that the - * DMA-buf can't be moved any more. + * DMA-buf can't be moved any more. The exporter should pin the buffer + * into system memory to make sure it is generally accessible by other + * devices. * * This is called with the &dmabuf.resv object locked and is mutual * exclusive with @cache_sgt_mapping. * - * This callback is optional and should only be used in limited use - * cases like scanout and not for temporary pin operations. + * This is called automatically for non-dynamic importers from + * dma_buf_attach(). * * Returns: * -- cgit v1.2.3 From 8fbdbb66f8c10bb359ad20fff95628e5deac88f4 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Tue, 5 Jan 2021 14:44:01 +0100 Subject: PCI: Export pci_rebar_get_possible_sizes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export pci_rebar_get_possible_sizes() for use by modular drivers. Signed-off-by: Darren Salt Signed-off-by: Nirmoy Das Signed-off-by: Christian König Acked-by: Bjorn Helgaas Link: https://patchwork.kernel.org/project/dri-devel/patch/20210107175017.15893-2-nirmoy.das@amd.com --- drivers/pci/pci.c | 1 + drivers/pci/pci.h | 1 - include/linux/pci.h | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b9fecc25d213..8d1aec39ecc8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3605,6 +3605,7 @@ u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); return (cap & PCI_REBAR_CAP_SIZES) >> 4; } +EXPORT_SYMBOL(pci_rebar_get_possible_sizes); /** * pci_rebar_get_current_size - get the current size of a BAR diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 5c59365092fa..8f130f9531b3 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -630,7 +630,6 @@ int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment, struct resource *res); #endif -u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar); int pci_rebar_get_current_size(struct pci_dev *pdev, int bar); int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size); static inline u64 pci_rebar_size_to_bytes(int size) diff --git a/include/linux/pci.h b/include/linux/pci.h index b32126d26997..5f25a0ec48c1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1232,6 +1232,7 @@ void pci_update_resource(struct pci_dev *dev, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); void pci_release_resource(struct pci_dev *dev, int resno); +u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar); int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size); int pci_select_bars(struct pci_dev *dev, unsigned long flags); bool pci_device_is_present(struct pci_dev *pdev); -- cgit v1.2.3 From 192f1bf7559e895d51f81c3976c5892c8b1e0601 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Thu, 7 Jan 2021 14:30:34 +0100 Subject: PCI: Add pci_rebar_bytes_to_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users of pci_resize_resource() need a way to calculate BAR size from desired bytes. Add a helper function and export it so that modular drivers can use it. Signed-off-by: Darren Salt Signed-off-by: Christian König Signed-off-by: Nirmoy Das Acked-by: Bjorn Helgaas Link: https://patchwork.kernel.org/project/dri-devel/patch/20210107175017.15893-3-nirmoy.das@amd.com --- drivers/pci/pci.c | 2 +- include/linux/pci.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8d1aec39ecc8..99ef2774b9d0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1644,7 +1644,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev) pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; res = pdev->resource + bar_idx; - size = ilog2(resource_size(res)) - 20; + size = pci_rebar_bytes_to_size(resource_size(res)); ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT; pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); diff --git a/include/linux/pci.h b/include/linux/pci.h index 5f25a0ec48c1..53f4904ee83d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1232,6 +1232,14 @@ void pci_update_resource(struct pci_dev *dev, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); void pci_release_resource(struct pci_dev *dev, int resno); +static inline int pci_rebar_bytes_to_size(u64 bytes) +{ + bytes = roundup_pow_of_two(bytes); + + /* Return BAR size as defined in the resizable BAR specification */ + return max(ilog2(bytes), 20) - 20; +} + u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar); int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size); int pci_select_bars(struct pci_dev *dev, unsigned long flags); -- cgit v1.2.3 From 61712a5f8271ebdbb9d34d28279b77a452db9d5c Mon Sep 17 00:00:00 2001 From: Yue Zou Date: Mon, 18 Jan 2021 01:03:55 +0000 Subject: vgaarb: Remove unneeded semicolons Remove superfluous semicolons after function definitions. Signed-off-by: Yue Zou Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210118010356.214491-1-zouyue3@huawei.com --- include/linux/vgaarb.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 977caf96c8d2..fc6dfeba04a5 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -121,9 +121,9 @@ extern struct pci_dev *vga_default_device(void); extern void vga_set_default_device(struct pci_dev *pdev); extern int vga_remove_vgacon(struct pci_dev *pdev); #else -static inline struct pci_dev *vga_default_device(void) { return NULL; }; -static inline void vga_set_default_device(struct pci_dev *pdev) { }; -static inline int vga_remove_vgacon(struct pci_dev *pdev) { return 0; }; +static inline struct pci_dev *vga_default_device(void) { return NULL; } +static inline void vga_set_default_device(struct pci_dev *pdev) { } +static inline int vga_remove_vgacon(struct pci_dev *pdev) { return 0; } #endif /* -- cgit v1.2.3 From 84335675f2223cbd25d0de7d38ecc7d40b95bd4a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 15 Jan 2021 17:47:39 +0100 Subject: dma-buf: Add debug option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have too many people abusing the struct page they can get at but really shouldn't in importers. Aside from that the backing page might simply not exist (for dynamic p2p mappings) looking at it and using it e.g. for mmap can also wreak the page handling of the exporter completely. Importers really must go through the proper interface like dma_buf_mmap for everything. I'm semi-tempted to enforce this for dynamic importers since those really have no excuse at all to break the rules. Unfortuantely we can't store the right pointers somewhere safe to make sure we oops on something recognizable, so best is to just wrangle them a bit by flipping all the bits. At least on x86 kernel addresses have all their high bits sets and the struct page array is fairly low in the kernel mapping, so flipping all the bits gives us a very high pointer in userspace and hence excellent chances for an invalid dereference. v2: Add a note to the @map_dma_buf hook that exporters shouldn't do fancy caching tricks, which would blow up with this address scrambling trick here (Chris) Enable by default when CONFIG_DMA_API_DEBUG is enabled. v3: Only one copy of the mangle/unmangle code (Christian) v4: #ifdef, not #if (0day) v5: sg_table can also be an ERR_PTR (Chris, Christian) Reviewed-by: Chris Wilson Reviewed-by: Christian König Signed-off-by: Daniel Vetter Cc: Chris Wilson Cc: Sumit Semwal Cc: "Christian König" Cc: David Stevens Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20210115164739.3958206-1-daniel.vetter@ffwll.ch --- drivers/dma-buf/Kconfig | 8 ++++++++ drivers/dma-buf/dma-buf.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- include/linux/dma-buf.h | 6 ++++++ 3 files changed, 56 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 4f8224a6ac95..4e16c71c24b7 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -50,6 +50,14 @@ config DMABUF_MOVE_NOTIFY This is marked experimental because we don't yet have a consistent execution context and memory management between drivers. +config DMABUF_DEBUG + bool "DMA-BUF debug checks" + default y if DMA_API_DEBUG + help + This option enables additional checks for DMA-BUF importers and + exporters. Specifically it validates that importers do not peek at the + underlying struct page when they import a buffer. + config DMABUF_SELFTESTS tristate "Selftests for the dma-buf interfaces" default n diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index b8465243eca2..3948b88aa123 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -653,6 +653,34 @@ void dma_buf_put(struct dma_buf *dmabuf) } EXPORT_SYMBOL_GPL(dma_buf_put); +static void mangle_sg_table(struct sg_table *sg_table) +{ +#ifdef CONFIG_DMABUF_DEBUG + int i; + struct scatterlist *sg; + + /* To catch abuse of the underlying struct page by importers mix + * up the bits, but take care to preserve the low SG_ bits to + * not corrupt the sgt. The mixing is undone in __unmap_dma_buf + * before passing the sgt back to the exporter. */ + for_each_sgtable_sg(sg_table, sg, i) + sg->page_link ^= ~0xffUL; +#endif + +} +static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach, + enum dma_data_direction direction) +{ + struct sg_table *sg_table; + + sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); + + if (!IS_ERR_OR_NULL(sg_table)) + mangle_sg_table(sg_table); + + return sg_table; +} + /** * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list * @dmabuf: [in] buffer to attach device to. @@ -724,7 +752,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, goto err_unlock; } - sgt = dmabuf->ops->map_dma_buf(attach, DMA_BIDIRECTIONAL); + sgt = __map_dma_buf(attach, DMA_BIDIRECTIONAL); if (!sgt) sgt = ERR_PTR(-ENOMEM); if (IS_ERR(sgt)) { @@ -771,6 +799,16 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, } EXPORT_SYMBOL_GPL(dma_buf_attach); +static void __unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *sg_table, + enum dma_data_direction direction) +{ + /* uses XOR, hence this unmangles */ + mangle_sg_table(sg_table); + + attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); +} + /** * dma_buf_detach - Remove the given attachment from dmabuf's attachments list * @dmabuf: [in] buffer to detach from. @@ -789,7 +827,7 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) if (dma_buf_is_dynamic(attach->dmabuf)) dma_resv_lock(attach->dmabuf->resv, NULL); - dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir); + __unmap_dma_buf(attach, attach->sgt, attach->dir); if (dma_buf_is_dynamic(attach->dmabuf)) { dma_buf_unpin(attach); @@ -911,7 +949,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, } } - sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); + sg_table = __map_dma_buf(attach, direction); if (!sg_table) sg_table = ERR_PTR(-ENOMEM); @@ -974,7 +1012,7 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, if (dma_buf_is_dynamic(attach->dmabuf)) dma_resv_assert_held(attach->dmabuf->resv); - attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); + __unmap_dma_buf(attach, sg_table, direction); if (dma_buf_is_dynamic(attach->dmabuf) && !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 628681bf6c99..efdc56b9d95f 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -154,6 +154,12 @@ struct dma_buf_ops { * On failure, returns a negative error value wrapped into a pointer. * May also return -EINTR when a signal was received while being * blocked. + * + * Note that exporters should not try to cache the scatter list, or + * return the same one for multiple calls. Caching is done either by the + * DMA-BUF code (for non-dynamic importers) or the importer. Ownership + * of the scatter list is transferred to the caller, and returned by + * @unmap_dma_buf. */ struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction); -- cgit v1.2.3 From e1e4f7fea37572f0ccf3887430e52c491e9accb6 Mon Sep 17 00:00:00 2001 From: CK Hu Date: Tue, 21 Jul 2020 15:46:06 +0800 Subject: soc / drm: mediatek: Move mtk mutex driver to soc folder mtk mutex is used by DRM and MDP driver, and its function is SoC-specific, so move it to soc folder. Signed-off-by: CK Hu Signed-off-by: Chun-Kuang Hu Acked-by: Matthias Brugger --- drivers/gpu/drm/mediatek/Makefile | 3 +- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 2 +- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 - drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 - drivers/gpu/drm/mediatek/mtk_mutex.c | 463 ------------------------------- drivers/gpu/drm/mediatek/mtk_mutex.h | 26 -- drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mtk-mutex.c | 474 ++++++++++++++++++++++++++++++++ include/linux/soc/mediatek/mtk-mutex.h | 26 ++ 9 files changed, 503 insertions(+), 494 deletions(-) delete mode 100644 drivers/gpu/drm/mediatek/mtk_mutex.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_mutex.h create mode 100644 drivers/soc/mediatek/mtk-mutex.c create mode 100644 include/linux/soc/mediatek/mtk-mutex.h (limited to 'include/linux') diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 09979c4c340a..01d06332f767 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -9,8 +9,7 @@ mediatek-drm-y := mtk_disp_color.o \ mtk_drm_gem.o \ mtk_drm_plane.o \ mtk_dsi.o \ - mtk_dpi.o \ - mtk_mutex.o + mtk_dpi.o obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 1e3a9450680b..e9b6788d52cd 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,6 @@ #include "mtk_drm_ddp_comp.h" #include "mtk_drm_gem.h" #include "mtk_drm_plane.h" -#include "mtk_mutex.h" /* * struct mtk_drm_crtc - MediaTek specific crtc structure. diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index b99a06e6834e..5d39dd54255d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -588,7 +588,6 @@ static struct platform_driver mtk_drm_platform_driver = { }; static struct platform_driver * const mtk_drm_drivers[] = { - &mtk_mutex_driver, &mtk_disp_color_driver, &mtk_disp_ovl_driver, &mtk_disp_rdma_driver, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index ae366868d01a..e8238fa4aa2a 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -46,7 +46,6 @@ struct mtk_drm_private { struct drm_atomic_state *suspend_state; }; -extern struct platform_driver mtk_mutex_driver; extern struct platform_driver mtk_disp_color_driver; extern struct platform_driver mtk_disp_ovl_driver; extern struct platform_driver mtk_disp_rdma_driver; diff --git a/drivers/gpu/drm/mediatek/mtk_mutex.c b/drivers/gpu/drm/mediatek/mtk_mutex.c deleted file mode 100644 index 66344759e622..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_mutex.c +++ /dev/null @@ -1,463 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "mtk_mutex.h" - -#define MT2701_MUTEX0_MOD0 0x2c -#define MT2701_MUTEX0_SOF0 0x30 - -#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) -#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) -#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) -#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n)) -#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n)) -#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n)) - -#define INT_MUTEX BIT(1) - -#define MT8167_MUTEX_MOD_DISP_PWM 1 -#define MT8167_MUTEX_MOD_DISP_OVL0 6 -#define MT8167_MUTEX_MOD_DISP_OVL1 7 -#define MT8167_MUTEX_MOD_DISP_RDMA0 8 -#define MT8167_MUTEX_MOD_DISP_RDMA1 9 -#define MT8167_MUTEX_MOD_DISP_WDMA0 10 -#define MT8167_MUTEX_MOD_DISP_CCORR 11 -#define MT8167_MUTEX_MOD_DISP_COLOR 12 -#define MT8167_MUTEX_MOD_DISP_AAL 13 -#define MT8167_MUTEX_MOD_DISP_GAMMA 14 -#define MT8167_MUTEX_MOD_DISP_DITHER 15 -#define MT8167_MUTEX_MOD_DISP_UFOE 16 - -#define MT8173_MUTEX_MOD_DISP_OVL0 11 -#define MT8173_MUTEX_MOD_DISP_OVL1 12 -#define MT8173_MUTEX_MOD_DISP_RDMA0 13 -#define MT8173_MUTEX_MOD_DISP_RDMA1 14 -#define MT8173_MUTEX_MOD_DISP_RDMA2 15 -#define MT8173_MUTEX_MOD_DISP_WDMA0 16 -#define MT8173_MUTEX_MOD_DISP_WDMA1 17 -#define MT8173_MUTEX_MOD_DISP_COLOR0 18 -#define MT8173_MUTEX_MOD_DISP_COLOR1 19 -#define MT8173_MUTEX_MOD_DISP_AAL 20 -#define MT8173_MUTEX_MOD_DISP_GAMMA 21 -#define MT8173_MUTEX_MOD_DISP_UFOE 22 -#define MT8173_MUTEX_MOD_DISP_PWM0 23 -#define MT8173_MUTEX_MOD_DISP_PWM1 24 -#define MT8173_MUTEX_MOD_DISP_OD 25 - -#define MT2712_MUTEX_MOD_DISP_PWM2 10 -#define MT2712_MUTEX_MOD_DISP_OVL0 11 -#define MT2712_MUTEX_MOD_DISP_OVL1 12 -#define MT2712_MUTEX_MOD_DISP_RDMA0 13 -#define MT2712_MUTEX_MOD_DISP_RDMA1 14 -#define MT2712_MUTEX_MOD_DISP_RDMA2 15 -#define MT2712_MUTEX_MOD_DISP_WDMA0 16 -#define MT2712_MUTEX_MOD_DISP_WDMA1 17 -#define MT2712_MUTEX_MOD_DISP_COLOR0 18 -#define MT2712_MUTEX_MOD_DISP_COLOR1 19 -#define MT2712_MUTEX_MOD_DISP_AAL0 20 -#define MT2712_MUTEX_MOD_DISP_UFOE 22 -#define MT2712_MUTEX_MOD_DISP_PWM0 23 -#define MT2712_MUTEX_MOD_DISP_PWM1 24 -#define MT2712_MUTEX_MOD_DISP_OD0 25 -#define MT2712_MUTEX_MOD2_DISP_AAL1 33 -#define MT2712_MUTEX_MOD2_DISP_OD1 34 - -#define MT2701_MUTEX_MOD_DISP_OVL 3 -#define MT2701_MUTEX_MOD_DISP_WDMA 6 -#define MT2701_MUTEX_MOD_DISP_COLOR 7 -#define MT2701_MUTEX_MOD_DISP_BLS 9 -#define MT2701_MUTEX_MOD_DISP_RDMA0 10 -#define MT2701_MUTEX_MOD_DISP_RDMA1 12 - -#define MT2712_MUTEX_SOF_SINGLE_MODE 0 -#define MT2712_MUTEX_SOF_DSI0 1 -#define MT2712_MUTEX_SOF_DSI1 2 -#define MT2712_MUTEX_SOF_DPI0 3 -#define MT2712_MUTEX_SOF_DPI1 4 -#define MT2712_MUTEX_SOF_DSI2 5 -#define MT2712_MUTEX_SOF_DSI3 6 -#define MT8167_MUTEX_SOF_DPI0 2 -#define MT8167_MUTEX_SOF_DPI1 3 - -struct mtk_mutex { - int id; - bool claimed; -}; - -enum mtk_mutex_sof_id { - MUTEX_SOF_SINGLE_MODE, - MUTEX_SOF_DSI0, - MUTEX_SOF_DSI1, - MUTEX_SOF_DPI0, - MUTEX_SOF_DPI1, - MUTEX_SOF_DSI2, - MUTEX_SOF_DSI3, -}; - -struct mtk_mutex_data { - const unsigned int *mutex_mod; - const unsigned int *mutex_sof; - const unsigned int mutex_mod_reg; - const unsigned int mutex_sof_reg; - const bool no_clk; -}; - -struct mtk_mutex_ctx { - struct device *dev; - struct clk *clk; - void __iomem *regs; - struct mtk_mutex mutex[10]; - const struct mtk_mutex_data *data; -}; - -static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS, - [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR, - [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL, - [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0, - [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1, - [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, -}; - -static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0, - [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1, - [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0, - [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1, - [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0, - [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1, - [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0, - [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1, - [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0, - [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1, - [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2, - [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0, - [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1, - [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2, - [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE, - [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0, - [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1, -}; - -static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL, - [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR, - [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR, - [DDP_COMPONENT_DITHER] = MT8167_MUTEX_MOD_DISP_DITHER, - [DDP_COMPONENT_GAMMA] = MT8167_MUTEX_MOD_DISP_GAMMA, - [DDP_COMPONENT_OVL0] = MT8167_MUTEX_MOD_DISP_OVL0, - [DDP_COMPONENT_OVL1] = MT8167_MUTEX_MOD_DISP_OVL1, - [DDP_COMPONENT_PWM0] = MT8167_MUTEX_MOD_DISP_PWM, - [DDP_COMPONENT_RDMA0] = MT8167_MUTEX_MOD_DISP_RDMA0, - [DDP_COMPONENT_RDMA1] = MT8167_MUTEX_MOD_DISP_RDMA1, - [DDP_COMPONENT_UFOE] = MT8167_MUTEX_MOD_DISP_UFOE, - [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0, -}; - -static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, - [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, - [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, - [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, - [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD, - [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0, - [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1, - [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0, - [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1, - [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0, - [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1, - [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2, - [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE, - [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0, - [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, -}; - -static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = { - [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, - [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, - [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, - [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0, - [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1, - [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2, - [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3, -}; - -static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = { - [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, - [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, - [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0, - [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1, -}; - -static const struct mtk_mutex_data mt2701_mutex_driver_data = { - .mutex_mod = mt2701_mutex_mod, - .mutex_sof = mt2712_mutex_sof, - .mutex_mod_reg = MT2701_MUTEX0_MOD0, - .mutex_sof_reg = MT2701_MUTEX0_SOF0, -}; - -static const struct mtk_mutex_data mt2712_mutex_driver_data = { - .mutex_mod = mt2712_mutex_mod, - .mutex_sof = mt2712_mutex_sof, - .mutex_mod_reg = MT2701_MUTEX0_MOD0, - .mutex_sof_reg = MT2701_MUTEX0_SOF0, -}; - -static const struct mtk_mutex_data mt8167_mutex_driver_data = { - .mutex_mod = mt8167_mutex_mod, - .mutex_sof = mt8167_mutex_sof, - .mutex_mod_reg = MT2701_MUTEX0_MOD0, - .mutex_sof_reg = MT2701_MUTEX0_SOF0, - .no_clk = true, -}; - -static const struct mtk_mutex_data mt8173_mutex_driver_data = { - .mutex_mod = mt8173_mutex_mod, - .mutex_sof = mt2712_mutex_sof, - .mutex_mod_reg = MT2701_MUTEX0_MOD0, - .mutex_sof_reg = MT2701_MUTEX0_SOF0, -}; - -struct mtk_mutex *mtk_mutex_get(struct device *dev) -{ - struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev); - int i; - - for (i = 0; i < 10; i++) - if (!mtx->mutex[i].claimed) { - mtx->mutex[i].claimed = true; - return &mtx->mutex[i]; - } - - return ERR_PTR(-EBUSY); -} - -void mtk_mutex_put(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - - WARN_ON(&mtx->mutex[mutex->id] != mutex); - - mutex->claimed = false; -} - -int mtk_mutex_prepare(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - return clk_prepare_enable(mtx->clk); -} - -void mtk_mutex_unprepare(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - clk_disable_unprepare(mtx->clk); -} - -void mtk_mutex_add_comp(struct mtk_mutex *mutex, - enum mtk_ddp_comp_id id) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - unsigned int reg; - unsigned int sof_id; - unsigned int offset; - - WARN_ON(&mtx->mutex[mutex->id] != mutex); - - switch (id) { - case DDP_COMPONENT_DSI0: - sof_id = MUTEX_SOF_DSI0; - break; - case DDP_COMPONENT_DSI1: - sof_id = MUTEX_SOF_DSI0; - break; - case DDP_COMPONENT_DSI2: - sof_id = MUTEX_SOF_DSI2; - break; - case DDP_COMPONENT_DSI3: - sof_id = MUTEX_SOF_DSI3; - break; - case DDP_COMPONENT_DPI0: - sof_id = MUTEX_SOF_DPI0; - break; - case DDP_COMPONENT_DPI1: - sof_id = MUTEX_SOF_DPI1; - break; - default: - if (mtx->data->mutex_mod[id] < 32) { - offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, - mutex->id); - reg = readl_relaxed(mtx->regs + offset); - reg |= 1 << mtx->data->mutex_mod[id]; - writel_relaxed(reg, mtx->regs + offset); - } else { - offset = DISP_REG_MUTEX_MOD2(mutex->id); - reg = readl_relaxed(mtx->regs + offset); - reg |= 1 << (mtx->data->mutex_mod[id] - 32); - writel_relaxed(reg, mtx->regs + offset); - } - return; - } - - writel_relaxed(mtx->data->mutex_sof[sof_id], - mtx->regs + - DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id)); -} - -void mtk_mutex_remove_comp(struct mtk_mutex *mutex, - enum mtk_ddp_comp_id id) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - unsigned int reg; - unsigned int offset; - - WARN_ON(&mtx->mutex[mutex->id] != mutex); - - switch (id) { - case DDP_COMPONENT_DSI0: - case DDP_COMPONENT_DSI1: - case DDP_COMPONENT_DSI2: - case DDP_COMPONENT_DSI3: - case DDP_COMPONENT_DPI0: - case DDP_COMPONENT_DPI1: - writel_relaxed(MUTEX_SOF_SINGLE_MODE, - mtx->regs + - DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, - mutex->id)); - break; - default: - if (mtx->data->mutex_mod[id] < 32) { - offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, - mutex->id); - reg = readl_relaxed(mtx->regs + offset); - reg &= ~(1 << mtx->data->mutex_mod[id]); - writel_relaxed(reg, mtx->regs + offset); - } else { - offset = DISP_REG_MUTEX_MOD2(mutex->id); - reg = readl_relaxed(mtx->regs + offset); - reg &= ~(1 << (mtx->data->mutex_mod[id] - 32)); - writel_relaxed(reg, mtx->regs + offset); - } - break; - } -} - -void mtk_mutex_enable(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - - WARN_ON(&mtx->mutex[mutex->id] != mutex); - - writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); -} - -void mtk_mutex_disable(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - - WARN_ON(&mtx->mutex[mutex->id] != mutex); - - writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); -} - -void mtk_mutex_acquire(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - u32 tmp; - - writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); - writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id)); - if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id), - tmp, tmp & INT_MUTEX, 1, 10000)) - pr_err("could not acquire mutex %d\n", mutex->id); -} - -void mtk_mutex_release(struct mtk_mutex *mutex) -{ - struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, - mutex[mutex->id]); - - writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id)); -} - -static int mtk_mutex_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mtk_mutex_ctx *mtx; - struct resource *regs; - int i; - - mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL); - if (!mtx) - return -ENOMEM; - - for (i = 0; i < 10; i++) - mtx->mutex[i].id = i; - - mtx->data = of_device_get_match_data(dev); - - if (!mtx->data->no_clk) { - mtx->clk = devm_clk_get(dev, NULL); - if (IS_ERR(mtx->clk)) { - if (PTR_ERR(mtx->clk) != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock\n"); - return PTR_ERR(mtx->clk); - } - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mtx->regs = devm_ioremap_resource(dev, regs); - if (IS_ERR(mtx->regs)) { - dev_err(dev, "Failed to map mutex registers\n"); - return PTR_ERR(mtx->regs); - } - - platform_set_drvdata(pdev, mtx); - - return 0; -} - -static int mtk_mutex_remove(struct platform_device *pdev) -{ - return 0; -} - -static const struct of_device_id mutex_driver_dt_match[] = { - { .compatible = "mediatek,mt2701-disp-mutex", - .data = &mt2701_mutex_driver_data}, - { .compatible = "mediatek,mt2712-disp-mutex", - .data = &mt2712_mutex_driver_data}, - { .compatible = "mediatek,mt8167-disp-mutex", - .data = &mt8167_mutex_driver_data}, - { .compatible = "mediatek,mt8173-disp-mutex", - .data = &mt8173_mutex_driver_data}, - {}, -}; -MODULE_DEVICE_TABLE(of, mutex_driver_dt_match); - -struct platform_driver mtk_mutex_driver = { - .probe = mtk_mutex_probe, - .remove = mtk_mutex_remove, - .driver = { - .name = "mediatek-mutex", - .owner = THIS_MODULE, - .of_match_table = mutex_driver_dt_match, - }, -}; diff --git a/drivers/gpu/drm/mediatek/mtk_mutex.h b/drivers/gpu/drm/mediatek/mtk_mutex.h deleted file mode 100644 index 6fe4ffbde290..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_mutex.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef MTK_MUTEX_H -#define MTK_MUTEX_H - -struct regmap; -struct device; -struct mtk_mutex; - -struct mtk_mutex *mtk_mutex_get(struct device *dev); -int mtk_mutex_prepare(struct mtk_mutex *mutex); -void mtk_mutex_add_comp(struct mtk_mutex *mutex, - enum mtk_ddp_comp_id id); -void mtk_mutex_enable(struct mtk_mutex *mutex); -void mtk_mutex_disable(struct mtk_mutex *mutex); -void mtk_mutex_remove_comp(struct mtk_mutex *mutex, - enum mtk_ddp_comp_id id); -void mtk_mutex_unprepare(struct mtk_mutex *mutex); -void mtk_mutex_put(struct mtk_mutex *mutex); -void mtk_mutex_acquire(struct mtk_mutex *mutex); -void mtk_mutex_release(struct mtk_mutex *mutex); - -#endif /* MTK_MUTEX_H */ diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index b6908db534c2..90270f8114ed 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o +obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c new file mode 100644 index 000000000000..f531b119da7a --- /dev/null +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT2701_MUTEX0_MOD0 0x2c +#define MT2701_MUTEX0_SOF0 0x30 + +#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) +#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) +#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n)) +#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n)) + +#define INT_MUTEX BIT(1) + +#define MT8167_MUTEX_MOD_DISP_PWM 1 +#define MT8167_MUTEX_MOD_DISP_OVL0 6 +#define MT8167_MUTEX_MOD_DISP_OVL1 7 +#define MT8167_MUTEX_MOD_DISP_RDMA0 8 +#define MT8167_MUTEX_MOD_DISP_RDMA1 9 +#define MT8167_MUTEX_MOD_DISP_WDMA0 10 +#define MT8167_MUTEX_MOD_DISP_CCORR 11 +#define MT8167_MUTEX_MOD_DISP_COLOR 12 +#define MT8167_MUTEX_MOD_DISP_AAL 13 +#define MT8167_MUTEX_MOD_DISP_GAMMA 14 +#define MT8167_MUTEX_MOD_DISP_DITHER 15 +#define MT8167_MUTEX_MOD_DISP_UFOE 16 + +#define MT8173_MUTEX_MOD_DISP_OVL0 11 +#define MT8173_MUTEX_MOD_DISP_OVL1 12 +#define MT8173_MUTEX_MOD_DISP_RDMA0 13 +#define MT8173_MUTEX_MOD_DISP_RDMA1 14 +#define MT8173_MUTEX_MOD_DISP_RDMA2 15 +#define MT8173_MUTEX_MOD_DISP_WDMA0 16 +#define MT8173_MUTEX_MOD_DISP_WDMA1 17 +#define MT8173_MUTEX_MOD_DISP_COLOR0 18 +#define MT8173_MUTEX_MOD_DISP_COLOR1 19 +#define MT8173_MUTEX_MOD_DISP_AAL 20 +#define MT8173_MUTEX_MOD_DISP_GAMMA 21 +#define MT8173_MUTEX_MOD_DISP_UFOE 22 +#define MT8173_MUTEX_MOD_DISP_PWM0 23 +#define MT8173_MUTEX_MOD_DISP_PWM1 24 +#define MT8173_MUTEX_MOD_DISP_OD 25 + +#define MT2712_MUTEX_MOD_DISP_PWM2 10 +#define MT2712_MUTEX_MOD_DISP_OVL0 11 +#define MT2712_MUTEX_MOD_DISP_OVL1 12 +#define MT2712_MUTEX_MOD_DISP_RDMA0 13 +#define MT2712_MUTEX_MOD_DISP_RDMA1 14 +#define MT2712_MUTEX_MOD_DISP_RDMA2 15 +#define MT2712_MUTEX_MOD_DISP_WDMA0 16 +#define MT2712_MUTEX_MOD_DISP_WDMA1 17 +#define MT2712_MUTEX_MOD_DISP_COLOR0 18 +#define MT2712_MUTEX_MOD_DISP_COLOR1 19 +#define MT2712_MUTEX_MOD_DISP_AAL0 20 +#define MT2712_MUTEX_MOD_DISP_UFOE 22 +#define MT2712_MUTEX_MOD_DISP_PWM0 23 +#define MT2712_MUTEX_MOD_DISP_PWM1 24 +#define MT2712_MUTEX_MOD_DISP_OD0 25 +#define MT2712_MUTEX_MOD2_DISP_AAL1 33 +#define MT2712_MUTEX_MOD2_DISP_OD1 34 + +#define MT2701_MUTEX_MOD_DISP_OVL 3 +#define MT2701_MUTEX_MOD_DISP_WDMA 6 +#define MT2701_MUTEX_MOD_DISP_COLOR 7 +#define MT2701_MUTEX_MOD_DISP_BLS 9 +#define MT2701_MUTEX_MOD_DISP_RDMA0 10 +#define MT2701_MUTEX_MOD_DISP_RDMA1 12 + +#define MT2712_MUTEX_SOF_SINGLE_MODE 0 +#define MT2712_MUTEX_SOF_DSI0 1 +#define MT2712_MUTEX_SOF_DSI1 2 +#define MT2712_MUTEX_SOF_DPI0 3 +#define MT2712_MUTEX_SOF_DPI1 4 +#define MT2712_MUTEX_SOF_DSI2 5 +#define MT2712_MUTEX_SOF_DSI3 6 +#define MT8167_MUTEX_SOF_DPI0 2 +#define MT8167_MUTEX_SOF_DPI1 3 + +struct mtk_mutex { + int id; + bool claimed; +}; + +enum mtk_mutex_sof_id { + MUTEX_SOF_SINGLE_MODE, + MUTEX_SOF_DSI0, + MUTEX_SOF_DSI1, + MUTEX_SOF_DPI0, + MUTEX_SOF_DPI1, + MUTEX_SOF_DSI2, + MUTEX_SOF_DSI3, +}; + +struct mtk_mutex_data { + const unsigned int *mutex_mod; + const unsigned int *mutex_sof; + const unsigned int mutex_mod_reg; + const unsigned int mutex_sof_reg; + const bool no_clk; +}; + +struct mtk_mutex_ctx { + struct device *dev; + struct clk *clk; + void __iomem *regs; + struct mtk_mutex mutex[10]; + const struct mtk_mutex_data *data; +}; + +static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS, + [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR, + [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL, + [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, +}; + +static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0, + [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1, + [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1, + [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0, + [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1, + [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0, + [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1, + [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2, + [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2, + [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0, + [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1, +}; + +static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL, + [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR, + [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR, + [DDP_COMPONENT_DITHER] = MT8167_MUTEX_MOD_DISP_DITHER, + [DDP_COMPONENT_GAMMA] = MT8167_MUTEX_MOD_DISP_GAMMA, + [DDP_COMPONENT_OVL0] = MT8167_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT8167_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT8167_MUTEX_MOD_DISP_PWM, + [DDP_COMPONENT_RDMA0] = MT8167_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT8167_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_UFOE] = MT8167_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0, +}; + +static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, + [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, + [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, + [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD, + [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0, + [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1, + [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2, + [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0, + [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, +}; + +static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = { + [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, + [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, + [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, + [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0, + [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1, + [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2, + [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3, +}; + +static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = { + [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, + [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, + [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0, + [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1, +}; + +static const struct mtk_mutex_data mt2701_mutex_driver_data = { + .mutex_mod = mt2701_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +static const struct mtk_mutex_data mt2712_mutex_driver_data = { + .mutex_mod = mt2712_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +static const struct mtk_mutex_data mt8167_mutex_driver_data = { + .mutex_mod = mt8167_mutex_mod, + .mutex_sof = mt8167_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, + .no_clk = true, +}; + +static const struct mtk_mutex_data mt8173_mutex_driver_data = { + .mutex_mod = mt8173_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +struct mtk_mutex *mtk_mutex_get(struct device *dev) +{ + struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 10; i++) + if (!mtx->mutex[i].claimed) { + mtx->mutex[i].claimed = true; + return &mtx->mutex[i]; + } + + return ERR_PTR(-EBUSY); +} +EXPORT_SYMBOL_GPL(mtk_mutex_get); + +void mtk_mutex_put(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + mutex->claimed = false; +} +EXPORT_SYMBOL_GPL(mtk_mutex_put); + +int mtk_mutex_prepare(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + return clk_prepare_enable(mtx->clk); +} +EXPORT_SYMBOL_GPL(mtk_mutex_prepare); + +void mtk_mutex_unprepare(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + clk_disable_unprepare(mtx->clk); +} +EXPORT_SYMBOL_GPL(mtk_mutex_unprepare); + +void mtk_mutex_add_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + unsigned int reg; + unsigned int sof_id; + unsigned int offset; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + switch (id) { + case DDP_COMPONENT_DSI0: + sof_id = MUTEX_SOF_DSI0; + break; + case DDP_COMPONENT_DSI1: + sof_id = MUTEX_SOF_DSI0; + break; + case DDP_COMPONENT_DSI2: + sof_id = MUTEX_SOF_DSI2; + break; + case DDP_COMPONENT_DSI3: + sof_id = MUTEX_SOF_DSI3; + break; + case DDP_COMPONENT_DPI0: + sof_id = MUTEX_SOF_DPI0; + break; + case DDP_COMPONENT_DPI1: + sof_id = MUTEX_SOF_DPI1; + break; + default: + if (mtx->data->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg |= 1 << mtx->data->mutex_mod[id]; + writel_relaxed(reg, mtx->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg |= 1 << (mtx->data->mutex_mod[id] - 32); + writel_relaxed(reg, mtx->regs + offset); + } + return; + } + + writel_relaxed(mtx->data->mutex_sof[sof_id], + mtx->regs + + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_add_comp); + +void mtk_mutex_remove_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + unsigned int reg; + unsigned int offset; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + switch (id) { + case DDP_COMPONENT_DSI0: + case DDP_COMPONENT_DSI1: + case DDP_COMPONENT_DSI2: + case DDP_COMPONENT_DSI3: + case DDP_COMPONENT_DPI0: + case DDP_COMPONENT_DPI1: + writel_relaxed(MUTEX_SOF_SINGLE_MODE, + mtx->regs + + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, + mutex->id)); + break; + default: + if (mtx->data->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg &= ~(1 << mtx->data->mutex_mod[id]); + writel_relaxed(reg, mtx->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg &= ~(1 << (mtx->data->mutex_mod[id] - 32)); + writel_relaxed(reg, mtx->regs + offset); + } + break; + } +} +EXPORT_SYMBOL_GPL(mtk_mutex_remove_comp); + +void mtk_mutex_enable(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_enable); + +void mtk_mutex_disable(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_disable); + +void mtk_mutex_acquire(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + u32 tmp; + + writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); + writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id)); + if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id), + tmp, tmp & INT_MUTEX, 1, 10000)) + pr_err("could not acquire mutex %d\n", mutex->id); +} +EXPORT_SYMBOL_GPL(mtk_mutex_acquire); + +void mtk_mutex_release(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_release); + +static int mtk_mutex_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_mutex_ctx *mtx; + struct resource *regs; + int i; + + mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL); + if (!mtx) + return -ENOMEM; + + for (i = 0; i < 10; i++) + mtx->mutex[i].id = i; + + mtx->data = of_device_get_match_data(dev); + + if (!mtx->data->no_clk) { + mtx->clk = devm_clk_get(dev, NULL); + if (IS_ERR(mtx->clk)) { + if (PTR_ERR(mtx->clk) != -EPROBE_DEFER) + dev_err(dev, "Failed to get clock\n"); + return PTR_ERR(mtx->clk); + } + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mtx->regs = devm_ioremap_resource(dev, regs); + if (IS_ERR(mtx->regs)) { + dev_err(dev, "Failed to map mutex registers\n"); + return PTR_ERR(mtx->regs); + } + + platform_set_drvdata(pdev, mtx); + + return 0; +} + +static int mtk_mutex_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id mutex_driver_dt_match[] = { + { .compatible = "mediatek,mt2701-disp-mutex", + .data = &mt2701_mutex_driver_data}, + { .compatible = "mediatek,mt2712-disp-mutex", + .data = &mt2712_mutex_driver_data}, + { .compatible = "mediatek,mt8167-disp-mutex", + .data = &mt8167_mutex_driver_data}, + { .compatible = "mediatek,mt8173-disp-mutex", + .data = &mt8173_mutex_driver_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, mutex_driver_dt_match); + +struct platform_driver mtk_mutex_driver = { + .probe = mtk_mutex_probe, + .remove = mtk_mutex_remove, + .driver = { + .name = "mediatek-mutex", + .owner = THIS_MODULE, + .of_match_table = mutex_driver_dt_match, + }, +}; + +builtin_platform_driver(mtk_mutex_driver); diff --git a/include/linux/soc/mediatek/mtk-mutex.h b/include/linux/soc/mediatek/mtk-mutex.h new file mode 100644 index 000000000000..6fe4ffbde290 --- /dev/null +++ b/include/linux/soc/mediatek/mtk-mutex.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#ifndef MTK_MUTEX_H +#define MTK_MUTEX_H + +struct regmap; +struct device; +struct mtk_mutex; + +struct mtk_mutex *mtk_mutex_get(struct device *dev); +int mtk_mutex_prepare(struct mtk_mutex *mutex); +void mtk_mutex_add_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id); +void mtk_mutex_enable(struct mtk_mutex *mutex); +void mtk_mutex_disable(struct mtk_mutex *mutex); +void mtk_mutex_remove_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id); +void mtk_mutex_unprepare(struct mtk_mutex *mutex); +void mtk_mutex_put(struct mtk_mutex *mutex); +void mtk_mutex_acquire(struct mtk_mutex *mutex); +void mtk_mutex_release(struct mtk_mutex *mutex); + +#endif /* MTK_MUTEX_H */ -- cgit v1.2.3