1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AMD MP2 1.1 communication interfaces
4 *
5 * Copyright (c) 2022, Advanced Micro Devices, Inc.
6 * All Rights Reserved.
7 *
8 * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
9 */
10 #include <linux/amd-pmf-io.h>
11 #include <linux/io-64-nonatomic-lo-hi.h>
12 #include <linux/iopoll.h>
13
14 #include "amd_sfh_interface.h"
15
16 static struct amd_mp2_dev *emp2;
17
amd_sfh_wait_response(struct amd_mp2_dev * mp2,u8 sid,u32 cmd_id)18 static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
19 {
20 struct sfh_cmd_response cmd_resp;
21
22 /* Get response with status within a max of 10000 ms timeout */
23 if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,
24 (cmd_resp.response.response == 0 &&
25 cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||
26 cmd_resp.response.sensor_id == sid)), 500, 10000000))
27 return cmd_resp.response.response;
28
29 return -1;
30 }
31
amd_start_sensor(struct amd_mp2_dev * privdata,struct amd_mp2_sensor_info info)32 static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
33 {
34 struct sfh_cmd_base cmd_base;
35
36 cmd_base.ul = 0;
37 cmd_base.cmd.cmd_id = ENABLE_SENSOR;
38 cmd_base.cmd.intr_disable = 0;
39 cmd_base.cmd.sub_cmd_value = 1;
40 cmd_base.cmd.sensor_id = info.sensor_idx;
41
42 writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
43 }
44
amd_stop_sensor(struct amd_mp2_dev * privdata,u16 sensor_idx)45 static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
46 {
47 struct sfh_cmd_base cmd_base;
48
49 cmd_base.ul = 0;
50 cmd_base.cmd.cmd_id = DISABLE_SENSOR;
51 cmd_base.cmd.intr_disable = 0;
52 cmd_base.cmd.sub_cmd_value = 1;
53 cmd_base.cmd.sensor_id = sensor_idx;
54
55 writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));
56 writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
57 }
58
amd_stop_all_sensor(struct amd_mp2_dev * privdata)59 static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
60 {
61 struct sfh_cmd_base cmd_base;
62
63 cmd_base.ul = 0;
64 cmd_base.cmd.cmd_id = DISABLE_SENSOR;
65 cmd_base.cmd.intr_disable = 0;
66 /* 0xf indicates all sensors */
67 cmd_base.cmd.sensor_id = 0xf;
68
69 writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
70 }
71
72 static struct amd_mp2_ops amd_sfh_ops = {
73 .start = amd_start_sensor,
74 .stop = amd_stop_sensor,
75 .stop_all = amd_stop_all_sensor,
76 .response = amd_sfh_wait_response,
77 };
78
sfh_deinit_emp2(void)79 void sfh_deinit_emp2(void)
80 {
81 emp2 = NULL;
82 }
83
sfh_interface_init(struct amd_mp2_dev * mp2)84 void sfh_interface_init(struct amd_mp2_dev *mp2)
85 {
86 mp2->mp2_ops = &amd_sfh_ops;
87 emp2 = mp2;
88 }
89
amd_sfh_hpd_info(u8 * user_present)90 static int amd_sfh_hpd_info(u8 *user_present)
91 {
92 struct hpd_status hpdstatus;
93
94 if (!user_present)
95 return -EINVAL;
96
97 if (!emp2 || !emp2->dev_en.is_hpd_present)
98 return -ENODEV;
99
100 hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4));
101 *user_present = hpdstatus.shpd.presence;
102
103 return 0;
104 }
105
amd_sfh_als_info(u32 * ambient_light)106 static int amd_sfh_als_info(u32 *ambient_light)
107 {
108 struct sfh_als_data als_data;
109 void __iomem *sensoraddr;
110
111 if (!ambient_light)
112 return -EINVAL;
113
114 if (!emp2 || !emp2->dev_en.is_als_present)
115 return -ENODEV;
116
117 sensoraddr = emp2->vsbase +
118 (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
119 OFFSET_SENSOR_DATA_DEFAULT;
120 memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
121 *ambient_light = amd_sfh_float_to_int(als_data.lux);
122
123 return 0;
124 }
125
amd_get_sfh_info(struct amd_sfh_info * sfh_info,enum sfh_message_type op)126 int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
127 {
128 if (sfh_info) {
129 switch (op) {
130 case MT_HPD:
131 return amd_sfh_hpd_info(&sfh_info->user_present);
132 case MT_ALS:
133 return amd_sfh_als_info(&sfh_info->ambient_light);
134 }
135 }
136 return -EINVAL;
137 }
138 EXPORT_SYMBOL_GPL(amd_get_sfh_info);
139