Merge tag 'drm-msm-next-2018-03-20' of git://people.freedesktop.org/~robclark/linux into drm-next
Updates for 4.17. Sorry, running a bit late on this, didn't have a chance to send pull-req before heading to linaro. But it has all been in linux-next for a while. Main updates: + DSI updates from 10nm / SDM845 + fix for race condition with a3xx/a4xx fence completion irq + some refactoring/prep work for eventual a6xx support (ie. when we have a userspace) + a5xx debugfs enhancements + some mdp5 fixes/cleanups to prepare for eventually merging writeback support (ie. when we have a userspace) * tag 'drm-msm-next-2018-03-20' of git://people.freedesktop.org/~robclark/linux: (36 commits) drm/msm: fix building without debugfs drm/msm/mdp5: don't pre-reserve LM's if no dual-dsi drm/msm/mdp5: add missing LM flush bits drm/msm/mdp5: print a bit more of the atomic state drm/msm/mdp5: rework CTL START signal handling drm/msm: Trigger fence completion from GPU drm/msm/dsi: fix direct caller of msm_gem_free_object() drm/msm: strip out msm_fence_cb drm/msm: rename mdp->disp drm/msm/dsi: Fix potential NULL pointer dereference in msm_dsi_modeset_init drm/msm/adreno/a5xx_debugfs: fix potential NULL pointer dereference drm/msm/dsi: Get byte_intf_clk only for versions that need it drm/msm/adreno: Use generic function to load firmware to a buffer object drm/msm/adreno: Define a list of firmware files to load per target drm/msm/adreno: Rename gpmufw to powerfw drm/msm: Pass the correct aperture end to drm_mm_init drm/msm/gpu: Set number of clocks to 0 if the list allocation fails drm/msm: Replace gem_object deprecated functions drm/msm/hdmi: fix semicolon.cocci warnings drm/msm/mdp5: Fix trailing semicolon ...
This commit is contained in:
		
						commit
						b65bd40311
					
				| @ -7,8 +7,6 @@ Required properties: | ||||
| - reg: Physical base address and length of the registers of controller | ||||
| - reg-names: The names of register regions. The following regions are required: | ||||
|   * "dsi_ctrl" | ||||
| - qcom,dsi-host-index: The ID of DSI controller hardware instance. This should | ||||
|   be 0 or 1, since we have 2 DSI controllers at most for now. | ||||
| - interrupts: The interrupt signal from the DSI block. | ||||
| - power-domains: Should be <&mmcc MDSS_GDSC>. | ||||
| - clocks: Phandles to device clocks. | ||||
| @ -22,6 +20,8 @@ Required properties: | ||||
|   * "core" | ||||
|   For DSIv2, we need an additional clock: | ||||
|    * "src" | ||||
|   For DSI6G v2.0 onwards, we need also need the clock: | ||||
|    * "byte_intf" | ||||
| - assigned-clocks: Parents of "byte" and "pixel" for the given platform. | ||||
| - assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided | ||||
|   by a DSI PHY block. See [1] for details on clock bindings. | ||||
| @ -88,21 +88,35 @@ Required properties: | ||||
|   * "qcom,dsi-phy-28nm-lp" | ||||
|   * "qcom,dsi-phy-20nm" | ||||
|   * "qcom,dsi-phy-28nm-8960" | ||||
| - reg: Physical base address and length of the registers of PLL, PHY and PHY | ||||
|   regulator | ||||
|   * "qcom,dsi-phy-14nm" | ||||
|   * "qcom,dsi-phy-10nm" | ||||
| - reg: Physical base address and length of the registers of PLL, PHY. Some | ||||
|   revisions require the PHY regulator base address, whereas others require the | ||||
|   PHY lane base address. See below for each PHY revision. | ||||
| - reg-names: The names of register regions. The following regions are required: | ||||
|   For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY: | ||||
|   * "dsi_pll" | ||||
|   * "dsi_phy" | ||||
|   * "dsi_phy_regulator" | ||||
|   For DSI 14nm and 10nm PHYs: | ||||
|   * "dsi_pll" | ||||
|   * "dsi_phy" | ||||
|   * "dsi_phy_lane" | ||||
| - clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating | ||||
|   2 clocks: A byte clock (index 0), and a pixel clock (index 1). | ||||
| - qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should | ||||
|   be 0 or 1, since we have 2 DSI PHYs at most for now. | ||||
| - power-domains: Should be <&mmcc MDSS_GDSC>. | ||||
| - clocks: Phandles to device clocks. See [1] for details on clock bindings. | ||||
| - clock-names: the following clocks are required: | ||||
|   * "iface" | ||||
|   For 28nm HPM/LP, 28nm 8960 PHYs: | ||||
| - vddio-supply: phandle to vdd-io regulator device node | ||||
|   For 20nm PHY: | ||||
| - vddio-supply: phandle to vdd-io regulator device node | ||||
| - vcca-supply: phandle to vcca regulator device node | ||||
|   For 14nm PHY: | ||||
| - vcca-supply: phandle to vcca regulator device node | ||||
|   For 10nm PHY: | ||||
| - vdds-supply: phandle to vdds regulator device node | ||||
| 
 | ||||
| Optional properties: | ||||
| - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY | ||||
|  | ||||
| @ -28,6 +28,19 @@ config DRM_MSM_REGISTER_LOGGING | ||||
| 	  that can be parsed by envytools demsm tool.  If enabled, register | ||||
| 	  logging can be switched on via msm.reglog=y module param. | ||||
| 
 | ||||
| config DRM_MSM_GPU_SUDO | ||||
| 	bool "Enable SUDO flag on submits" | ||||
| 	depends on DRM_MSM && EXPERT | ||||
| 	default n | ||||
| 	help | ||||
| 	  Enable userspace that has CAP_SYS_RAWIO to submit GPU commands | ||||
| 	  that are run from RB instead of IB1.  This essentially gives | ||||
| 	  userspace kernel level access, but is useful for firmware | ||||
| 	  debugging. | ||||
| 
 | ||||
| 	  Only use this if you are a driver developer.  This should *not* | ||||
| 	  be enabled for production kernels.  If unsure, say N. | ||||
| 
 | ||||
| config DRM_MSM_HDMI_HDCP | ||||
| 	bool "Enable HDMI HDCP support in MSM DRM driver" | ||||
| 	depends on DRM_MSM && QCOM_SCM | ||||
| @ -81,3 +94,10 @@ config DRM_MSM_DSI_14NM_PHY | ||||
| 	default y | ||||
| 	help | ||||
| 	  Choose this option if DSI PHY on 8996 is used on the platform. | ||||
| 
 | ||||
| config DRM_MSM_DSI_10NM_PHY | ||||
| 	bool "Enable DSI 10nm PHY driver in MSM DRM (used by SDM845)" | ||||
| 	depends on DRM_MSM_DSI | ||||
| 	default y | ||||
| 	help | ||||
| 	  Choose this option if DSI PHY on SDM845 is used on the platform. | ||||
|  | ||||
| @ -25,26 +25,26 @@ msm-y := \ | ||||
| 	edp/edp_connector.o \
 | ||||
| 	edp/edp_ctrl.o \
 | ||||
| 	edp/edp_phy.o \
 | ||||
| 	mdp/mdp_format.o \
 | ||||
| 	mdp/mdp_kms.o \
 | ||||
| 	mdp/mdp4/mdp4_crtc.o \
 | ||||
| 	mdp/mdp4/mdp4_dtv_encoder.o \
 | ||||
| 	mdp/mdp4/mdp4_lcdc_encoder.o \
 | ||||
| 	mdp/mdp4/mdp4_lvds_connector.o \
 | ||||
| 	mdp/mdp4/mdp4_irq.o \
 | ||||
| 	mdp/mdp4/mdp4_kms.o \
 | ||||
| 	mdp/mdp4/mdp4_plane.o \
 | ||||
| 	mdp/mdp5/mdp5_cfg.o \
 | ||||
| 	mdp/mdp5/mdp5_ctl.o \
 | ||||
| 	mdp/mdp5/mdp5_crtc.o \
 | ||||
| 	mdp/mdp5/mdp5_encoder.o \
 | ||||
| 	mdp/mdp5/mdp5_irq.o \
 | ||||
| 	mdp/mdp5/mdp5_mdss.o \
 | ||||
| 	mdp/mdp5/mdp5_kms.o \
 | ||||
| 	mdp/mdp5/mdp5_pipe.o \
 | ||||
| 	mdp/mdp5/mdp5_mixer.o \
 | ||||
| 	mdp/mdp5/mdp5_plane.o \
 | ||||
| 	mdp/mdp5/mdp5_smp.o \
 | ||||
| 	disp/mdp_format.o \
 | ||||
| 	disp/mdp_kms.o \
 | ||||
| 	disp/mdp4/mdp4_crtc.o \
 | ||||
| 	disp/mdp4/mdp4_dtv_encoder.o \
 | ||||
| 	disp/mdp4/mdp4_lcdc_encoder.o \
 | ||||
| 	disp/mdp4/mdp4_lvds_connector.o \
 | ||||
| 	disp/mdp4/mdp4_irq.o \
 | ||||
| 	disp/mdp4/mdp4_kms.o \
 | ||||
| 	disp/mdp4/mdp4_plane.o \
 | ||||
| 	disp/mdp5/mdp5_cfg.o \
 | ||||
| 	disp/mdp5/mdp5_ctl.o \
 | ||||
| 	disp/mdp5/mdp5_crtc.o \
 | ||||
| 	disp/mdp5/mdp5_encoder.o \
 | ||||
| 	disp/mdp5/mdp5_irq.o \
 | ||||
| 	disp/mdp5/mdp5_mdss.o \
 | ||||
| 	disp/mdp5/mdp5_kms.o \
 | ||||
| 	disp/mdp5/mdp5_pipe.o \
 | ||||
| 	disp/mdp5/mdp5_mixer.o \
 | ||||
| 	disp/mdp5/mdp5_plane.o \
 | ||||
| 	disp/mdp5/mdp5_smp.o \
 | ||||
| 	msm_atomic.o \
 | ||||
| 	msm_debugfs.o \
 | ||||
| 	msm_drv.o \
 | ||||
| @ -62,31 +62,35 @@ msm-y := \ | ||||
| 	msm_ringbuffer.o \
 | ||||
| 	msm_submitqueue.o | ||||
| 
 | ||||
| msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o | ||||
| 
 | ||||
| msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o | ||||
| msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o | ||||
| msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o | ||||
| msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o | ||||
| msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o | ||||
| 
 | ||||
| msm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o | ||||
| 
 | ||||
| msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
 | ||||
| 			mdp/mdp4/mdp4_dsi_encoder.o \
 | ||||
| 			disp/mdp4/mdp4_dsi_encoder.o \
 | ||||
| 			dsi/dsi_cfg.o \
 | ||||
| 			dsi/dsi_host.o \
 | ||||
| 			dsi/dsi_manager.o \
 | ||||
| 			dsi/phy/dsi_phy.o \
 | ||||
| 			mdp/mdp5/mdp5_cmd_encoder.o | ||||
| 			disp/mdp5/mdp5_cmd_encoder.o | ||||
| 
 | ||||
| msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/phy/dsi_phy_14nm.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o | ||||
| 
 | ||||
| ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) | ||||
| msm-y += dsi/pll/dsi_pll.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/pll/dsi_pll_14nm.o | ||||
| msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/pll/dsi_pll_10nm.o | ||||
| endif | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_MSM)	+= msm.o | ||||
|  | ||||
| @ -35,6 +35,7 @@ | ||||
| 	 A3XX_INT0_CP_RB_INT |             \ | ||||
| 	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \ | ||||
| 	 A3XX_INT0_CP_AHB_ERROR_HALT |     \ | ||||
| 	 A3XX_INT0_CACHE_FLUSH_TS |        \ | ||||
| 	 A3XX_INT0_UCHE_OOB_ACCESS) | ||||
| 
 | ||||
| extern bool hang_debug; | ||||
| @ -256,8 +257,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Load PM4: */ | ||||
| 	ptr = (uint32_t *)(adreno_gpu->pm4->data); | ||||
| 	len = adreno_gpu->pm4->size / 4; | ||||
| 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); | ||||
| 	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; | ||||
| 	DBG("loading PM4 ucode version: %x", ptr[1]); | ||||
| 
 | ||||
| 	gpu_write(gpu, REG_AXXX_CP_DEBUG, | ||||
| @ -268,8 +269,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) | ||||
| 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); | ||||
| 
 | ||||
| 	/* Load PFP: */ | ||||
| 	ptr = (uint32_t *)(adreno_gpu->pfp->data); | ||||
| 	len = adreno_gpu->pfp->size / 4; | ||||
| 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); | ||||
| 	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; | ||||
| 	DBG("loading PFP ucode version: %x", ptr[5]); | ||||
| 
 | ||||
| 	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| 	 A4XX_INT0_CP_RB_INT |             \ | ||||
| 	 A4XX_INT0_CP_REG_PROTECT_FAULT |  \ | ||||
| 	 A4XX_INT0_CP_AHB_ERROR_HALT |     \ | ||||
| 	 A4XX_INT0_CACHE_FLUSH_TS |        \ | ||||
| 	 A4XX_INT0_UCHE_OOB_ACCESS) | ||||
| 
 | ||||
| extern bool hang_debug; | ||||
| @ -274,16 +275,16 @@ static int a4xx_hw_init(struct msm_gpu *gpu) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* Load PM4: */ | ||||
| 	ptr = (uint32_t *)(adreno_gpu->pm4->data); | ||||
| 	len = adreno_gpu->pm4->size / 4; | ||||
| 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); | ||||
| 	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; | ||||
| 	DBG("loading PM4 ucode version: %u", ptr[0]); | ||||
| 	gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0); | ||||
| 	for (i = 1; i < len; i++) | ||||
| 		gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]); | ||||
| 
 | ||||
| 	/* Load PFP: */ | ||||
| 	ptr = (uint32_t *)(adreno_gpu->pfp->data); | ||||
| 	len = adreno_gpu->pfp->size / 4; | ||||
| 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); | ||||
| 	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; | ||||
| 	DBG("loading PFP ucode version: %u", ptr[0]); | ||||
| 
 | ||||
| 	gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0); | ||||
|  | ||||
							
								
								
									
										187
									
								
								drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | ||||
| /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
 | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 and | ||||
|  * only version 2 as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <drm/drm_print.h> | ||||
| 
 | ||||
| #include "a5xx_gpu.h" | ||||
| 
 | ||||
| static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	drm_printf(p, "PFP state:\n"); | ||||
| 
 | ||||
