1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2022 Intel Corporation
4  */
5 
6 #include "i915_drv.h"
7 #include "i915_reg.h"
8 
9 #include "intel_de.h"
10 #include "intel_display.h"
11 #include "intel_dkl_phy.h"
12 
13 static void
dkl_phy_set_hip_idx(struct drm_i915_private * i915,i915_reg_t reg,int idx)14 dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx)
15 {
16 	enum tc_port tc_port = DKL_REG_TC_PORT(reg);
17 
18 	drm_WARN_ON(&i915->drm, tc_port < TC_PORT_1 || tc_port >= I915_MAX_TC_PORTS);
19 
20 	intel_de_write(i915,
21 		       HIP_INDEX_REG(tc_port),
22 		       HIP_INDEX_VAL(tc_port, idx));
23 }
24 
25 /**
26  * intel_dkl_phy_read - read a Dekel PHY register
27  * @i915: i915 device instance
28  * @reg: Dekel PHY register
29  * @ln: lane instance of @reg
30  *
31  * Read the @reg Dekel PHY register.
32  *
33  * Returns the read value.
34  */
35 u32
intel_dkl_phy_read(struct drm_i915_private * i915,i915_reg_t reg,int ln)36 intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln)
37 {
38 	u32 val;
39 
40 	spin_lock(&i915->display.dkl.phy_lock);
41 
42 	dkl_phy_set_hip_idx(i915, reg, ln);
43 	val = intel_de_read(i915, reg);
44 
45 	spin_unlock(&i915->display.dkl.phy_lock);
46 
47 	return val;
48 }
49 
50 /**
51  * intel_dkl_phy_write - write a Dekel PHY register
52  * @i915: i915 device instance
53  * @reg: Dekel PHY register
54  * @ln: lane instance of @reg
55  * @val: value to write
56  *
57  * Write @val to the @reg Dekel PHY register.
58  */
59 void
intel_dkl_phy_write(struct drm_i915_private * i915,i915_reg_t reg,int ln,u32 val)60 intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val)
61 {
62 	spin_lock(&i915->display.dkl.phy_lock);
63 
64 	dkl_phy_set_hip_idx(i915, reg, ln);
65 	intel_de_write(i915, reg, val);
66 
67 	spin_unlock(&i915->display.dkl.phy_lock);
68 }
69 
70 /**
71  * intel_dkl_phy_rmw - read-modify-write a Dekel PHY register
72  * @i915: i915 device instance
73  * @reg: Dekel PHY register
74  * @ln: lane instance of @reg
75  * @clear: mask to clear
76  * @set: mask to set
77  *
78  * Read the @reg Dekel PHY register, clearing then setting the @clear/@set bits in it, and writing
79  * this value back to the register if the value differs from the read one.
80  */
81 void
intel_dkl_phy_rmw(struct drm_i915_private * i915,i915_reg_t reg,int ln,u32 clear,u32 set)82 intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set)
83 {
84 	spin_lock(&i915->display.dkl.phy_lock);
85 
86 	dkl_phy_set_hip_idx(i915, reg, ln);
87 	intel_de_rmw(i915, reg, clear, set);
88 
89 	spin_unlock(&i915->display.dkl.phy_lock);
90 }
91 
92 /**
93  * intel_dkl_phy_posting_read - do a posting read from a Dekel PHY register
94  * @i915: i915 device instance
95  * @reg: Dekel PHY register
96  * @ln: lane instance of @reg
97  *
98  * Read the @reg Dekel PHY register without returning the read value.
99  */
100 void
intel_dkl_phy_posting_read(struct drm_i915_private * i915,i915_reg_t reg,int ln)101 intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln)
102 {
103 	spin_lock(&i915->display.dkl.phy_lock);
104 
105 	dkl_phy_set_hip_idx(i915, reg, ln);
106 	intel_de_posting_read(i915, reg);
107 
108 	spin_unlock(&i915->display.dkl.phy_lock);
109 }
110