From patchwork Thu Aug 6 14:25:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Deucher X-Patchwork-Id: 6960141 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id CD8AEC05AC for ; Thu, 6 Aug 2015 14:27:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BAC1B202EB for ; Thu, 6 Aug 2015 14:26:56 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 8981A20680 for ; Thu, 6 Aug 2015 14:26:54 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 8E6AC2604E5; Thu, 6 Aug 2015 16:26:53 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id C3FAC2605D8; Thu, 6 Aug 2015 16:25:32 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id F0BE02605D6; Thu, 6 Aug 2015 16:25:31 +0200 (CEST) Received: from mail-yk0-f173.google.com (mail-yk0-f173.google.com [209.85.160.173]) by alsa0.perex.cz (Postfix) with ESMTP id 58E7D2604E2 for ; Thu, 6 Aug 2015 16:25:21 +0200 (CEST) Received: by ykcq64 with SMTP id q64so58592061ykc.2 for ; Thu, 06 Aug 2015 07:25:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=EJAfu/5CWKSQetCVW+nbYVIgBIMGvZBqJWr+IlJiFnQ=; b=GNdcSDBqhENQ60dsDC++Xwjeb9YNdGQbHlfH/lVml5+XVdU9TWN1UKY8P8LG6XgwSP Xd4kdM/IM8P6YmuT4QpDrIim7ZOM1aPvKaB/9QZmYc85hRqV72n65mS3fZ7KO+HDvk8I /BqZ9jcEQQ6LxPUG/kK9BB8Jp/PS3VAFogdxfuVOsEw8tXV3NUByzwPYleKsopKWAkdd ashiYl3GT2IIerduBctHu130ky47m28otrnyax4moZxMSf6xs9e6gO53OnQoDQhSwvcC s2DpJD0q8fG1Jjji2UlcZmxjXeHKw72JMdN48Tu8x6DvW+tXmDaNBIZUopv/a2kaqf8y GPqA== X-Received: by 10.129.94.197 with SMTP id s188mr1975510ywb.111.1438871120351; Thu, 06 Aug 2015 07:25:20 -0700 (PDT) Received: from localhost.localdomain (static-74-96-105-49.washdc.fios.verizon.net. [74.96.105.49]) by smtp.gmail.com with ESMTPSA id k128sm6182789ywe.11.2015.08.06.07.25.19 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 06 Aug 2015 07:25:19 -0700 (PDT) From: Alex Deucher X-Google-Original-From: Alex Deucher To: broonie@kernel.org, airlied@gmail.com, dri-devel@lists.freedesktop.org, alsa-devel@alsa-project.org Date: Thu, 6 Aug 2015 10:25:02 -0400 Message-Id: <1438871112-25946-2-git-send-email-alexander.deucher@amd.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1438871112-25946-1-git-send-email-alexander.deucher@amd.com> References: <1438871112-25946-1-git-send-email-alexander.deucher@amd.com> Cc: Chunming Zhou , maruthi.bayyavarapu@amd.com, tiwai@suse.de, lgirdwood@gmail.com, Alex Deucher Subject: [alsa-devel] [PATCH 01/12] drm/amdgpu: add amd_gnb_bus support X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Chunming Zhou This is used by the incoming ACP driver. The DMA engine for the i2s audio codec is part of the GPU. This exposes an amd gnb bus for the i2s codec to hang off of. Reviewed-by: Jammy Zhou Signed-off-by: Chunming Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/Kconfig | 3 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/amd/bus/Kconfig | 7 + drivers/gpu/drm/amd/bus/Makefile | 4 + drivers/gpu/drm/amd/bus/amd_gnb_bus.c | 266 ++++++++++++++++++++++++++ drivers/gpu/drm/amd/include/bus/amd_gnb_bus.h | 78 ++++++++ 6 files changed, 359 insertions(+) create mode 100644 drivers/gpu/drm/amd/bus/Kconfig create mode 100644 drivers/gpu/drm/amd/bus/Makefile create mode 100644 drivers/gpu/drm/amd/bus/amd_gnb_bus.c create mode 100644 drivers/gpu/drm/amd/include/bus/amd_gnb_bus.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c46ca31..8c3cc9e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -120,6 +120,8 @@ config DRM_RADEON source "drivers/gpu/drm/radeon/Kconfig" +source "drivers/gpu/drm/amd/bus/Kconfig" + config DRM_AMDGPU tristate "AMD GPU" depends on DRM && PCI @@ -134,6 +136,7 @@ config DRM_AMDGPU select HWMON select BACKLIGHT_CLASS_DEVICE select INTERVAL_TREE + select DRM_AMD_GNB_BUS help Choose this option if you have a recent AMD Radeon graphics card. diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5713d05..5380477 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DRM_TDFX) += tdfx/ obj-$(CONFIG_DRM_R128) += r128/ obj-$(CONFIG_HSA_AMD) += amd/amdkfd/ obj-$(CONFIG_DRM_RADEON)+= radeon/ +obj-$(CONFIG_DRM_AMD_GNB_BUS) += amd/bus/ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ obj-$(CONFIG_DRM_MGA) += mga/ obj-$(CONFIG_DRM_I810) += i810/ diff --git a/drivers/gpu/drm/amd/bus/Kconfig b/drivers/gpu/drm/amd/bus/Kconfig new file mode 100644 index 0000000..f101dd8 --- /dev/null +++ b/drivers/gpu/drm/amd/bus/Kconfig @@ -0,0 +1,7 @@ +menu "AMD GNB BUS" + visible if 0 + +config DRM_AMD_GNB_BUS + tristate "AMD GNB bus - used for GNB IPs such as ACP and ISP" + +endmenu diff --git a/drivers/gpu/drm/amd/bus/Makefile b/drivers/gpu/drm/amd/bus/Makefile new file mode 100644 index 0000000..c41ffc9 --- /dev/null +++ b/drivers/gpu/drm/amd/bus/Makefile @@ -0,0 +1,4 @@ +# +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/bus/ + +obj-$(CONFIG_DRM_AMD_GNB_BUS) := amd_gnb_bus.o diff --git a/drivers/gpu/drm/amd/bus/amd_gnb_bus.c b/drivers/gpu/drm/amd/bus/amd_gnb_bus.c new file mode 100644 index 0000000..071b16c --- /dev/null +++ b/drivers/gpu/drm/amd/bus/amd_gnb_bus.c @@ -0,0 +1,266 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + */ +#include +#include +#include +#include "amd_gnb_bus.h" + +#define to_amd_gnb_bus_device(x) container_of((x), struct amd_gnb_bus_dev, dev) +#define to_amd_gnb_bus_driver(drv) (container_of((drv), \ + struct amd_gnb_bus_driver, \ + driver)) + +static int amd_gnb_bus_match(struct device *dev, struct device_driver *drv) +{ + struct amd_gnb_bus_dev *amd_gnb_bus_dev = to_amd_gnb_bus_device(dev); + struct amd_gnb_bus_driver *amd_gnb_bus_driver = + to_amd_gnb_bus_driver(drv); + + return amd_gnb_bus_dev->ip == amd_gnb_bus_driver->ip ? 1 : 0; +} + +#ifdef CONFIG_PM_SLEEP +static int amd_gnb_bus_legacy_suspend(struct device *dev, pm_message_t mesg) +{ + struct amd_gnb_bus_dev *amd_gnb_bus_dev = to_amd_gnb_bus_device(dev); + struct amd_gnb_bus_driver *driver; + + if (!amd_gnb_bus_dev || !dev->driver) + return 0; + driver = to_amd_gnb_bus_driver(dev->driver); + if (!driver->suspend) + return 0; + return driver->suspend(amd_gnb_bus_dev, mesg); +} + +static int amd_gnb_bus_legacy_resume(struct device *dev) +{ + struct amd_gnb_bus_dev *amd_gnb_bus_dev = to_amd_gnb_bus_device(dev); + struct amd_gnb_bus_driver *driver; + + if (!amd_gnb_bus_dev || !dev->driver) + return 0; + driver = to_amd_gnb_bus_driver(dev->driver); + if (!driver->resume) + return 0; + return driver->resume(amd_gnb_bus_dev); +} + +static int amd_gnb_bus_device_pm_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_suspend(dev); + else + return amd_gnb_bus_legacy_suspend(dev, PMSG_SUSPEND); +} + +static int amd_gnb_bus_device_pm_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_resume(dev); + else + return amd_gnb_bus_legacy_resume(dev); +} + +static int amd_gnb_bus_device_pm_freeze(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_freeze(dev); + else + return amd_gnb_bus_legacy_suspend(dev, PMSG_FREEZE); +} + +static int amd_gnb_bus_device_pm_thaw(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_thaw(dev); + else + return amd_gnb_bus_legacy_resume(dev); +} + +static int amd_gnb_bus_device_pm_poweroff(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_poweroff(dev); + else + return amd_gnb_bus_legacy_suspend(dev, PMSG_HIBERNATE); +} + +static int amd_gnb_bus_device_pm_restore(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_restore(dev); + else + return amd_gnb_bus_legacy_resume(dev); +} +#else /* !CONFIG_PM_SLEEP */ +#define amd_gnb_bus_device_pm_suspend NULL +#define amd_gnb_bus_device_pm_resume NULL +#define amd_gnb_bus_device_pm_freeze NULL +#define amd_gnb_bus_device_pm_thaw NULL +#define amd_gnb_bus_device_pm_poweroff NULL +#define amd_gnb_bus_device_pm_restore NULL +#endif /* !CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops amd_gnb_bus_device_pm_ops = { + .suspend = amd_gnb_bus_device_pm_suspend, + .resume = amd_gnb_bus_device_pm_resume, + .freeze = amd_gnb_bus_device_pm_freeze, + .thaw = amd_gnb_bus_device_pm_thaw, + .poweroff = amd_gnb_bus_device_pm_poweroff, + .restore = amd_gnb_bus_device_pm_restore, + SET_RUNTIME_PM_OPS( + pm_generic_runtime_suspend, + pm_generic_runtime_resume, + pm_runtime_idle + ) +}; + +/* The bus should only be registered by the first amd_gnb, but further + * socs can add devices to the bus. */ +struct bus_type amd_gnb_bus_type = { + .name = "amd_gnb", + .match = amd_gnb_bus_match, + .pm = &amd_gnb_bus_device_pm_ops, +}; +EXPORT_SYMBOL(amd_gnb_bus_type); + +static int amd_gnb_bus_drv_probe(struct device *_dev) +{ + struct amd_gnb_bus_driver *drv = to_amd_gnb_bus_driver(_dev->driver); + struct amd_gnb_bus_dev *dev = to_amd_gnb_bus_device(_dev); + + return drv->probe(dev); +} + +static int amd_gnb_bus_drv_remove(struct device *_dev) +{ + struct amd_gnb_bus_driver *drv = to_amd_gnb_bus_driver(_dev->driver); + struct amd_gnb_bus_dev *dev = to_amd_gnb_bus_device(_dev); + + return drv->remove(dev); +} + +static void amd_gnb_bus_drv_shutdown(struct device *_dev) +{ + struct amd_gnb_bus_driver *drv = to_amd_gnb_bus_driver(_dev->driver); + struct amd_gnb_bus_dev *dev = to_amd_gnb_bus_device(_dev); + + drv->shutdown(dev); +} + +int amd_gnb_bus_register_driver(struct amd_gnb_bus_driver *drv, + struct module *owner, + const char *mod_name) +{ + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &amd_gnb_bus_type; + drv->driver.owner = owner; + drv->driver.mod_name = mod_name; + + if (drv->probe) + drv->driver.probe = amd_gnb_bus_drv_probe; + if (drv->remove) + drv->driver.remove = amd_gnb_bus_drv_remove; + if (drv->shutdown) + drv->driver.shutdown = amd_gnb_bus_drv_shutdown; + + /* register with core */ + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(amd_gnb_bus_register_driver); + +void amd_gnb_bus_unregister_driver(struct amd_gnb_bus_driver *drv) +{ + /* register with core */ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(amd_gnb_bus_unregister_driver); + +int amd_gnb_bus_register_device(struct amd_gnb_bus_dev *dev) +{ + dev->dev.bus = &amd_gnb_bus_type; + return device_add(&dev->dev); +} +EXPORT_SYMBOL(amd_gnb_bus_register_device); + +void amd_gnb_bus_unregister_device(struct amd_gnb_bus_dev *dev) +{ + if (dev) + device_del(&dev->dev); +} +EXPORT_SYMBOL(amd_gnb_bus_unregister_device); + +int amd_gnb_bus_device_init(struct amd_gnb_bus_dev *bus_dev, + enum amd_gnb_bus_ip ip, + char *dev_name, + void *handle, + struct device *parent) +{ + device_initialize(&bus_dev->dev); + bus_dev->dev.init_name = dev_name; + bus_dev->ip = ip; + bus_dev->private_data = handle; + bus_dev->dev.parent = parent; + return amd_gnb_bus_register_device(bus_dev); +} +EXPORT_SYMBOL(amd_gnb_bus_device_init); + +static int __init amd_gnb_bus_init(void) +{ + int ret = 0; + /* does this need to be thread safe? */ + ret = bus_register(&amd_gnb_bus_type); + if (ret) + pr_err("%s: bus register failed\n", __func__); + else + pr_info("%s: initialization is successful\n", __func__); + + return ret; +} + +static void __exit amd_gnb_bus_exit(void) +{ + bus_unregister(&amd_gnb_bus_type); +} + +module_init(amd_gnb_bus_init); +module_exit(amd_gnb_bus_exit); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("AMD GPU bus"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/amd/include/bus/amd_gnb_bus.h b/drivers/gpu/drm/amd/include/bus/amd_gnb_bus.h new file mode 100644 index 0000000..3e90077 --- /dev/null +++ b/drivers/gpu/drm/amd/include/bus/amd_gnb_bus.h @@ -0,0 +1,78 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + */ + +#ifndef __AMD_GNB_BUS_H__ +#define __AMD_GNB_BUS_H__ + +#include + +enum amd_gnb_bus_ip { + AMD_GNB_IP_ACP_DMA, + AMD_GNB_IP_ACP_I2S, + AMD_GNB_IP_ACP_PCM, + AMD_GNB_IP_ISP, + AMD_GNB_IP_NUM +}; + +struct amd_gnb_bus_dev { + struct device dev; /* generic device interface */ + enum amd_gnb_bus_ip ip; + /* private data can be acp_handle/isp_handle etc.*/ + void *private_data; +}; + +struct amd_gnb_bus_driver { + const char *name; + enum amd_gnb_bus_ip ip; + int (*probe)(struct amd_gnb_bus_dev *dev); /* New device inserted */ + int (*remove)(struct amd_gnb_bus_dev *dev); /* Device removed */ + int (*suspend)(struct amd_gnb_bus_dev *dev, pm_message_t state); + int (*resume)(struct amd_gnb_bus_dev *dev); + void (*shutdown)(struct amd_gnb_bus_dev *dev); + struct device_driver driver; /* generic device driver interface */ +}; + +#define amd_gnb_to_acp_device(x) container_of((x), \ + struct amd_gnb_bus_dev_acp, \ + base) +#define amd_gnb_to_isp_device(x) container_of((x), \ + struct amd_gnb_bus_dev_isp, \ + base) +#define amd_gnb_parent_to_pci_device(x) container_of((x)->dev.parent, \ + struct pci_dev, \ + dev) + +int amd_gnb_bus_register_device(struct amd_gnb_bus_dev *dev); +void amd_gnb_bus_unregister_device(struct amd_gnb_bus_dev *dev); +int amd_gnb_bus_device_init(struct amd_gnb_bus_dev *bus_dev, + enum amd_gnb_bus_ip ip, + char *dev_name, + void *handle, + struct device *parent); +int amd_gnb_bus_register_driver(struct amd_gnb_bus_driver *drv, + struct module *owner, + const char *mod_name); +void amd_gnb_bus_unregister_driver(struct amd_gnb_bus_driver *drv); + +#endif