| 	for (i = 0; i < 36; i++) { | ||||
| 		gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i); | ||||
| 		drm_printf(p, "  %02x: %08x\n", i, | ||||
| 			gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA)); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int me_print(struct msm_gpu *gpu, struct drm_printer *p) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	drm_printf(p, "ME state:\n"); | ||||
| 
 | ||||
| 	for (i = 0; i < 29; i++) { | ||||
| 		gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i); | ||||
| 		drm_printf(p, "  %02x: %08x\n", i, | ||||
| 			gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA)); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int meq_print(struct msm_gpu *gpu, struct drm_printer *p) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	drm_printf(p, "MEQ state:\n"); | ||||
| 	gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0); | ||||
| 
 | ||||
| 	for (i = 0; i < 64; i++) { | ||||
| 		drm_printf(p, "  %02x: %08x\n", i, | ||||
| 			gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA)); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int roq_print(struct msm_gpu *gpu, struct drm_printer *p) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	drm_printf(p, "ROQ state:\n"); | ||||
| 	gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0); | ||||
| 
 | ||||
| 	for (i = 0; i < 512 / 4; i++) { | ||||
| 		uint32_t val[4]; | ||||
| 		int j; | ||||
| 		for (j = 0; j < 4; j++) | ||||
| 			val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA); | ||||
| 		drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i, | ||||
| 			val[0], val[1], val[2], val[3]); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int show(struct seq_file *m, void *arg) | ||||
| { | ||||
| 	struct drm_info_node *node = (struct drm_info_node *) m->private; | ||||
| 	struct drm_device *dev = node->minor->dev; | ||||
| 	struct msm_drm_private *priv = dev->dev_private; | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 	int (*show)(struct msm_gpu *gpu, struct drm_printer *p) = | ||||
| 		node->info_ent->data; | ||||
| 
 | ||||
| 	return show(priv->gpu, &p); | ||||
| } | ||||
| 
 | ||||
| #define ENT(n) { .name = #n, .show = show, .data = n ##_print } | ||||
| static struct drm_info_list a5xx_debugfs_list[] = { | ||||
| 	ENT(pfp), | ||||
| 	ENT(me), | ||||
| 	ENT(meq), | ||||
| 	ENT(roq), | ||||
| }; | ||||
| 
 | ||||
| /* for debugfs files that can be written to, we can't use drm helper: */ | ||||
| static int | ||||
| reset_set(void *data, u64 val) | ||||
| { | ||||
| 	struct drm_device *dev = data; | ||||
| 	struct msm_drm_private *priv = dev->dev_private; | ||||
| 	struct msm_gpu *gpu = priv->gpu; | ||||
| 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||||
| 	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); | ||||
| 
 | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* TODO do we care about trying to make sure the GPU is idle?
 | ||||
| 	 * Since this is just a debug feature limited to CAP_SYS_ADMIN, | ||||
| 	 * maybe it is fine to let the user keep both pieces if they | ||||
| 	 * try to reset an active GPU. | ||||
| 	 */ | ||||
| 
 | ||||
| 	mutex_lock(&dev->struct_mutex); | ||||
| 
 | ||||
| 	release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]); | ||||
| 	adreno_gpu->fw[ADRENO_FW_PM4] = NULL; | ||||
| 
 | ||||
| 	release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]); | ||||
| 	adreno_gpu->fw[ADRENO_FW_PFP] = NULL; | ||||
| 
 | ||||
| 	if (a5xx_gpu->pm4_bo) { | ||||
| 		if (a5xx_gpu->pm4_iova) | ||||
| 			msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference(a5xx_gpu->pm4_bo); | ||||
| 		a5xx_gpu->pm4_bo = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (a5xx_gpu->pfp_bo) { | ||||
| 		if (a5xx_gpu->pfp_iova) | ||||
| 			msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference(a5xx_gpu->pfp_bo); | ||||
| 		a5xx_gpu->pfp_bo = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	gpu->needs_hw_init = true; | ||||
| 
 | ||||
| 	pm_runtime_get_sync(&gpu->pdev->dev); | ||||
| 	gpu->funcs->recover(gpu); | ||||
| 
 | ||||
| 	pm_runtime_put_sync(&gpu->pdev->dev); | ||||
| 	mutex_unlock(&dev->struct_mutex); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); | ||||
| 
 | ||||
| 
 | ||||
| int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) | ||||
| { | ||||
| 	struct drm_device *dev; | ||||
| 	struct dentry *ent; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!minor) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	dev = minor->dev; | ||||
| 
 | ||||
| 	ret = drm_debugfs_create_files(a5xx_debugfs_list, | ||||
| 			ARRAY_SIZE(a5xx_debugfs_list), | ||||
| 			minor->debugfs_root, minor); | ||||
| 
 | ||||
| 	if (ret) { | ||||
| 		dev_err(dev->dev, "could not install a5xx_debugfs_list\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ent = debugfs_create_file("reset", S_IWUGO, | ||||
| 		minor->debugfs_root, | ||||
| 		dev, &reset_fops); | ||||
| 	if (!ent) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -140,6 +140,65 @@ static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) | ||||
| 		gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); | ||||
| } | ||||
| 
 | ||||
| static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
| 	struct msm_file_private *ctx) | ||||
| { | ||||
| 	struct msm_drm_private *priv = gpu->dev->dev_private; | ||||
| 	struct msm_ringbuffer *ring = submit->ring; | ||||
| 	struct msm_gem_object *obj; | ||||
| 	uint32_t *ptr, dwords; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	for (i = 0; i < submit->nr_cmds; i++) { | ||||
| 		switch (submit->cmd[i].type) { | ||||
| 		case MSM_SUBMIT_CMD_IB_TARGET_BUF: | ||||
| 			break; | ||||
| 		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: | ||||
| 			if (priv->lastctx == ctx) | ||||
| 				break; | ||||
| 		case MSM_SUBMIT_CMD_BUF: | ||||
| 			/* copy commands into RB: */ | ||||
| 			obj = submit->bos[submit->cmd[i].idx].obj; | ||||
| 			dwords = submit->cmd[i].size; | ||||
| 
 | ||||
| 			ptr = msm_gem_get_vaddr(&obj->base); | ||||
| 
 | ||||
| 			/* _get_vaddr() shouldn't fail at this point,
 | ||||
| 			 * since we've already mapped it once in | ||||
| 			 * submit_reloc() | ||||
| 			 */ | ||||
| 			if (WARN_ON(!ptr)) | ||||
| 				return; | ||||
| 
 | ||||
| 			for (i = 0; i < dwords; i++) { | ||||
| 				/* normally the OUT_PKTn() would wait
 | ||||
| 				 * for space for the packet.  But since | ||||
| 				 * we just OUT_RING() the whole thing, | ||||
| 				 * need to call adreno_wait_ring() | ||||
| 				 * ourself: | ||||
| 				 */ | ||||
| 				adreno_wait_ring(ring, 1); | ||||
| 				OUT_RING(ring, ptr[i]); | ||||
| 			} | ||||
| 
 | ||||
| 			msm_gem_put_vaddr(&obj->base); | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	a5xx_flush(gpu, ring); | ||||
| 	a5xx_preempt_trigger(gpu); | ||||
| 
 | ||||
| 	/* we might not necessarily have a cmd from userspace to
 | ||||
| 	 * trigger an event to know that submit has completed, so | ||||
| 	 * do this manually: | ||||
| 	 */ | ||||
| 	a5xx_idle(gpu, ring); | ||||
| 	ring->memptrs->fence = submit->seqno; | ||||
| 	msm_gpu_retire(gpu); | ||||
| } | ||||
| 
 | ||||
| static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
| 	struct msm_file_private *ctx) | ||||
| { | ||||
| @ -149,6 +208,12 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
| 	struct msm_ringbuffer *ring = submit->ring; | ||||
| 	unsigned int i, ibs = 0; | ||||
| 
 | ||||
| 	if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { | ||||
| 		priv->lastctx = NULL; | ||||
| 		a5xx_submit_in_rb(gpu, submit, ctx); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); | ||||
| 	OUT_RING(ring, 0x02); | ||||
| 
 | ||||
| @ -432,25 +497,6 @@ static int a5xx_preempt_start(struct msm_gpu *gpu) | ||||
| 	return a5xx_idle(gpu, ring) ? 0 : -EINVAL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu, | ||||
| 		const struct firmware *fw, u64 *iova) | ||||
| { | ||||
| 	struct drm_gem_object *bo; | ||||
| 	void *ptr; | ||||
| 
 | ||||
| 	ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, | ||||
| 		MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); | ||||
| 
 | ||||
| 	if (IS_ERR(ptr)) | ||||
| 		return ERR_CAST(ptr); | ||||
| 
 | ||||
| 	memcpy(ptr, &fw->data[4], fw->size - 4); | ||||
| 
 | ||||
| 	msm_gem_put_vaddr(bo); | ||||
| 	return bo; | ||||
| } | ||||
| 
 | ||||
| static int a5xx_ucode_init(struct msm_gpu *gpu) | ||||
| { | ||||
| 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||||
| @ -458,8 +504,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!a5xx_gpu->pm4_bo) { | ||||
| 		a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pm4, | ||||
| 			&a5xx_gpu->pm4_iova); | ||||
| 		a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu, | ||||
| 			adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); | ||||
| 
 | ||||
| 		if (IS_ERR(a5xx_gpu->pm4_bo)) { | ||||
| 			ret = PTR_ERR(a5xx_gpu->pm4_bo); | ||||
| @ -471,8 +517,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) | ||||
| 	} | ||||
| 
 | ||||
| 	if (!a5xx_gpu->pfp_bo) { | ||||
| 		a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pfp, | ||||
| 			&a5xx_gpu->pfp_iova); | ||||
| 		a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu, | ||||
| 			adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); | ||||
| 
 | ||||
| 		if (IS_ERR(a5xx_gpu->pfp_bo)) { | ||||
| 			ret = PTR_ERR(a5xx_gpu->pfp_bo); | ||||
| @ -793,19 +839,19 @@ static void a5xx_destroy(struct msm_gpu *gpu) | ||||
| 	if (a5xx_gpu->pm4_bo) { | ||||
| 		if (a5xx_gpu->pm4_iova) | ||||
| 			msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference_unlocked(a5xx_gpu->pm4_bo); | ||||
| 		drm_gem_object_put_unlocked(a5xx_gpu->pm4_bo); | ||||
| 	} | ||||
| 
 | ||||
| 	if (a5xx_gpu->pfp_bo) { | ||||
| 		if (a5xx_gpu->pfp_iova) | ||||
| 			msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo); | ||||
| 		drm_gem_object_put_unlocked(a5xx_gpu->pfp_bo); | ||||
| 	} | ||||
| 
 | ||||
| 	if (a5xx_gpu->gpmu_bo) { | ||||
| 		if (a5xx_gpu->gpmu_iova) | ||||
| 			msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo); | ||||
| 		drm_gem_object_put_unlocked(a5xx_gpu->gpmu_bo); | ||||
| 	} | ||||
| 
 | ||||
| 	adreno_gpu_cleanup(adreno_gpu); | ||||
| @ -1195,6 +1241,7 @@ static const struct adreno_gpu_funcs funcs = { | ||||
| 		.destroy = a5xx_destroy, | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 		.show = a5xx_show, | ||||
| 		.debugfs_init = a5xx_debugfs_init, | ||||
| #endif | ||||
| 		.gpu_busy = a5xx_gpu_busy, | ||||
| 	}, | ||||
|  | ||||
| @ -49,6 +49,10 @@ struct a5xx_gpu { | ||||
| 
 | ||||
| #define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor); | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * In order to do lockless preemption we use a simple state machine to progress | ||||
|  * through the process. | ||||
|  | ||||
| @ -261,7 +261,6 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) | ||||
| 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||||
| 	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); | ||||
| 	struct drm_device *drm = gpu->dev; | ||||
| 	const struct firmware *fw; | ||||
| 	uint32_t dwords = 0, offset = 0, bosize; | ||||
| 	unsigned int *data, *ptr, *cmds; | ||||
| 	unsigned int cmds_size; | ||||
| @ -269,15 +268,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) | ||||
| 	if (a5xx_gpu->gpmu_bo) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* Get the firmware */ | ||||
| 	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->gpmufw); | ||||
| 	if (IS_ERR(fw)) { | ||||
| 		DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n", | ||||
| 			gpu->name); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	data = (unsigned int *) fw->data; | ||||
| 	data = (unsigned int *) adreno_gpu->fw[ADRENO_FW_GPMU]->data; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The first dword is the size of the remaining data in dwords. Use it | ||||
| @ -285,12 +276,14 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) | ||||
| 	 * the firmware that we read | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2))) | ||||
| 		goto out; | ||||
| 	if (adreno_gpu->fw[ADRENO_FW_GPMU]->size < 8 || | ||||
| 		(data[0] < 2) || (data[0] >= | ||||
| 			(adreno_gpu->fw[ADRENO_FW_GPMU]->size >> 2))) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */ | ||||
| 	if (data[1] != 2) | ||||
| 		goto out; | ||||
| 		return; | ||||
| 
 | ||||
| 	cmds = data + data[2] + 3; | ||||
| 	cmds_size = data[0] - data[2] - 2; | ||||
| @ -325,8 +318,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) | ||||
| 	msm_gem_put_vaddr(a5xx_gpu->gpmu_bo); | ||||
| 	a5xx_gpu->gpmu_dwords = dwords; | ||||
| 
 | ||||
| 	goto out; | ||||
| 
 | ||||
| 	return; | ||||
| err: | ||||
| 	if (a5xx_gpu->gpmu_iova) | ||||
| 		msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); | ||||
| @ -336,8 +328,4 @@ err: | ||||
| 	a5xx_gpu->gpmu_bo = NULL; | ||||
| 	a5xx_gpu->gpmu_iova = 0; | ||||
| 	a5xx_gpu->gpmu_dwords = 0; | ||||
| 
 | ||||
