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