| out: | ||||
| 	/* No need to keep that firmware laying around anymore */ | ||||
| 	release_firmware(fw); | ||||
| } | ||||
|  | ||||
| @ -30,61 +30,75 @@ static const struct adreno_info gpulist[] = { | ||||
| 		.rev   = ADRENO_REV(3, 0, 5, ANY_ID), | ||||
| 		.revn  = 305, | ||||
| 		.name  = "A305", | ||||
| 		.pm4fw = "a300_pm4.fw", | ||||
| 		.pfpfw = "a300_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a300_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a300_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = SZ_256K, | ||||
| 		.init  = a3xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev   = ADRENO_REV(3, 0, 6, 0), | ||||
| 		.revn  = 307,        /* because a305c is revn==306 */ | ||||
| 		.name  = "A306", | ||||
| 		.pm4fw = "a300_pm4.fw", | ||||
| 		.pfpfw = "a300_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a300_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a300_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = SZ_128K, | ||||
| 		.init  = a3xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID), | ||||
| 		.revn  = 320, | ||||
| 		.name  = "A320", | ||||
| 		.pm4fw = "a300_pm4.fw", | ||||
| 		.pfpfw = "a300_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a300_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a300_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = SZ_512K, | ||||
| 		.init  = a3xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev   = ADRENO_REV(3, 3, 0, ANY_ID), | ||||
| 		.revn  = 330, | ||||
| 		.name  = "A330", | ||||
| 		.pm4fw = "a330_pm4.fw", | ||||
| 		.pfpfw = "a330_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a330_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a330_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = SZ_1M, | ||||
| 		.init  = a3xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev   = ADRENO_REV(4, 2, 0, ANY_ID), | ||||
| 		.revn  = 420, | ||||
| 		.name  = "A420", | ||||
| 		.pm4fw = "a420_pm4.fw", | ||||
| 		.pfpfw = "a420_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a420_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a420_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = (SZ_1M + SZ_512K), | ||||
| 		.init  = a4xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev   = ADRENO_REV(4, 3, 0, ANY_ID), | ||||
| 		.revn  = 430, | ||||
| 		.name  = "A430", | ||||
| 		.pm4fw = "a420_pm4.fw", | ||||
| 		.pfpfw = "a420_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a420_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a420_pfp.fw", | ||||
| 		}, | ||||
| 		.gmem  = (SZ_1M + SZ_512K), | ||||
| 		.init  = a4xx_gpu_init, | ||||
| 	}, { | ||||
| 		.rev = ADRENO_REV(5, 3, 0, 2), | ||||
| 		.revn = 530, | ||||
| 		.name = "A530", | ||||
| 		.pm4fw = "a530_pm4.fw", | ||||
| 		.pfpfw = "a530_pfp.fw", | ||||
| 		.fw = { | ||||
| 			[ADRENO_FW_PM4] = "a530_pm4.fw", | ||||
| 			[ADRENO_FW_PFP] = "a530_pfp.fw", | ||||
| 			[ADRENO_FW_GPMU] = "a530v3_gpmu.fw2", | ||||
| 		}, | ||||
| 		.gmem = SZ_1M, | ||||
| 		.quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | | ||||
| 			ADRENO_QUIRK_FAULT_DETECT_MASK, | ||||
| 		.init = a5xx_gpu_init, | ||||
| 		.gpmufw = "a530v3_gpmu.fw2", | ||||
| 		.zapfw = "a530_zap.mdt", | ||||
| 	}, | ||||
| }; | ||||
| @ -150,6 +164,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 	if (gpu->funcs->debugfs_init) { | ||||
| 		gpu->funcs->debugfs_init(gpu, dev->primary); | ||||
| 		gpu->funcs->debugfs_init(gpu, dev->render); | ||||
| 		gpu->funcs->debugfs_init(gpu, dev->control); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	return gpu; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -140,27 +140,47 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname) | ||||
| 
 | ||||
| static int adreno_load_fw(struct adreno_gpu *adreno_gpu) | ||||
| { | ||||
| 	const struct firmware *fw; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (adreno_gpu->pm4) | ||||
| 		return 0; | ||||
| 	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) { | ||||
| 		const struct firmware *fw; | ||||
| 
 | ||||
| 	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pm4fw); | ||||
| 	if (IS_ERR(fw)) | ||||
| 		return PTR_ERR(fw); | ||||
| 	adreno_gpu->pm4 = fw; | ||||
| 		if (!adreno_gpu->info->fw[i]) | ||||
| 			continue; | ||||
| 
 | ||||
| 	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pfpfw); | ||||
| 	if (IS_ERR(fw)) { | ||||
| 		release_firmware(adreno_gpu->pm4); | ||||
| 		adreno_gpu->pm4 = NULL; | ||||
| 		return PTR_ERR(fw); | ||||
| 		/* Skip if the firmware has already been loaded */ | ||||
| 		if (adreno_gpu->fw[i]) | ||||
| 			continue; | ||||
| 
 | ||||
| 		fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->fw[i]); | ||||
| 		if (IS_ERR(fw)) | ||||
| 			return PTR_ERR(fw); | ||||
| 
 | ||||
| 		adreno_gpu->fw[i] = fw; | ||||
| 	} | ||||
| 	adreno_gpu->pfp = fw; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, | ||||
| 		const struct firmware *fw, u64 *iova) | ||||
| { | ||||
| 	struct drm_gem_object *bo; | ||||
| 	void *ptr; | ||||
| 
 | ||||
| 	ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, | ||||
| 		MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); | ||||
| 
 | ||||
| 	if (IS_ERR(ptr)) | ||||
| 		return ERR_CAST(ptr); | ||||
| 
 | ||||
| 	memcpy(ptr, &fw->data[4], fw->size - 4); | ||||
| 
 | ||||
| 	msm_gem_put_vaddr(bo); | ||||
| 
 | ||||
| 	return bo; | ||||
| } | ||||
| 
 | ||||
| int adreno_hw_init(struct msm_gpu *gpu) | ||||
| { | ||||
| 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||||
| @ -293,26 +313,12 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
| 		OUT_RING(ring, 0x00000000); | ||||
| 	} | ||||
| 
 | ||||
| 	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ | ||||
| 	OUT_PKT3(ring, CP_EVENT_WRITE, 3); | ||||
| 	OUT_RING(ring, CACHE_FLUSH_TS); | ||||
| 	OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); | ||||
| 	OUT_RING(ring, rbmemptr(ring, fence)); | ||||
| 	OUT_RING(ring, submit->seqno); | ||||
| 
 | ||||
| 	/* we could maybe be clever and only CP_COND_EXEC the interrupt: */ | ||||
| 	OUT_PKT3(ring, CP_INTERRUPT, 1); | ||||
| 	OUT_RING(ring, 0x80000000); | ||||
| 
 | ||||
| 	/* Workaround for missing irq issue on 8x16/a306.  Unsure if the
 | ||||
| 	 * root cause is a platform issue or some a306 quirk, but this | ||||
| 	 * keeps things humming along: | ||||
| 	 */ | ||||
| 	if (adreno_is_a306(adreno_gpu)) { | ||||
| 		OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); | ||||
| 		OUT_RING(ring, 0x00000000); | ||||
| 		OUT_PKT3(ring, CP_INTERRUPT, 1); | ||||
| 		OUT_RING(ring, 0x80000000); | ||||
| 	} | ||||
| 
 | ||||
| #if 0 | ||||
| 	if (adreno_is_a3xx(adreno_gpu)) { | ||||
| 		/* Dummy set-constant to trigger context rollover */ | ||||
| @ -569,8 +575,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, | ||||
| 
 | ||||
| void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) | ||||
| { | ||||
| 	release_firmware(adreno_gpu->pm4); | ||||
| 	release_firmware(adreno_gpu->pfp); | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) | ||||
| 		release_firmware(adreno_gpu->fw[i]); | ||||
| 
 | ||||
| 	msm_gpu_cleanup(&adreno_gpu->base); | ||||
| } | ||||
|  | ||||
| @ -48,6 +48,13 @@ enum adreno_regs { | ||||
| 	REG_ADRENO_REGISTER_MAX, | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
| 	ADRENO_FW_PM4 = 0, | ||||
| 	ADRENO_FW_PFP = 1, | ||||
| 	ADRENO_FW_GPMU = 2, | ||||
| 	ADRENO_FW_MAX, | ||||
| }; | ||||
| 
 | ||||
| enum adreno_quirks { | ||||
| 	ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, | ||||
| 	ADRENO_QUIRK_FAULT_DETECT_MASK = 2, | ||||
| @ -72,8 +79,7 @@ struct adreno_info { | ||||
| 	struct adreno_rev rev; | ||||
| 	uint32_t revn; | ||||
| 	const char *name; | ||||
| 	const char *pm4fw, *pfpfw; | ||||
| 	const char *gpmufw; | ||||
| 	const char *fw[ADRENO_FW_MAX]; | ||||
| 	uint32_t gmem; | ||||
| 	enum adreno_quirks quirks; | ||||
| 	struct msm_gpu *(*init)(struct drm_device *dev); | ||||
| @ -115,7 +121,7 @@ struct adreno_gpu { | ||||
| 	} fwloc; | ||||
| 
 | ||||
| 	/* firmware: */ | ||||
| 	const struct firmware *pm4, *pfp; | ||||
| 	const struct firmware *fw[ADRENO_FW_MAX]; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Register offsets are different between some GPUs. | ||||
| @ -200,6 +206,8 @@ static inline int adreno_is_a530(struct adreno_gpu *gpu) | ||||
| int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); | ||||
| const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, | ||||
| 		const char *fwname); | ||||
| struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, | ||||
| 		const struct firmware *fw, u64 *iova); | ||||
| int adreno_hw_init(struct msm_gpu *gpu); | ||||
| void adreno_recover(struct msm_gpu *gpu); | ||||
| void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
|  | ||||
| @ -129,7 +129,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) | ||||
| 	struct msm_kms *kms = &mdp4_kms->base.base; | ||||
| 
 | ||||
| 	msm_gem_put_iova(val, kms->aspace); | ||||
| 	drm_gem_object_unreference_unlocked(val); | ||||
| 	drm_gem_object_put_unlocked(val); | ||||
| } | ||||
| 
 | ||||
| static void mdp4_crtc_destroy(struct drm_crtc *crtc) | ||||
| @ -382,7 +382,7 @@ static void update_cursor(struct drm_crtc *crtc) | ||||
| 
 | ||||
| 		if (next_bo) { | ||||
| 			/* take a obj ref + iova ref when we start scanning out: */ | ||||
| 			drm_gem_object_reference(next_bo); | ||||
| 			drm_gem_object_get(next_bo); | ||||
| 			msm_gem_get_iova(next_bo, kms->aspace, &iova); | ||||
| 
 | ||||
| 			/* enable cursor: */ | ||||
| @ -467,7 +467,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, | ||||
| 	return 0; | ||||
| 
 | ||||
| fail: | ||||
| 	drm_gem_object_unreference_unlocked(cursor_bo); | ||||
| 	drm_gem_object_put_unlocked(cursor_bo); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -164,7 +164,7 @@ static void mdp4_destroy(struct msm_kms *kms) | ||||
| 
 | ||||
| 	if (mdp4_kms->blank_cursor_iova) | ||||
| 		msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace); | ||||
| 	drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); | ||||
| 	drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo); | ||||
| 
 | ||||
| 	if (aspace) { | ||||
| 		aspace->mmu->funcs->detach(aspace->mmu, | ||||
| @ -22,7 +22,7 @@ | ||||
| 
 | ||||
| #include "msm_drv.h" | ||||
| #include "msm_kms.h" | ||||
| #include "mdp/mdp_kms.h" | ||||
| #include "disp/mdp_kms.h" | ||||
| #include "mdp4.xml.h" | ||||
| 
 | ||||
| struct device_node; | ||||
| @ -159,7 +159,7 @@ void mdp5_cmd_encoder_disable(struct drm_encoder *encoder) | ||||
| 	pingpong_tearcheck_disable(encoder); | ||||
| 
 | ||||
| 	mdp5_ctl_set_encoder_state(ctl, pipeline, false); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); | ||||
| 
 | ||||
| 	bs_set(mdp5_cmd_enc, 0); | ||||
| 
 | ||||
| @ -180,7 +180,7 @@ void mdp5_cmd_encoder_enable(struct drm_encoder *encoder) | ||||
| 	if (pingpong_tearcheck_enable(encoder)) | ||||
| 		return; | ||||
| 
 | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); | ||||
| 
 | ||||
| 	mdp5_ctl_set_encoder_state(ctl, pipeline, true); | ||||
| 
 | ||||
| @ -97,9 +97,13 @@ static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask) | ||||
| 	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); | ||||
| 	struct mdp5_ctl *ctl = mdp5_cstate->ctl; | ||||
| 	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; | ||||
| 	bool start = !mdp5_cstate->defer_start; | ||||
| 
 | ||||
| 	mdp5_cstate->defer_start = false; | ||||
| 
 | ||||
| 	DBG("%s: flush=%08x", crtc->name, flush_mask); | ||||
| 	return mdp5_ctl_commit(ctl, pipeline, flush_mask); | ||||
| 
 | ||||
| 	return mdp5_ctl_commit(ctl, pipeline, flush_mask, start); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -170,7 +174,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) | ||||
| 	struct msm_kms *kms = &mdp5_kms->base.base; | ||||
| 
 | ||||
| 	msm_gem_put_iova(val, kms->aspace); | ||||
| 	drm_gem_object_unreference_unlocked(val); | ||||
| 	drm_gem_object_put_unlocked(val); | ||||
| } | ||||
| 
 | ||||
| static void mdp5_crtc_destroy(struct drm_crtc *crtc) | ||||
| @ -947,12 +951,17 @@ mdp5_crtc_atomic_print_state(struct drm_printer *p, | ||||
| 	if (WARN_ON(!pipeline)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (mdp5_cstate->ctl) | ||||
| 		drm_printf(p, "\tctl=%d\n", mdp5_ctl_get_ctl_id(mdp5_cstate->ctl)); | ||||
| 
 | ||||
| 	drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ? | ||||
| 			pipeline->mixer->name : "(null)"); | ||||
| 
 | ||||
| 	if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT) | ||||
| 		drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ? | ||||
| 			   pipeline->r_mixer->name : "(null)"); | ||||
| 
 | ||||
| 	drm_printf(p, "\tcmd_mode=%d\n", mdp5_cstate->cmd_mode); | ||||
| } | ||||
| 
 | ||||
| static void mdp5_crtc_reset(struct drm_crtc *crtc) | ||||
| @ -41,7 +41,9 @@ struct mdp5_ctl { | ||||
| 	u32 status; | ||||
| 
 | ||||
| 	bool encoder_enabled; | ||||
| 	uint32_t start_mask; | ||||
| 
 | ||||
| 	/* pending flush_mask bits */ | ||||
| 	u32 flush_mask; | ||||
| 
 | ||||
| 	/* REG_MDP5_CTL_*(<id>) registers access info + lock: */ | ||||
| 	spinlock_t hw_lock; | ||||
| @ -173,16 +175,8 @@ static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline) | ||||
| 
 | ||||
| int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline) | ||||
| { | ||||
| 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; | ||||
| 	struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr); | ||||
| 	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm); | ||||
| 	struct mdp5_interface *intf = pipeline->intf; | ||||
| 	struct mdp5_hw_mixer *mixer = pipeline->mixer; | ||||
| 	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; | ||||
| 
 | ||||
| 	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) | | ||||
| 			  mdp_ctl_flush_mask_encoder(intf); | ||||
| 	if (r_mixer) | ||||
| 		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); | ||||
| 
 | ||||
| 	/* Virtual interfaces need not set a display intf (e.g.: Writeback) */ | ||||
| 	if (!mdp5_cfg_intf_is_virtual(intf->type)) | ||||
| @ -198,7 +192,7 @@ static bool start_signal_needed(struct mdp5_ctl *ctl, | ||||
| { | ||||
| 	struct mdp5_interface *intf = pipeline->intf; | ||||
| 
 | ||||
| 	if (!ctl->encoder_enabled || ctl->start_mask != 0) | ||||
| 	if (!ctl->encoder_enabled) | ||||
| 		return false; | ||||
| 
 | ||||
| 	switch (intf->type) { | ||||
| @ -227,25 +221,6 @@ static void send_start_signal(struct mdp5_ctl *ctl) | ||||
| 	spin_unlock_irqrestore(&ctl->hw_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void refill_start_mask(struct mdp5_ctl *ctl, | ||||
| 			      struct mdp5_pipeline *pipeline) | ||||
| { | ||||
| 	struct mdp5_interface *intf = pipeline->intf; | ||||
| 	struct mdp5_hw_mixer *mixer = pipeline->mixer; | ||||
| 	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; | ||||
| 
 | ||||
| 	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm); | ||||
| 	if (r_mixer) | ||||
| 		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Writeback encoder needs to program & flush | ||||
| 	 * address registers for each page flip.. | ||||
| 	 */ | ||||
| 	if (intf->type == INTF_WB) | ||||
| 		ctl->start_mask |= mdp_ctl_flush_mask_encoder(intf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * mdp5_ctl_set_encoder_state() - set the encoder state | ||||
|  * | ||||
| @ -268,7 +243,6 @@ int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, | ||||
| 
 | ||||
| 	if (start_signal_needed(ctl, pipeline)) { | ||||
| 		send_start_signal(ctl); | ||||
| 		refill_start_mask(ctl, pipeline); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -494,6 +468,8 @@ u32 mdp_ctl_flush_mask_lm(int lm) | ||||
| 	case 0:  return MDP5_CTL_FLUSH_LM0; | ||||
| 	case 1:  return MDP5_CTL_FLUSH_LM1; | ||||
| 	case 2:  return MDP5_CTL_FLUSH_LM2; | ||||
| 	case 3:  return MDP5_CTL_FLUSH_LM3; | ||||
| 	case 4:  return MDP5_CTL_FLUSH_LM4; | ||||
| 	case 5:  return MDP5_CTL_FLUSH_LM5; | ||||
| 	default: return 0; | ||||
| 	} | ||||
| @ -557,17 +533,14 @@ static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask, | ||||
|  */ | ||||
| u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, | ||||
| 		    struct mdp5_pipeline *pipeline, | ||||
| 		    u32 flush_mask) | ||||
| 		    u32 flush_mask, bool start) | ||||
| { | ||||
| 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; | ||||
| 	unsigned long flags; | ||||
| 	u32 flush_id = ctl->id; | ||||
| 	u32 curr_ctl_flush_mask; | ||||
| 
 | ||||
| 	ctl->start_mask &= ~flush_mask; | ||||
| 
 | ||||
| 	VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask, | ||||
| 			ctl->start_mask, ctl->pending_ctl_trigger); | ||||
| 	VERB("flush_mask=%x, trigger=%x", flush_mask, ctl->pending_ctl_trigger); | ||||
| 
 | ||||
| 	if (ctl->pending_ctl_trigger & flush_mask) { | ||||
| 		flush_mask |= MDP5_CTL_FLUSH_CTL; | ||||
| @ -582,6 +555,14 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, | ||||
| 
 | ||||
| 	fix_for_single_flush(ctl, &flush_mask, &flush_id); | ||||
| 
 | ||||
| 	if (!start) { | ||||
| 		ctl->flush_mask |= flush_mask; | ||||
| 		return curr_ctl_flush_mask; | ||||
| 	} else { | ||||
| 		flush_mask |= ctl->flush_mask; | ||||
| 		ctl->flush_mask = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (flush_mask) { | ||||
| 		spin_lock_irqsave(&ctl->hw_lock, flags); | ||||
| 		ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask); | ||||
| @ -590,7 +571,6 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, | ||||
| 
 | ||||
| 	if (start_signal_needed(ctl, pipeline)) { | ||||
| 		send_start_signal(ctl); | ||||
| 		refill_start_mask(ctl, pipeline); | ||||
| 	} | ||||
| 
 | ||||
| 	return curr_ctl_flush_mask; | ||||
| @ -711,6 +691,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, | ||||
| 	struct mdp5_ctl_manager *ctl_mgr; | ||||
| 	const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd); | ||||
| 	int rev = mdp5_cfg_get_hw_rev(cfg_hnd); | ||||
| 	unsigned dsi_cnt = 0; | ||||
| 	const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl; | ||||
| 	unsigned long flags; | ||||
| 	int c, ret; | ||||
| @ -760,7 +741,10 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, | ||||
| 	 * only write into CTL0's FLUSH register) to keep two DSI pipes in sync. | ||||
| 	 * Single FLUSH is supported from hw rev v3.0. | ||||
| 	 */ | ||||
| 	if (rev >= 3) { | ||||
| 	for (c = 0; c < ARRAY_SIZE(hw_cfg->intf.connect); c++) | ||||
| 		if (hw_cfg->intf.connect[c] == INTF_DSI) | ||||
| 			dsi_cnt++; | ||||
| 	if ((rev >= 3) && (dsi_cnt > 1)) { | ||||
| 		ctl_mgr->single_flush_supported = true; | ||||
| 		/* Reserve CTL0/1 for INTF1/2 */ | ||||
| 		ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED; | ||||
| @ -78,7 +78,7 @@ u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf); | ||||
| 
 | ||||
| /* @flush_mask: see CTL flush masks definitions below */ | ||||
| u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, | ||||
| 		    u32 flush_mask); | ||||
| 		    u32 flush_mask, bool start); | ||||
| u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl); | ||||
| 
 | ||||
| 
 | ||||
| @ -228,7 +228,7 @@ static void mdp5_vid_encoder_disable(struct drm_encoder *encoder) | ||||
| 	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); | ||||
| 	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0); | ||||
| 	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Wait for a vsync so we know the ENABLE=0 latched before | ||||
| @ -262,7 +262,7 @@ static void mdp5_vid_encoder_enable(struct drm_encoder *encoder) | ||||
| 	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); | ||||
| 	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1); | ||||
| 	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf)); | ||||
| 	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true); | ||||
| 
 | ||||
| 	mdp5_ctl_set_encoder_state(ctl, pipeline, true); | ||||
| 
 | ||||
| @ -319,6 +319,7 @@ static int mdp5_encoder_atomic_check(struct drm_encoder *encoder, | ||||
| 
 | ||||
| 	mdp5_cstate->ctl = ctl; | ||||
| 	mdp5_cstate->pipeline.intf = intf; | ||||
| 	mdp5_cstate->defer_start = true; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) | ||||
| 	} else { | ||||
| 		dev_info(&pdev->dev, | ||||
| 			 "no iommu, fallback to phys contig buffers for scanout\n"); | ||||
| 		aspace = NULL;; | ||||
| 		aspace = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	pm_runtime_put_sync(&pdev->dev); | ||||
| @ -20,7 +20,7 @@ | ||||
| 
 | ||||
| #include "msm_drv.h" | ||||
| #include "msm_kms.h" | ||||
| #include "mdp/mdp_kms.h" | ||||
| #include "disp/mdp_kms.h" | ||||
| #include "mdp5_cfg.h"	/* must be included before mdp5.xml.h */ | ||||
| #include "mdp5.xml.h" | ||||
| #include "mdp5_pipe.h" | ||||
| @ -133,6 +133,14 @@ struct mdp5_crtc_state { | ||||
| 	u32 pp_done_irqmask; | ||||
| 
 | ||||
| 	bool cmd_mode; | ||||
| 
 | ||||
| 	/* should we not write CTL[n].START register on flush?  If the
 | ||||
| 	 * encoder has changed this is set to true, since encoder->enable() | ||||
| 	 * is called after crtc state is committed, but we only want to | ||||
| 	 * write the CTL[n].START register once.  This lets us defer | ||||
| 	 * writing CTL[n].START until encoder->enable() | ||||
| 	 */ | ||||
| 	bool defer_start; | ||||
| }; | ||||
| #define to_mdp5_crtc_state(x) \ | ||||
| 		container_of(x, struct mdp5_crtc_state, base) | ||||
| @ -535,7 +535,7 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane, | ||||
| 
 | ||||
| 		ctl = mdp5_crtc_get_ctl(new_state->crtc); | ||||
| 
 | ||||
| 		mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane)); | ||||
| 		mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane), true); | ||||
| 	} | ||||
| 
 | ||||
| 	*to_mdp5_plane_state(plane->state) = | ||||
| @ -192,13 +192,14 @@ void __exit msm_dsi_unregister(void) | ||||
| int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, | ||||
| 			 struct drm_encoder *encoder) | ||||
| { | ||||
| 	struct msm_drm_private *priv = dev->dev_private; | ||||
| 	struct msm_drm_private *priv; | ||||
| 	struct drm_bridge *ext_bridge; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (WARN_ON(!encoder)) | ||||
| 	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	priv = dev->dev_private; | ||||
| 	msm_dsi->dev = dev; | ||||
| 
 | ||||
| 	ret = msm_dsi_host_modeset_init(msm_dsi->host, dev); | ||||
| @ -245,20 +246,18 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, | ||||
| 
 | ||||
| 	return 0; | ||||
| fail: | ||||
| 	if (msm_dsi) { | ||||
| 		/* bridge/connector are normally destroyed by drm: */ | ||||
| 		if (msm_dsi->bridge) { | ||||
| 			msm_dsi_manager_bridge_destroy(msm_dsi->bridge); | ||||
| 			msm_dsi->bridge = NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		/* don't destroy connector if we didn't make it */ | ||||
| 		if (msm_dsi->connector && !msm_dsi->external_bridge) | ||||
| 			msm_dsi->connector->funcs->destroy(msm_dsi->connector); | ||||
| 
 | ||||
| 		msm_dsi->connector = NULL; | ||||
| 	/* bridge/connector are normally destroyed by drm: */ | ||||
| 	if (msm_dsi->bridge) { | ||||
| 		msm_dsi_manager_bridge_destroy(msm_dsi->bridge); | ||||
| 		msm_dsi->bridge = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* don't destroy connector if we didn't make it */ | ||||
| 	if (msm_dsi->connector && !msm_dsi->external_bridge) | ||||
| 		msm_dsi->connector->funcs->destroy(msm_dsi->connector); | ||||
| 
 | ||||
| 	msm_dsi->connector = NULL; | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -36,6 +36,7 @@ enum msm_dsi_phy_type { | ||||
| 	MSM_DSI_PHY_20NM, | ||||
| 	MSM_DSI_PHY_28NM_8960, | ||||
| 	MSM_DSI_PHY_14NM, | ||||
| 	MSM_DSI_PHY_10NM, | ||||
| 	MSM_DSI_PHY_MAX | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -8,19 +8,10 @@ http://github.com/freedreno/envytools/ | ||||
| git clone https://github.com/freedreno/envytools.git
 | ||||
| 
 | ||||
| The rules-ng-ng source files this header was generated from are: | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42) | ||||
| - /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27) | ||||
| - /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/dsi/dsi.xml    (  37239 bytes, from 2018-01-12 09:09:22) | ||||
| - /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2016-05-09 06:32:54) | ||||
| 
 | ||||
| Copyright (C) 2013-2017 by the following authors: | ||||
| Copyright (C) 2013-2018 by the following authors: | ||||
| - Rob Clark <robdclark@gmail.com> (robclark) | ||||
| - Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) | ||||
| 
 | ||||
| @ -1556,5 +1547,175 @@ static inline uint32_t REG_DSI_14nm_PHY_LN_VREG_CNTRL(uint32_t i0) { return 0x00 | ||||
| 
 | ||||
| #define REG_DSI_14nm_PHY_PLL_PLL_BANDGAP			0x00000108 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_REVISION_ID0			0x00000000 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_REVISION_ID1			0x00000004 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_REVISION_ID2			0x00000008 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_REVISION_ID3			0x0000000c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_CLK_CFG0				0x00000010 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_CLK_CFG1				0x00000014 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_GLBL_CTRL				0x00000018 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_RBUF_CTRL				0x0000001c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_VREG_CTRL				0x00000020 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_CTRL_0				0x00000024 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_CTRL_1				0x00000028 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_CTRL_2				0x0000002c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CFG0				0x00000030 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CFG1				0x00000034 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_PLL_CNTRL				0x00000038 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CTRL0				0x00000098 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CTRL1				0x0000009c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CTRL2				0x000000a0 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CTRL3				0x000000a4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_CTRL4				0x000000a8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0			0x000000ac | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1			0x000000b0 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2			0x000000b4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3			0x000000b8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4			0x000000bc | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5			0x000000c0 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6			0x000000c4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7			0x000000c8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8			0x000000cc | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9			0x000000d0 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10			0x000000d4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11			0x000000d8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_PHY_STATUS				0x000000ec | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_STATUS0			0x000000f4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_CMN_LANE_STATUS1			0x000000f8 | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_CFG0(uint32_t i0) { return 0x00000000 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_CFG1(uint32_t i0) { return 0x00000004 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_CFG2(uint32_t i0) { return 0x00000008 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_CFG3(uint32_t i0) { return 0x0000000c + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000010 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_PIN_SWAP(uint32_t i0) { return 0x00000014 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(uint32_t i0) { return 0x00000018 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(uint32_t i0) { return 0x0000001c + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(uint32_t i0) { return 0x00000020 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(uint32_t i0) { return 0x00000024 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_LPRX_CTRL(uint32_t i0) { return 0x00000028 + 0x80*i0; } | ||||
| 
 | ||||
| static inline uint32_t REG_DSI_10nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x0000002c + 0x80*i0; } | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE		0x00000000 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO		0x00000004 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE		0x00000010 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_DSM_DIVIDER			0x0000001c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER			0x00000020 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES			0x00000024 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_CMODE				0x0000002c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS		0x00000030 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE	0x00000054 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE		0x00000064 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PFILT				0x0000007c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_IFILT				0x00000080 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_OUTDIV				0x00000094 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE			0x000000a4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE		0x000000a8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO		0x000000b4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1		0x000000cc | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1		0x000000d0 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1		0x000000d4 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1		0x000000d8 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1			0x0000010c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1		0x00000110 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1			0x00000114 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1			0x00000118 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1		0x0000011c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1		0x00000120 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_SSC_CONTROL			0x0000013c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE			0x00000140 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1			0x00000144 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1		0x0000014c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1		0x00000154 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1		0x0000015c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1	0x00000164 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE			0x00000180 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY			0x00000184 | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS			0x0000018c | ||||
| 
 | ||||
| #define REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE			0x000001a0 | ||||
| 
 | ||||
| 
 | ||||
| #endif /* DSI_XML */ | ||||
|  | ||||
| @ -118,6 +118,24 @@ static const struct msm_dsi_config msm8996_dsi_cfg = { | ||||
| 	.num_dsi = 2, | ||||
| }; | ||||
| 
 | ||||
| static const char * const dsi_sdm845_bus_clk_names[] = { | ||||
| 	"iface", "bus", | ||||
| }; | ||||
| 
 | ||||
| static const struct msm_dsi_config sdm845_dsi_cfg = { | ||||
| 	.io_offset = DSI_6G_REG_SHIFT, | ||||
| 	.reg_cfg = { | ||||
| 		.num = 1, | ||||
| 		.regs = { | ||||
| 			{"vdda", 21800, 4 },	/* 1.2 V */ | ||||
| 		}, | ||||
| 	}, | ||||
| 	.bus_clk_names = dsi_sdm845_bus_clk_names, | ||||
| 	.num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names), | ||||
| 	.io_start = { 0xae94000, 0xae96000 }, | ||||
| 	.num_dsi = 2, | ||||
| }; | ||||
| 
 | ||||
| static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { | ||||
| 	{MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg}, | ||||
| 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0, | ||||
| @ -131,6 +149,7 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { | ||||
| 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg}, | ||||
| 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg}, | ||||
| 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg}, | ||||
| 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg}, | ||||
| }; | ||||
| 
 | ||||
| const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
| #define MSM_DSI_6G_VER_MINOR_V1_3	0x10030000 | ||||
| #define MSM_DSI_6G_VER_MINOR_V1_3_1	0x10030001 | ||||
| #define MSM_DSI_6G_VER_MINOR_V1_4_1	0x10040001 | ||||
| #define MSM_DSI_6G_VER_MINOR_V2_2_1	0x20020001 | ||||
| 
 | ||||
| #define MSM_DSI_V2_VER_MINOR_8064	0x0 | ||||
| 
 | ||||
|  | ||||
| @ -115,6 +115,7 @@ struct msm_dsi_host { | ||||
| 	struct clk *pixel_clk; | ||||
| 	struct clk *byte_clk_src; | ||||
| 	struct clk *pixel_clk_src; | ||||
| 	struct clk *byte_intf_clk; | ||||
| 
 | ||||
| 	u32 byte_clk_rate; | ||||
| 	u32 esc_clk_rate; | ||||
| @ -214,7 +215,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	ahb_clk = clk_get(dev, "iface_clk"); | ||||
| 	ahb_clk = msm_clk_get(msm_host->pdev, "iface"); | ||||
| 	if (IS_ERR(ahb_clk)) { | ||||
| 		pr_err("%s: cannot get interface clock\n", __func__); | ||||
| 		goto put_gdsc; | ||||
| @ -225,7 +226,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( | ||||
| 	ret = regulator_enable(gdsc_reg); | ||||
| 	if (ret) { | ||||
| 		pr_err("%s: unable to enable gdsc\n", __func__); | ||||
| 		goto put_clk; | ||||
| 		goto put_gdsc; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = clk_prepare_enable(ahb_clk); | ||||
| @ -249,8 +250,6 @@ disable_clks: | ||||
| disable_gdsc: | ||||
| 	regulator_disable(gdsc_reg); | ||||
| 	pm_runtime_put_sync(dev); | ||||
| put_clk: | ||||
| 	clk_put(ahb_clk); | ||||
| put_gdsc: | ||||
| 	regulator_put(gdsc_reg); | ||||
| exit: | ||||
| @ -379,6 +378,19 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && | ||||
| 	    cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_2_1) { | ||||
| 		msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); | ||||
| 		if (IS_ERR(msm_host->byte_intf_clk)) { | ||||
| 			ret = PTR_ERR(msm_host->byte_intf_clk); | ||||
| 			pr_err("%s: can't find byte_intf clock. ret=%d\n", | ||||
| 			        __func__, ret); | ||||
| 			goto exit; | ||||
| 		} | ||||
| 	} else { | ||||
| 		msm_host->byte_intf_clk = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); | ||||
| 	if (!msm_host->byte_clk_src) { | ||||
| 		ret = -ENODEV; | ||||
| @ -504,6 +516,16 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	if (msm_host->byte_intf_clk) { | ||||
| 		ret = clk_set_rate(msm_host->byte_intf_clk, | ||||
| 				   msm_host->byte_clk_rate / 2); | ||||
| 		if (ret) { | ||||
| 			pr_err("%s: Failed to set rate byte intf clk, %d\n", | ||||
| 			       __func__, ret); | ||||
| 			goto error; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ret = clk_prepare_enable(msm_host->esc_clk); | ||||
| 	if (ret) { | ||||
| 		pr_err("%s: Failed to enable dsi esc clk\n", __func__); | ||||
| @ -522,8 +544,19 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) | ||||
| 		goto pixel_clk_err; | ||||
| 	} | ||||
| 
 | ||||
| 	if (msm_host->byte_intf_clk) { | ||||
| 		ret = clk_prepare_enable(msm_host->byte_intf_clk); | ||||
| 		if (ret) { | ||||
| 			pr_err("%s: Failed to enable byte intf clk\n", | ||||
| 			       __func__); | ||||
| 			goto byte_intf_clk_err; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| byte_intf_clk_err: | ||||
| 	clk_disable_unprepare(msm_host->pixel_clk); | ||||
| pixel_clk_err: | ||||
| 	clk_disable_unprepare(msm_host->byte_clk); | ||||
| byte_clk_err: | ||||
| @ -617,6 +650,8 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) | ||||
| 	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { | ||||
| 		clk_disable_unprepare(msm_host->esc_clk); | ||||
| 		clk_disable_unprepare(msm_host->pixel_clk); | ||||
| 		if (msm_host->byte_intf_clk) | ||||
| 			clk_disable_unprepare(msm_host->byte_intf_clk); | ||||
| 		clk_disable_unprepare(msm_host->byte_clk); | ||||
| 	} else { | ||||
| 		clk_disable_unprepare(msm_host->pixel_clk); | ||||
| @ -1028,10 +1063,8 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) | ||||
| 
 | ||||
| 	if (msm_host->tx_gem_obj) { | ||||
| 		msm_gem_put_iova(msm_host->tx_gem_obj, 0); | ||||
| 		mutex_lock(&dev->struct_mutex); | ||||
| 		msm_gem_free_object(msm_host->tx_gem_obj); | ||||
| 		drm_gem_object_put_unlocked(msm_host->tx_gem_obj); | ||||
| 		msm_host->tx_gem_obj = NULL; | ||||
| 		mutex_unlock(&dev->struct_mutex); | ||||
| 	} | ||||
| 
 | ||||
| 	if (msm_host->tx_buf) | ||||
|  | ||||
| @ -88,6 +88,8 @@ static int dsi_mgr_setup_components(int id) | ||||
| 
 | ||||
| 		msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); | ||||
| 		src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); | ||||
| 		if (IS_ERR(src_pll)) | ||||
| 			return PTR_ERR(src_pll); | ||||
| 		ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); | ||||
| 	} else if (!other_dsi) { | ||||
| 		ret = 0; | ||||
| @ -116,6 +118,8 @@ static int dsi_mgr_setup_components(int id) | ||||
| 		msm_dsi_phy_set_usecase(clk_slave_dsi->phy, | ||||
| 					MSM_DSI_PHY_SLAVE); | ||||
| 		src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy); | ||||
| 		if (IS_ERR(src_pll)) | ||||
| 			return PTR_ERR(src_pll); | ||||
| 		ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| @ -858,7 +862,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) | ||||
| 	int id = msm_dsi->id; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (id > DSI_MAX) { | ||||
| 	if (id >= DSI_MAX) { | ||||
| 		pr_err("%s: invalid id %d\n", __func__, id); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| @ -394,6 +394,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { | ||||
| #ifdef CONFIG_DRM_MSM_DSI_14NM_PHY | ||||
| 	{ .compatible = "qcom,dsi-phy-14nm", | ||||
| 	  .data = &dsi_phy_14nm_cfgs }, | ||||
| #endif | ||||
| #ifdef CONFIG_DRM_MSM_DSI_10NM_PHY | ||||
| 	{ .compatible = "qcom,dsi-phy-10nm", | ||||
| 	  .data = &dsi_phy_10nm_cfgs }, | ||||
| #endif | ||||
| 	{} | ||||
| }; | ||||
| @ -503,10 +507,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id); | ||||
| 	if (!phy->pll) | ||||
| 	if (IS_ERR_OR_NULL(phy->pll)) | ||||
| 		dev_info(dev, | ||||
| 			"%s: pll init failed, need separate pll clk driver\n", | ||||
| 			__func__); | ||||
| 			"%s: pll init failed: %ld, need separate pll clk driver\n", | ||||
| 			__func__, PTR_ERR(phy->pll)); | ||||
| 
 | ||||
| 	dsi_phy_disable_resource(phy); | ||||
| 
 | ||||
|  | ||||
| @ -48,6 +48,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; | ||||
| extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; | ||||
| extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; | ||||
| extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; | ||||
| extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; | ||||
| 
 | ||||
| struct msm_dsi_dphy_timing { | ||||
| 	u32 clk_pre; | ||||
|  | ||||
							
								
								
									
										251
									
								
								drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,251 @@ | ||||
| /*
 | ||||
|  * SPDX-License-Identifier: GPL-2.0 | ||||
|  * Copyright (c) 2018, The Linux Foundation | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/iopoll.h> | ||||
| 
 | ||||
| #include "dsi_phy.h" | ||||
| #include "dsi.xml.h" | ||||
| 
 | ||||
| static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) | ||||
| { | ||||
| 	void __iomem *base = phy->base; | ||||
| 	u32 data = 0; | ||||
| 
 | ||||
| 	data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); | ||||
| 	mb(); /* make sure read happened */ | ||||
| 
 | ||||
| 	return (data & BIT(0)); | ||||
| } | ||||
| 
 | ||||
| static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable) | ||||
| { | ||||
| 	void __iomem *lane_base = phy->lane_base; | ||||
| 	int phy_lane_0 = 0;	/* TODO: Support all lane swap configs */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * LPRX and CDRX need to enabled only for physical data lane | ||||
| 	 * corresponding to the logical data lane 0 | ||||
| 	 */ | ||||
| 	if (enable) | ||||
| 		dsi_phy_write(lane_base + | ||||
| 			      REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3); | ||||
| 	else | ||||
| 		dsi_phy_write(lane_base + | ||||
| 			      REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0); | ||||
| } | ||||
| 
 | ||||
| static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) | ||||
| { | ||||
| 	int i; | ||||
| 	u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; | ||||
| 	void __iomem *lane_base = phy->lane_base; | ||||
| 
 | ||||
| 	/* Strength ctrl settings */ | ||||
| 	for (i = 0; i < 5; i++) { | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), | ||||
| 			      0x55); | ||||
| 		/*
 | ||||
| 		 * Disable LPRX and CDRX for all lanes. And later on, it will | ||||
| 		 * be only enabled for the physical data lane corresponding | ||||
| 		 * to the logical data lane 0 | ||||
| 		 */ | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i), | ||||
| 			      0x88); | ||||
| 	} | ||||
| 
 | ||||
| 	dsi_phy_hw_v3_0_config_lpcdrx(phy, true); | ||||
| 
 | ||||
| 	/* other settings */ | ||||
| 	for (i = 0; i < 5; i++) { | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i), | ||||
| 			      i == 4 ? 0x80 : 0x0); | ||||
| 		dsi_phy_write(lane_base + | ||||
| 			      REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + | ||||
| 			      REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0); | ||||
| 		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i), | ||||
| 			      tx_dctrl[i]); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Toggle BIT 0 to release freeze I/0 */ | ||||
| 	dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); | ||||
| 	dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); | ||||
| } | ||||
| 
 | ||||
| static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, | ||||
| 				       struct msm_dsi_phy_clk_request *clk_req) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * TODO: These params need to be computed, they're currently hardcoded | ||||
| 	 * for a 1440x2560@60Hz panel with a byteclk of 100.618 Mhz, and a | ||||
| 	 * default escape clock of 19.2 Mhz. | ||||
| 	 */ | ||||
| 
 | ||||
| 	timing->hs_halfbyte_en = 0; | ||||
| 	timing->clk_zero = 0x1c; | ||||
| 	timing->clk_prepare = 0x07; | ||||
| 	timing->clk_trail = 0x07; | ||||
| 	timing->hs_exit = 0x23; | ||||
| 	timing->hs_zero = 0x21; | ||||
| 	timing->hs_prepare = 0x07; | ||||
| 	timing->hs_trail = 0x07; | ||||
| 	timing->hs_rqst = 0x05; | ||||
| 	timing->ta_sure = 0x00; | ||||
| 	timing->ta_go = 0x03; | ||||
| 	timing->ta_get = 0x04; | ||||
| 
 | ||||
| 	timing->shared_timings.clk_pre = 0x2d; | ||||
| 	timing->shared_timings.clk_post = 0x0d; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, | ||||
| 			       struct msm_dsi_phy_clk_request *clk_req) | ||||
| { | ||||
| 	int ret; | ||||
| 	u32 status; | ||||
| 	u32 const delay_us = 5; | ||||
| 	u32 const timeout_us = 1000; | ||||
| 	struct msm_dsi_dphy_timing *timing = &phy->timing; | ||||
| 	void __iomem *base = phy->base; | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	DBG(""); | ||||
| 
 | ||||
| 	if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) { | ||||
| 		dev_err(&phy->pdev->dev, | ||||
| 			"%s: D-PHY timing calculation failed\n", __func__); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (dsi_phy_hw_v3_0_is_pll_on(phy)) | ||||
| 		pr_warn("PLL turned on before configuring PHY\n"); | ||||
| 
 | ||||
| 	/* wait for REFGEN READY */ | ||||
| 	ret = readl_poll_timeout_atomic(base + REG_DSI_10nm_PHY_CMN_PHY_STATUS, | ||||
| 					status, (status & BIT(0)), | ||||
| 					delay_us, timeout_us); | ||||
| 	if (ret) { | ||||
| 		pr_err("Ref gen not ready. Aborting\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* de-assert digital and pll power down */ | ||||
| 	data = BIT(6) | BIT(5); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); | ||||
| 
 | ||||
| 	/* Assert PLL core reset */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00); | ||||
| 
 | ||||
| 	/* turn off resync FIFO */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00); | ||||
| 
 | ||||
| 	/* Select MS1 byte-clk */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10); | ||||
| 
 | ||||
| 	/* Enable LDO */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59); | ||||
| 
 | ||||
| 	/* Configure PHY lane swap (TODO: we need to calculate this) */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84); | ||||
| 
 | ||||
| 	/* DSI PHY timings */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0, | ||||
| 		      timing->hs_halfbyte_en); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1, | ||||
| 		      timing->clk_zero); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2, | ||||
| 		      timing->clk_prepare); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3, | ||||
| 		      timing->clk_trail); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4, | ||||
| 		      timing->hs_exit); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5, | ||||
| 		      timing->hs_zero); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6, | ||||
| 		      timing->hs_prepare); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7, | ||||
| 		      timing->hs_trail); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8, | ||||
| 		      timing->hs_rqst); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9, | ||||
| 		      timing->ta_go | (timing->ta_sure << 3)); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10, | ||||
| 		      timing->ta_get); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11, | ||||
| 		      0x00); | ||||
| 
 | ||||
| 	/* Remove power down from all blocks */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f); | ||||
| 
 | ||||
| 	/* power up lanes */ | ||||
| 	data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); | ||||
| 
 | ||||
| 	/* TODO: only power up lanes that are used */ | ||||
| 	data |= 0x1F; | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F); | ||||
| 
 | ||||
| 	/* Select full-rate mode */ | ||||
| 	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40); | ||||
| 
 | ||||
| 	ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase); | ||||
| 	if (ret) { | ||||
| 		dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n", | ||||
| 			__func__, ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* DSI lane settings */ | ||||
| 	dsi_phy_hw_v3_0_lane_settings(phy); | ||||
| 
 | ||||
| 	DBG("DSI%d PHY enabled", phy->id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static int dsi_10nm_phy_init(struct msm_dsi_phy *phy) | ||||
| { | ||||
| 	struct platform_device *pdev = phy->pdev; | ||||
| 
 | ||||
| 	phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane", | ||||
| 				     "DSI_PHY_LANE"); | ||||
| 	if (IS_ERR(phy->lane_base)) { | ||||
| 		dev_err(&pdev->dev, "%s: failed to map phy lane base\n", | ||||
| 			__func__); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { | ||||
| 	.type = MSM_DSI_PHY_10NM, | ||||
| 	.src_pll_truthtable = { {false, false}, {true, false} }, | ||||
| 	.reg_cfg = { | ||||
| 		.num = 1, | ||||
| 		.regs = { | ||||
| 			{"vdds", 36000, 32}, | ||||
| 		}, | ||||
| 	}, | ||||
| 	.ops = { | ||||
| 		.enable = dsi_10nm_phy_enable, | ||||
| 		.disable = dsi_10nm_phy_disable, | ||||
| 		.init = dsi_10nm_phy_init, | ||||
| 	}, | ||||
| 	.io_start = { 0xae94400, 0xae96400 }, | ||||
| 	.num_dsi_phy = 2, | ||||
| }; | ||||
| @ -166,6 +166,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, | ||||
| 	case MSM_DSI_PHY_14NM: | ||||
| 		pll = msm_dsi_pll_14nm_init(pdev, id); | ||||
| 		break; | ||||
| 	case MSM_DSI_PHY_10NM: | ||||
| 		pll = msm_dsi_pll_10nm_init(pdev, id); | ||||
| 		break; | ||||
| 	default: | ||||
| 		pll = ERR_PTR(-ENXIO); | ||||
| 		break; | ||||
| @ -173,7 +176,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, | ||||
| 
 | ||||
| 	if (IS_ERR(pll)) { | ||||
| 		dev_err(dev, "%s: failed to init DSI PLL\n", __func__); | ||||
| 		return NULL; | ||||
| 		return pll; | ||||
| 	} | ||||
| 
 | ||||
| 	pll->type = type; | ||||
|  | ||||
| @ -115,5 +115,14 @@ msm_dsi_pll_14nm_init(struct platform_device *pdev, int id) | ||||
| 	return ERR_PTR(-ENODEV); | ||||
| } | ||||
| #endif | ||||
| #ifdef CONFIG_DRM_MSM_DSI_10NM_PHY | ||||
| struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id); | ||||
| #else | ||||
| static inline struct msm_dsi_pll * | ||||
| msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) | ||||
| { | ||||
| 	return ERR_PTR(-ENODEV); | ||||
| } | ||||
| #endif | ||||
| #endif /* __DSI_PLL_H__ */ | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										822
									
								
								drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										822
									
								
								drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,822 @@ | ||||
| /*
 | ||||
|  * SPDX-License-Identifier: GPL-2.0 | ||||
|  * Copyright (c) 2018, The Linux Foundation | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/clk.h> | ||||
| #include <linux/clk-provider.h> | ||||
| #include <linux/iopoll.h> | ||||
| 
 | ||||
| #include "dsi_pll.h" | ||||
| #include "dsi.xml.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * DSI PLL 10nm - clock diagram (eg: DSI0): | ||||
|  * | ||||
|  *           dsi0_pll_out_div_clk  dsi0_pll_bit_clk | ||||
|  *                              |                | | ||||
|  *                              |                | | ||||
|  *                 +---------+  |  +----------+  |  +----+ | ||||
|  *  dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0pllbyte | ||||
|  *                 +---------+  |  +----------+  |  +----+ | ||||
|  *                              |                | | ||||
|  *                              |                |         dsi0_pll_by_2_bit_clk | ||||
|  *                              |                |          | | ||||
|  *                              |                |  +----+  |  |\  dsi0_pclk_mux | ||||
|  *                              |                |--| /2 |--o--| \   | | ||||
|  *                              |                |  +----+     |  \  |  +---------+ | ||||
|  *                              |                --------------|  |--o--| div_7_4 |-- dsi0pll | ||||
|  *                              |------------------------------|  /     +---------+ | ||||
|  *                              |          +-----+             | / | ||||
|  *                              -----------| /4? |--o----------|/ | ||||
|  *                                         +-----+  |           | | ||||
|  *                                                  |           |dsiclk_sel | ||||
|  *                                                  | | ||||
|  *                                                  dsi0_pll_post_out_div_clk | ||||
|  */ | ||||
| 
 | ||||
| #define DSI_BYTE_PLL_CLK		0 | ||||
| #define DSI_PIXEL_PLL_CLK		1 | ||||
| #define NUM_PROVIDED_CLKS		2 | ||||
| 
 | ||||
| struct dsi_pll_regs { | ||||
| 	u32 pll_prop_gain_rate; | ||||
| 	u32 pll_lockdet_rate; | ||||
| 	u32 decimal_div_start; | ||||
| 	u32 frac_div_start_low; | ||||
| 	u32 frac_div_start_mid; | ||||
| 	u32 frac_div_start_high; | ||||
| 	u32 pll_clock_inverters; | ||||
| 	u32 ssc_stepsize_low; | ||||
| 	u32 ssc_stepsize_high; | ||||
| 	u32 ssc_div_per_low; | ||||
| 	u32 ssc_div_per_high; | ||||
| 	u32 ssc_adjper_low; | ||||
| 	u32 ssc_adjper_high; | ||||
| 	u32 ssc_control; | ||||
| }; | ||||
| 
 | ||||
| struct dsi_pll_config { | ||||
| 	u32 ref_freq; | ||||
| 	bool div_override; | ||||
| 	u32 output_div; | ||||
| 	bool ignore_frac; | ||||
| 	bool disable_prescaler; | ||||
| 	bool enable_ssc; | ||||
| 	bool ssc_center; | ||||
| 	u32 dec_bits; | ||||
| 	u32 frac_bits; | ||||
| 	u32 lock_timer; | ||||
| 	u32 ssc_freq; | ||||
| 	u32 ssc_offset; | ||||
| 	u32 ssc_adj_per; | ||||
| 	u32 thresh_cycles; | ||||
| 	u32 refclk_cycles; | ||||
| }; | ||||
| 
 | ||||
| struct pll_10nm_cached_state { | ||||
| 	unsigned long vco_rate; | ||||
| 	u8 bit_clk_div; | ||||
| 	u8 pix_clk_div; | ||||
| 	u8 pll_out_div; | ||||
| 	u8 pll_mux; | ||||
| }; | ||||
| 
 | ||||
| struct dsi_pll_10nm { | ||||
| 	struct msm_dsi_pll base; | ||||
| 
 | ||||
| 	int id; | ||||
| 	struct platform_device *pdev; | ||||
| 
 | ||||
| 	void __iomem *phy_cmn_mmio; | ||||
| 	void __iomem *mmio; | ||||
| 
 | ||||
| 	u64 vco_ref_clk_rate; | ||||
| 	u64 vco_current_rate; | ||||
| 
 | ||||
| 	/* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ | ||||
| 	spinlock_t postdiv_lock; | ||||
| 
 | ||||
| 	int vco_delay; | ||||
| 	struct dsi_pll_config pll_configuration; | ||||
| 	struct dsi_pll_regs reg_setup; | ||||
| 
 | ||||
| 	/* private clocks: */ | ||||
| 	struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; | ||||
| 	u32 num_hws; | ||||
| 
 | ||||
| 	/* clock-provider: */ | ||||
| 	struct clk_hw_onecell_data *hw_data; | ||||
| 
 | ||||
| 	struct pll_10nm_cached_state cached_state; | ||||
| 
 | ||||
| 	enum msm_dsi_phy_usecase uc; | ||||
| 	struct dsi_pll_10nm *slave; | ||||
| }; | ||||
| 
 | ||||
| #define to_pll_10nm(x)	container_of(x, struct dsi_pll_10nm, base) | ||||
| 
 | ||||
| /*
 | ||||
|  * Global list of private DSI PLL struct pointers. We need this for Dual DSI | ||||
|  * mode, where the master PLL's clk_ops needs access the slave's private data | ||||
|  */ | ||||
| static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; | ||||
| 
 | ||||
| static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	struct dsi_pll_config *config = &pll->pll_configuration; | ||||
| 
 | ||||
| 	config->ref_freq = pll->vco_ref_clk_rate; | ||||
| 	config->output_div = 1; | ||||
| 	config->dec_bits = 8; | ||||
| 	config->frac_bits = 18; | ||||
| 	config->lock_timer = 64; | ||||
| 	config->ssc_freq = 31500; | ||||
| 	config->ssc_offset = 5000; | ||||
| 	config->ssc_adj_per = 2; | ||||
| 	config->thresh_cycles = 32; | ||||
| 	config->refclk_cycles = 256; | ||||
| 
 | ||||
| 	config->div_override = false; | ||||
| 	config->ignore_frac = false; | ||||
| 	config->disable_prescaler = false; | ||||
| 
 | ||||
| 	config->enable_ssc = false; | ||||
| 	config->ssc_center = 0; | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	struct dsi_pll_config *config = &pll->pll_configuration; | ||||
| 	struct dsi_pll_regs *regs = &pll->reg_setup; | ||||
| 	u64 fref = pll->vco_ref_clk_rate; | ||||
| 	u64 pll_freq; | ||||
| 	u64 divider; | ||||
| 	u64 dec, dec_multiple; | ||||
| 	u32 frac; | ||||
| 	u64 multiplier; | ||||
| 
 | ||||
| 	pll_freq = pll->vco_current_rate; | ||||
| 
 | ||||
| 	if (config->disable_prescaler) | ||||
| 		divider = fref; | ||||
| 	else | ||||
| 		divider = fref * 2; | ||||
| 
 | ||||
| 	multiplier = 1 << config->frac_bits; | ||||
| 	dec_multiple = div_u64(pll_freq * multiplier, divider); | ||||
| 	div_u64_rem(dec_multiple, multiplier, &frac); | ||||
| 
 | ||||
| 	dec = div_u64(dec_multiple, multiplier); | ||||
| 
 | ||||
| 	if (pll_freq <= 1900000000UL) | ||||
| 		regs->pll_prop_gain_rate = 8; | ||||
| 	else if (pll_freq <= 3000000000UL) | ||||
| 		regs->pll_prop_gain_rate = 10; | ||||
| 	else | ||||
| 		regs->pll_prop_gain_rate = 12; | ||||
| 	if (pll_freq < 1100000000UL) | ||||
| 		regs->pll_clock_inverters = 8; | ||||
| 	else | ||||
| 		regs->pll_clock_inverters = 0; | ||||
| 
 | ||||
| 	regs->pll_lockdet_rate = config->lock_timer; | ||||
| 	regs->decimal_div_start = dec; | ||||
| 	regs->frac_div_start_low = (frac & 0xff); | ||||
| 	regs->frac_div_start_mid = (frac & 0xff00) >> 8; | ||||
| 	regs->frac_div_start_high = (frac & 0x30000) >> 16; | ||||
| } | ||||
| 
 | ||||
| #define SSC_CENTER		BIT(0) | ||||
| #define SSC_EN			BIT(1) | ||||
| 
 | ||||
| static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	struct dsi_pll_config *config = &pll->pll_configuration; | ||||
| 	struct dsi_pll_regs *regs = &pll->reg_setup; | ||||
| 	u32 ssc_per; | ||||
| 	u32 ssc_mod; | ||||
| 	u64 ssc_step_size; | ||||
| 	u64 frac; | ||||
| 
 | ||||
| 	if (!config->enable_ssc) { | ||||
| 		DBG("SSC not enabled\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; | ||||
| 	ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); | ||||
| 	ssc_per -= ssc_mod; | ||||
| 
 | ||||
| 	frac = regs->frac_div_start_low | | ||||
| 			(regs->frac_div_start_mid << 8) | | ||||
| 			(regs->frac_div_start_high << 16); | ||||
| 	ssc_step_size = regs->decimal_div_start; | ||||
| 	ssc_step_size *= (1 << config->frac_bits); | ||||
| 	ssc_step_size += frac; | ||||
| 	ssc_step_size *= config->ssc_offset; | ||||
| 	ssc_step_size *= (config->ssc_adj_per + 1); | ||||
| 	ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); | ||||
| 	ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); | ||||
| 
 | ||||
| 	regs->ssc_div_per_low = ssc_per & 0xFF; | ||||
| 	regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; | ||||
| 	regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); | ||||
| 	regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); | ||||
| 	regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; | ||||
| 	regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; | ||||
| 
 | ||||
| 	regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; | ||||
| 
 | ||||
| 	pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", | ||||
| 		 regs->decimal_div_start, frac, config->frac_bits); | ||||
| 	pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", | ||||
| 		 ssc_per, (u32)ssc_step_size, config->ssc_adj_per); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	void __iomem *base = pll->mmio; | ||||
| 	struct dsi_pll_regs *regs = &pll->reg_setup; | ||||
| 
 | ||||
| 	if (pll->pll_configuration.enable_ssc) { | ||||
| 		pr_debug("SSC is enabled\n"); | ||||
| 
 | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, | ||||
| 			  regs->ssc_stepsize_low); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, | ||||
| 			  regs->ssc_stepsize_high); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, | ||||
| 			  regs->ssc_div_per_low); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, | ||||
| 			  regs->ssc_div_per_high); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, | ||||
| 			  regs->ssc_adjper_low); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, | ||||
| 			  regs->ssc_adjper_high); | ||||
| 		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, | ||||
| 			  SSC_EN | regs->ssc_control); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	void __iomem *base = pll->mmio; | ||||
| 
 | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, | ||||
| 		  0xba); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, | ||||
| 		  0x4c); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_commit(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	void __iomem *base = pll->mmio; | ||||
| 	struct dsi_pll_regs *reg = &pll->reg_setup; | ||||
| 
 | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, | ||||
| 		  reg->decimal_div_start); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, | ||||
| 		  reg->frac_div_start_low); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, | ||||
| 		  reg->frac_div_start_mid); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, | ||||
| 		  reg->frac_div_start_high); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, | ||||
| 		  reg->pll_clock_inverters); | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, | ||||
| 				     unsigned long parent_rate) | ||||
| { | ||||
| 	struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 
 | ||||
| 	DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, | ||||
| 	    parent_rate); | ||||
| 
 | ||||
| 	pll_10nm->vco_current_rate = rate; | ||||
| 	pll_10nm->vco_ref_clk_rate = parent_rate; | ||||
| 
 | ||||
| 	dsi_pll_setup_config(pll_10nm); | ||||
| 
 | ||||
| 	dsi_pll_calc_dec_frac(pll_10nm); | ||||
| 
 | ||||
| 	dsi_pll_calc_ssc(pll_10nm); | ||||
| 
 | ||||
| 	dsi_pll_commit(pll_10nm); | ||||
| 
 | ||||
| 	dsi_pll_config_hzindep_reg(pll_10nm); | ||||
| 
 | ||||
| 	dsi_pll_ssc_commit(pll_10nm); | ||||
| 
 | ||||
| 	/* flush, ensure all register writes are done*/ | ||||
| 	wmb(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	int rc; | ||||
| 	u32 status = 0; | ||||
| 	u32 const delay_us = 100; | ||||
| 	u32 const timeout_us = 5000; | ||||
| 
 | ||||
| 	rc = readl_poll_timeout_atomic(pll->mmio + | ||||
| 				       REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, | ||||
| 				       status, | ||||
| 				       ((status & BIT(0)) > 0), | ||||
| 				       delay_us, | ||||
| 				       timeout_us); | ||||
| 	if (rc) | ||||
| 		pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", | ||||
| 		       pll->id, status); | ||||
| 
 | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); | ||||
| 
 | ||||
| 	pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); | ||||
| 	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, | ||||
| 		  data & ~BIT(5)); | ||||
| 	ndelay(250); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); | ||||
| 
 | ||||
| 	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, | ||||
| 		  data | BIT(5)); | ||||
| 	pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); | ||||
| 	ndelay(250); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | ||||
| 	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, | ||||
| 		  data & ~BIT(5)); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | ||||
| 	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, | ||||
| 		  data | BIT(5)); | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) | ||||
| { | ||||
| 	struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	int rc; | ||||
| 
 | ||||
| 	dsi_pll_enable_pll_bias(pll_10nm); | ||||
| 	if (pll_10nm->slave) | ||||
| 		dsi_pll_enable_pll_bias(pll_10nm->slave); | ||||
| 
 | ||||
| 	/* Start PLL */ | ||||
| 	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, | ||||
| 		  0x01); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * ensure all PLL configurations are written prior to checking | ||||
| 	 * for PLL lock. | ||||
| 	 */ | ||||
| 	wmb(); | ||||
| 
 | ||||
| 	/* Check for PLL lock */ | ||||
| 	rc = dsi_pll_10nm_lock_status(pll_10nm); | ||||
| 	if (rc) { | ||||
| 		pr_err("PLL(%d) lock failed\n", pll_10nm->id); | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	pll->pll_on = true; | ||||
| 
 | ||||
| 	dsi_pll_enable_global_clk(pll_10nm); | ||||
| 	if (pll_10nm->slave) | ||||
| 		dsi_pll_enable_global_clk(pll_10nm->slave); | ||||
| 
 | ||||
| 	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, | ||||
| 		  0x01); | ||||
| 	if (pll_10nm->slave) | ||||
| 		pll_write(pll_10nm->slave->phy_cmn_mmio + | ||||
| 			  REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); | ||||
| 
 | ||||
| error: | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) | ||||
| { | ||||
| 	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); | ||||
| 	dsi_pll_disable_pll_bias(pll); | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) | ||||
| { | ||||
| 	struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * To avoid any stray glitches while abruptly powering down the PLL | ||||
| 	 * make sure to gate the clock using the clock enable bit before | ||||
| 	 * powering down the PLL | ||||
| 	 */ | ||||
| 	dsi_pll_disable_global_clk(pll_10nm); | ||||
| 	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0); | ||||
| 	dsi_pll_disable_sub(pll_10nm); | ||||
| 	if (pll_10nm->slave) { | ||||
| 		dsi_pll_disable_global_clk(pll_10nm->slave); | ||||
| 		dsi_pll_disable_sub(pll_10nm->slave); | ||||
| 	} | ||||
| 	/* flush, ensure all register writes are done */ | ||||
| 	wmb(); | ||||
| 	pll->pll_on = false; | ||||
| } | ||||
| 
 | ||||
| static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, | ||||
| 						  unsigned long parent_rate) | ||||
| { | ||||
| 	struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	void __iomem *base = pll_10nm->mmio; | ||||
| 	u64 ref_clk = pll_10nm->vco_ref_clk_rate; | ||||
| 	u64 vco_rate = 0x0; | ||||
| 	u64 multiplier; | ||||
| 	u32 frac; | ||||
| 	u32 dec; | ||||
| 	u64 pll_freq, tmp64; | ||||
| 
 | ||||
| 	dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); | ||||
| 	dec &= 0xff; | ||||
| 
 | ||||
| 	frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); | ||||
| 	frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & | ||||
| 		  0xff) << 8); | ||||
| 	frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & | ||||
| 		  0x3) << 16); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * TODO: | ||||
| 	 *	1. Assumes prescaler is disabled | ||||
| 	 *	2. Multiplier is 2^18. it should be 2^(num_of_frac_bits) | ||||
| 	 */ | ||||
| 	multiplier = 1 << 18; | ||||
| 	pll_freq = dec * (ref_clk * 2); | ||||
| 	tmp64 = (ref_clk * 2 * frac); | ||||
| 	pll_freq += div_u64(tmp64, multiplier); | ||||
| 
 | ||||
| 	vco_rate = pll_freq; | ||||
| 
 | ||||
| 	DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", | ||||
| 	    pll_10nm->id, (unsigned long)vco_rate, dec, frac); | ||||
| 
 | ||||
| 	return (unsigned long)vco_rate; | ||||
| } | ||||
| 
 | ||||
| static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { | ||||
| 	.round_rate = msm_dsi_pll_helper_clk_round_rate, | ||||
| 	.set_rate = dsi_pll_10nm_vco_set_rate, | ||||
| 	.recalc_rate = dsi_pll_10nm_vco_recalc_rate, | ||||
| 	.prepare = dsi_pll_10nm_vco_prepare, | ||||
| 	.unprepare = dsi_pll_10nm_vco_unprepare, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * PLL Callbacks | ||||
|  */ | ||||
| 
 | ||||
| static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; | ||||
| 	void __iomem *phy_base = pll_10nm->phy_cmn_mmio; | ||||
| 	u32 cmn_clk_cfg0, cmn_clk_cfg1; | ||||
| 
 | ||||
| 	cached->pll_out_div = pll_read(pll_10nm->mmio + | ||||
| 				       REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); | ||||
| 	cached->pll_out_div &= 0x3; | ||||
| 
 | ||||
| 	cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); | ||||
| 	cached->bit_clk_div = cmn_clk_cfg0 & 0xf; | ||||
| 	cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; | ||||
| 
 | ||||
| 	cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | ||||
| 	cached->pll_mux = cmn_clk_cfg1 & 0x3; | ||||
| 
 | ||||
| 	DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", | ||||
| 	    pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, | ||||
| 	    cached->pix_clk_div, cached->pll_mux); | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; | ||||
| 	void __iomem *phy_base = pll_10nm->phy_cmn_mmio; | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); | ||||
| 	val &= ~0x3; | ||||
| 	val |= cached->pll_out_div; | ||||
| 	pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); | ||||
| 
 | ||||
| 	pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, | ||||
| 		  cached->bit_clk_div | (cached->pix_clk_div << 4)); | ||||
| 
 | ||||
| 	val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | ||||
| 	val &= ~0x3; | ||||
| 	val |= cached->pll_mux; | ||||
| 	pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); | ||||
| 
 | ||||
| 	DBG("DSI PLL%d", pll_10nm->id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, | ||||
| 				    enum msm_dsi_phy_usecase uc) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	void __iomem *base = pll_10nm->phy_cmn_mmio; | ||||
| 	u32 data = 0x0;	/* internal PLL */ | ||||
| 
 | ||||
| 	DBG("DSI PLL%d", pll_10nm->id); | ||||
| 
 | ||||
| 	switch (uc) { | ||||
| 	case MSM_DSI_PHY_STANDALONE: | ||||
| 		break; | ||||
| 	case MSM_DSI_PHY_MASTER: | ||||
| 		pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; | ||||
| 		break; | ||||
| 	case MSM_DSI_PHY_SLAVE: | ||||
| 		data = 0x1; /* external PLL */ | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* set PLL src */ | ||||
| 	pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); | ||||
| 
 | ||||
| 	pll_10nm->uc = uc; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, | ||||
| 				     struct clk **byte_clk_provider, | ||||
| 				     struct clk **pixel_clk_provider) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 	struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; | ||||
| 
 | ||||
| 	DBG("DSI PLL%d", pll_10nm->id); | ||||
| 
 | ||||
| 	if (byte_clk_provider) | ||||
| 		*byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; | ||||
| 	if (pixel_clk_provider) | ||||
| 		*pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | ||||
| 
 | ||||
| 	DBG("DSI PLL%d", pll_10nm->id); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The post dividers and mux clocks are created using the standard divider and | ||||
|  * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux | ||||
|  * state to follow the master PLL's divider/mux state. Therefore, we don't | ||||
|  * require special clock ops that also configure the slave PLL registers | ||||
|  */ | ||||
| static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) | ||||
| { | ||||
| 	char clk_name[32], parent[32], vco_name[32]; | ||||
| 	char parent2[32], parent3[32], parent4[32]; | ||||
| 	struct clk_init_data vco_init = { | ||||
| 		.parent_names = (const char *[]){ "xo" }, | ||||
| 		.num_parents = 1, | ||||
| 		.name = vco_name, | ||||
| 		.flags = CLK_IGNORE_UNUSED, | ||||
| 		.ops = &clk_ops_dsi_pll_10nm_vco, | ||||
| 	}; | ||||
| 	struct device *dev = &pll_10nm->pdev->dev; | ||||
| 	struct clk_hw **hws = pll_10nm->hws; | ||||
| 	struct clk_hw_onecell_data *hw_data; | ||||
| 	struct clk_hw *hw; | ||||
| 	int num = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	DBG("DSI%d", pll_10nm->id); | ||||
| 
 | ||||
| 	hw_data = devm_kzalloc(dev, sizeof(*hw_data) + | ||||
| 			       NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), | ||||
| 			       GFP_KERNEL); | ||||
| 	if (!hw_data) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); | ||||
| 	pll_10nm->base.clk_hw.init = &vco_init; | ||||
| 
 | ||||
| 	ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	hws[num++] = &pll_10nm->base.clk_hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	hw = clk_hw_register_divider(dev, clk_name, | ||||
| 				     parent, CLK_SET_RATE_PARENT, | ||||
| 				     pll_10nm->mmio + | ||||
| 				     REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, | ||||
| 				     0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	/* BIT CLK: DIV_CTRL_3_0 */ | ||||
| 	hw = clk_hw_register_divider(dev, clk_name, parent, | ||||
| 				     CLK_SET_RATE_PARENT, | ||||
| 				     pll_10nm->phy_cmn_mmio + | ||||
| 				     REG_DSI_10nm_PHY_CMN_CLK_CFG0, | ||||
| 				     0, 4, CLK_DIVIDER_ONE_BASED, | ||||
| 				     &pll_10nm->postdiv_lock); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%dpllbyte", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	/* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ | ||||
| 	hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | ||||
| 					  CLK_SET_RATE_PARENT, 1, 8); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 	hw_data->hws[DSI_BYTE_PLL_CLK] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | ||||
| 					  0, 1, 2); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | ||||
| 					  0, 1, 4); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | ||||
| 	snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); | ||||
| 	snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | ||||
| 	snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); | ||||
| 
 | ||||
| 	hw = clk_hw_register_mux(dev, clk_name, | ||||
| 				 (const char *[]){ | ||||
| 				 parent, parent2, parent3, parent4 | ||||
| 				 }, 4, 0, pll_10nm->phy_cmn_mmio + | ||||
| 				 REG_DSI_10nm_PHY_CMN_CLK_CFG1, | ||||
| 				 0, 2, 0, NULL); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 
 | ||||
| 	snprintf(clk_name, 32, "dsi%dpll", pll_10nm->id); | ||||
| 	snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); | ||||
| 
 | ||||
| 	/* PIX CLK DIV : DIV_CTRL_7_4*/ | ||||
| 	hw = clk_hw_register_divider(dev, clk_name, parent, | ||||
| 				     0, pll_10nm->phy_cmn_mmio + | ||||
| 					REG_DSI_10nm_PHY_CMN_CLK_CFG0, | ||||
| 				     4, 4, CLK_DIVIDER_ONE_BASED, | ||||
| 				     &pll_10nm->postdiv_lock); | ||||
| 	if (IS_ERR(hw)) | ||||
| 		return PTR_ERR(hw); | ||||
| 
 | ||||
| 	hws[num++] = hw; | ||||
| 	hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; | ||||
| 
 | ||||
| 	pll_10nm->num_hws = num; | ||||
| 
 | ||||
| 	hw_data->num = NUM_PROVIDED_CLKS; | ||||
| 	pll_10nm->hw_data = hw_data; | ||||
| 
 | ||||
| 	ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||||
| 				     pll_10nm->hw_data); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "failed to register clk provider: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) | ||||
| { | ||||
| 	struct dsi_pll_10nm *pll_10nm; | ||||
| 	struct msm_dsi_pll *pll; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!pdev) | ||||
| 		return ERR_PTR(-ENODEV); | ||||
| 
 | ||||
| 	pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); | ||||
| 	if (!pll_10nm) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 
 | ||||
| 	DBG("DSI PLL%d", id); | ||||
| 
 | ||||
| 	pll_10nm->pdev = pdev; | ||||
| 	pll_10nm->id = id; | ||||
| 	pll_10nm_list[id] = pll_10nm; | ||||
| 
 | ||||
| 	pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); | ||||
| 	if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { | ||||
| 		dev_err(&pdev->dev, "failed to map CMN PHY base\n"); | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 	} | ||||
| 
 | ||||
| 	pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); | ||||
| 	if (IS_ERR_OR_NULL(pll_10nm->mmio)) { | ||||
| 		dev_err(&pdev->dev, "failed to map PLL base\n"); | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 	} | ||||
| 
 | ||||
| 	pll = &pll_10nm->base; | ||||
| 	pll->min_rate = 1000000000UL; | ||||
| 	pll->max_rate = 3500000000UL; | ||||
| 	pll->get_provider = dsi_pll_10nm_get_provider; | ||||
| 	pll->destroy = dsi_pll_10nm_destroy; | ||||
| 	pll->save_state = dsi_pll_10nm_save_state; | ||||
| 	pll->restore_state = dsi_pll_10nm_restore_state; | ||||
| 	pll->set_usecase = dsi_pll_10nm_set_usecase; | ||||
| 
 | ||||
| 	pll_10nm->vco_delay = 1; | ||||
| 
 | ||||
| 	ret = pll_10nm_register(pll_10nm); | ||||
| 	if (ret) { | ||||
| 		dev_err(&pdev->dev, "failed to register PLL: %d\n", ret); | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
| 
 | ||||
| 	/* TODO: Remove this when we have proper display handover support */ | ||||
| 	msm_dsi_pll_save_state(pll); | ||||
| 
 | ||||
| 	return pll; | ||||
| } | ||||
| @ -769,7 +769,7 @@ static int msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctr | ||||
| 	if (rc) { | ||||
| 		pr_err("%s: wait key and an ready failed\n", __func__); | ||||
| 		return rc; | ||||
| 	}; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Read BCAPS and send to HDCP engine */ | ||||
| 	rc = msm_hdmi_hdcp_recv_bcaps(hdcp_ctrl); | ||||
|  | ||||
| @ -161,8 +161,11 @@ int msm_debugfs_init(struct drm_minor *minor) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (priv->kms->funcs->debugfs_init) | ||||
| 	if (priv->kms->funcs->debugfs_init) { | ||||
| 		ret = priv->kms->funcs->debugfs_init(priv->kms, minor); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -660,7 +660,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, | ||||
| 
 | ||||
| 	ret = msm_gem_cpu_prep(obj, args->op, &timeout); | ||||
| 
 | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -678,7 +678,7 @@ static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, | ||||
| 
 | ||||
| 	ret = msm_gem_cpu_fini(obj); | ||||
| 
 | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -718,7 +718,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, | ||||
| 		args->offset = msm_gem_mmap_offset(obj); | ||||
| 	} | ||||
| 
 | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -783,7 +783,7 @@ static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, | ||||
| 		ret = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	drm_gem_object_unreference(obj); | ||||
| 	drm_gem_object_put(obj); | ||||
| 
 | ||||
| unlock: | ||||
| 	mutex_unlock(&dev->struct_mutex); | ||||
|  | ||||
| @ -51,7 +51,6 @@ struct msm_rd_state; | ||||
| struct msm_perf_state; | ||||
| struct msm_gem_submit; | ||||
| struct msm_fence_context; | ||||
| struct msm_fence_cb; | ||||
| struct msm_gem_address_space; | ||||
| struct msm_gem_vma; | ||||
| 
 | ||||
|  | ||||
| @ -53,7 +53,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) | ||||
| 	for (i = 0; i < n; i++) { | ||||
| 		struct drm_gem_object *bo = msm_fb->planes[i]; | ||||
| 
 | ||||
| 		drm_gem_object_unreference_unlocked(bo); | ||||
| 		drm_gem_object_put_unlocked(bo); | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(msm_fb); | ||||
| @ -160,7 +160,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, | ||||
| 
 | ||||
| out_unref: | ||||
| 	for (i = 0; i < n; i++) | ||||
| 		drm_gem_object_unreference_unlocked(bos[i]); | ||||
| 		drm_gem_object_put_unlocked(bos[i]); | ||||
| 	return ERR_PTR(ret); | ||||
| } | ||||
| 
 | ||||
| @ -274,7 +274,7 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format | ||||
| 		/* note: if fb creation failed, we can't rely on fb destroy
 | ||||
| 		 * to unref the bo: | ||||
| 		 */ | ||||
| 		drm_gem_object_unreference_unlocked(bo); | ||||
| 		drm_gem_object_put_unlocked(bo); | ||||
| 		return ERR_CAST(fb); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -37,8 +37,6 @@ void msm_fence_context_free(struct msm_fence_context *fctx); | ||||
| 
 | ||||
| int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, | ||||
| 		ktime_t *timeout, bool interruptible); | ||||
| int msm_queue_fence_cb(struct msm_fence_context *fctx, | ||||
| 		struct msm_fence_cb *cb, uint32_t fence); | ||||
| void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); | ||||
| 
 | ||||
| struct dma_fence * msm_fence_alloc(struct msm_fence_context *fctx); | ||||
|  | ||||
| @ -470,7 +470,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, | ||||
| 
 | ||||
| 	*offset = msm_gem_mmap_offset(obj); | ||||
| 
 | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 
 | ||||
| fail: | ||||
| 	return ret; | ||||
| @ -798,6 +798,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* don't call directly!  Use drm_gem_object_put() and friends */ | ||||
| void msm_gem_free_object(struct drm_gem_object *obj) | ||||
| { | ||||
| 	struct drm_device *dev = obj->dev; | ||||
| @ -854,7 +855,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, | ||||
| 	ret = drm_gem_handle_create(file, obj, handle); | ||||
| 
 | ||||
| 	/* drop reference from allocate - handle holds it now */ | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -974,7 +975,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, | ||||
| 	return obj; | ||||
| 
 | ||||
| fail: | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 	return ERR_PTR(ret); | ||||
| } | ||||
| 
 | ||||
| @ -1034,7 +1035,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, | ||||
| 	return obj; | ||||
| 
 | ||||
| fail: | ||||
| 	drm_gem_object_unreference_unlocked(obj); | ||||
| 	drm_gem_object_put_unlocked(obj); | ||||
| 	return ERR_PTR(ret); | ||||
| } | ||||
| 
 | ||||
| @ -1052,7 +1053,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, | ||||
| 	if (iova) { | ||||
| 		ret = msm_gem_get_iova(obj, aspace, iova); | ||||
| 		if (ret) { | ||||
| 			drm_gem_object_unreference(obj); | ||||
| 			drm_gem_object_put(obj); | ||||
| 			return ERR_PTR(ret); | ||||
| 		} | ||||
| 	} | ||||
| @ -1060,7 +1061,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, | ||||
| 	vaddr = msm_gem_get_vaddr(obj); | ||||
| 	if (IS_ERR(vaddr)) { | ||||
| 		msm_gem_put_iova(obj, aspace); | ||||
| 		drm_gem_object_unreference(obj); | ||||
| 		drm_gem_object_put(obj); | ||||
| 		return ERR_CAST(vaddr); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -146,6 +146,7 @@ struct msm_gem_submit { | ||||
| 	struct msm_gpu_submitqueue *queue; | ||||
| 	struct pid *pid;    /* submitting process */ | ||||
| 	bool valid;         /* true if no cmdstream patching needed */ | ||||
| 	bool in_rb;         /* "sudo" mode, copy cmds into RB */ | ||||
| 	struct msm_ringbuffer *ring; | ||||
| 	unsigned int nr_cmds; | ||||
| 	unsigned int nr_bos; | ||||
|  | ||||
| @ -430,6 +430,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, | ||||
| 	if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (args->flags & MSM_SUBMIT_SUDO) { | ||||
| 		if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) || | ||||
| 		    !capable(CAP_SYS_RAWIO)) | ||||
| 			return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	queue = msm_submitqueue_get(ctx, args->queueid); | ||||
| 	if (!queue) | ||||
| 		return -ENOENT; | ||||
| @ -471,6 +477,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	if (args->flags & MSM_SUBMIT_SUDO) | ||||
| 		submit->in_rb = true; | ||||
| 
 | ||||
| 	ret = submit_lookup_objects(submit, args, file); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
|  | ||||
| @ -96,6 +96,8 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | ||||
| 		const char *name) | ||||
| { | ||||
| 	struct msm_gem_address_space *aspace; | ||||
| 	u64 size = domain->geometry.aperture_end - | ||||
| 		domain->geometry.aperture_start; | ||||
| 
 | ||||
| 	aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); | ||||
| 	if (!aspace) | ||||
| @ -106,7 +108,7 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | ||||
| 	aspace->mmu = msm_iommu_new(dev, domain); | ||||
| 
 | ||||
| 	drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), | ||||
| 			(domain->geometry.aperture_end >> PAGE_SHIFT) - 1); | ||||
| 		size >> PAGE_SHIFT); | ||||
| 
 | ||||
| 	kref_init(&aspace->kref); | ||||
| 
 | ||||
|  | ||||
| @ -552,7 +552,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) | ||||
| 		/* move to inactive: */ | ||||
| 		msm_gem_move_to_inactive(&msm_obj->base); | ||||
| 		msm_gem_put_iova(&msm_obj->base, gpu->aspace); | ||||
| 		drm_gem_object_unreference(&msm_obj->base); | ||||
| 		drm_gem_object_put(&msm_obj->base); | ||||
| 	} | ||||
| 
 | ||||
| 	pm_runtime_mark_last_busy(&gpu->pdev->dev); | ||||
| @ -634,7 +634,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | ||||
| 		WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); | ||||
| 
 | ||||
| 		/* submit takes a reference to the bo and iova until retired: */ | ||||
| 		drm_gem_object_reference(&msm_obj->base); | ||||
| 		drm_gem_object_get(&msm_obj->base); | ||||
| 		msm_gem_get_iova(&msm_obj->base, | ||||
| 				submit->gpu->aspace, &iova); | ||||
| 
 | ||||
| @ -682,8 +682,10 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) | ||||
| 
 | ||||
| 	gpu->grp_clks = devm_kcalloc(dev, sizeof(struct clk *), gpu->nr_clocks, | ||||
| 		GFP_KERNEL); | ||||
| 	if (!gpu->grp_clks) | ||||
| 	if (!gpu->grp_clks) { | ||||
| 		gpu->nr_clocks = 0; | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	of_property_for_each_string(dev->of_node, "clock-names", prop, name) { | ||||
| 		gpu->grp_clks[i] = get_clock(dev, name); | ||||
| @ -865,7 +867,7 @@ fail: | ||||
| 	if (gpu->memptrs_bo) { | ||||
| 		msm_gem_put_vaddr(gpu->memptrs_bo); | ||||
| 		msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference_unlocked(gpu->memptrs_bo); | ||||
| 		drm_gem_object_put_unlocked(gpu->memptrs_bo); | ||||
| 	} | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| @ -888,7 +890,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) | ||||
| 	if (gpu->memptrs_bo) { | ||||
| 		msm_gem_put_vaddr(gpu->memptrs_bo); | ||||
| 		msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); | ||||
| 		drm_gem_object_unreference_unlocked(gpu->memptrs_bo); | ||||
| 		drm_gem_object_put_unlocked(gpu->memptrs_bo); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!IS_ERR_OR_NULL(gpu->aspace)) { | ||||
|  | ||||
| @ -65,6 +65,8 @@ struct msm_gpu_funcs { | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 	/* show GPU status in debugfs: */ | ||||
| 	void (*show)(struct msm_gpu *gpu, struct seq_file *m); | ||||
| 	/* for generation specific debugfs: */ | ||||
| 	int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); | ||||
| #endif | ||||
| 	int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); | ||||
| }; | ||||
|  | ||||
| @ -76,7 +76,7 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) | ||||
| 	if (ring->bo) { | ||||
| 		msm_gem_put_iova(ring->bo, ring->gpu->aspace); | ||||
| 		msm_gem_put_vaddr(ring->bo); | ||||
| 		drm_gem_object_unreference_unlocked(ring->bo); | ||||
| 		drm_gem_object_put_unlocked(ring->bo); | ||||
| 	} | ||||
| 	kfree(ring); | ||||
| } | ||||
|  | ||||
| @ -201,10 +201,12 @@ struct drm_msm_gem_submit_bo { | ||||
| #define MSM_SUBMIT_NO_IMPLICIT   0x80000000 /* disable implicit sync */ | ||||
| #define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */ | ||||
| #define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */ | ||||
| #define MSM_SUBMIT_SUDO          0x10000000 /* run submitted cmds from RB */ | ||||
| #define MSM_SUBMIT_FLAGS                ( \ | ||||
| 		MSM_SUBMIT_NO_IMPLICIT   | \ | ||||
| 		MSM_SUBMIT_FENCE_FD_IN   | \ | ||||
| 		MSM_SUBMIT_FENCE_FD_OUT  | \ | ||||
| 		MSM_SUBMIT_SUDO          | \ | ||||
| 		0) | ||||
| 
 | ||||
| /* Each cmdstream submit consists of a table of buffers involved, and
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user