diff options
-rw-r--r-- | drivers/firmware/ti_sci.c | 685 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.h | 289 | ||||
-rw-r--r-- | include/linux/ti_sci_protocol.h | 78 |
3 files changed, 1052 insertions, 0 deletions
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 1e9a2a68c471..51194b3cbbaf 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c | |||
@@ -837,6 +837,675 @@ static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id, | |||
837 | } | 837 | } |
838 | 838 | ||
839 | /** | 839 | /** |
840 | * ti_sci_set_clock_state() - Set clock state helper | ||
841 | * @handle: pointer to TI SCI handle | ||
842 | * @dev_id: Device identifier this request is for | ||
843 | * @clk_id: Clock identifier for the device for this request. | ||
844 | * Each device has it's own set of clock inputs. This indexes | ||
845 | * which clock input to modify. | ||
846 | * @flags: Header flags as needed | ||
847 | * @state: State to request for the clock. | ||
848 | * | ||
849 | * Return: 0 if all went well, else returns appropriate error value. | ||
850 | */ | ||
851 | static int ti_sci_set_clock_state(const struct ti_sci_handle *handle, | ||
852 | u32 dev_id, u8 clk_id, | ||
853 | u32 flags, u8 state) | ||
854 | { | ||
855 | struct ti_sci_info *info; | ||
856 | struct ti_sci_msg_req_set_clock_state *req; | ||
857 | struct ti_sci_msg_hdr *resp; | ||
858 | struct ti_sci_xfer *xfer; | ||
859 | struct device *dev; | ||
860 | int ret = 0; | ||
861 | |||
862 | if (IS_ERR(handle)) | ||
863 | return PTR_ERR(handle); | ||
864 | if (!handle) | ||
865 | return -EINVAL; | ||
866 | |||
867 | info = handle_to_ti_sci_info(handle); | ||
868 | dev = info->dev; | ||
869 | |||
870 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_STATE, | ||
871 | flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
872 | sizeof(*req), sizeof(*resp)); | ||
873 | if (IS_ERR(xfer)) { | ||
874 | ret = PTR_ERR(xfer); | ||
875 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
876 | return ret; | ||
877 | } | ||
878 | req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf; | ||
879 | req->dev_id = dev_id; | ||
880 | req->clk_id = clk_id; | ||
881 | req->request_state = state; | ||
882 | |||
883 | ret = ti_sci_do_xfer(info, xfer); | ||
884 | if (ret) { | ||
885 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
886 | goto fail; | ||
887 | } | ||
888 | |||
889 | resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | ||
890 | |||
891 | ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; | ||
892 | |||
893 | fail: | ||
894 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
895 | |||
896 | return ret; | ||
897 | } | ||
898 | |||
899 | /** | ||
900 | * ti_sci_cmd_get_clock_state() - Get clock state helper | ||
901 | * @handle: pointer to TI SCI handle | ||
902 | * @dev_id: Device identifier this request is for | ||
903 | * @clk_id: Clock identifier for the device for this request. | ||
904 | * Each device has it's own set of clock inputs. This indexes | ||
905 | * which clock input to modify. | ||
906 | * @programmed_state: State requested for clock to move to | ||
907 | * @current_state: State that the clock is currently in | ||
908 | * | ||
909 | * Return: 0 if all went well, else returns appropriate error value. | ||
910 | */ | ||
911 | static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle, | ||
912 | u32 dev_id, u8 clk_id, | ||
913 | u8 *programmed_state, u8 *current_state) | ||
914 | { | ||
915 | struct ti_sci_info *info; | ||
916 | struct ti_sci_msg_req_get_clock_state *req; | ||
917 | struct ti_sci_msg_resp_get_clock_state *resp; | ||
918 | struct ti_sci_xfer *xfer; | ||
919 | struct device *dev; | ||
920 | int ret = 0; | ||
921 | |||
922 | if (IS_ERR(handle)) | ||
923 | return PTR_ERR(handle); | ||
924 | if (!handle) | ||
925 | return -EINVAL; | ||
926 | |||
927 | if (!programmed_state && !current_state) | ||
928 | return -EINVAL; | ||
929 | |||
930 | info = handle_to_ti_sci_info(handle); | ||
931 | dev = info->dev; | ||
932 | |||
933 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_STATE, | ||
934 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
935 | sizeof(*req), sizeof(*resp)); | ||
936 | if (IS_ERR(xfer)) { | ||
937 | ret = PTR_ERR(xfer); | ||
938 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
939 | return ret; | ||
940 | } | ||
941 | req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf; | ||
942 | req->dev_id = dev_id; | ||
943 | req->clk_id = clk_id; | ||
944 | |||
945 | ret = ti_sci_do_xfer(info, xfer); | ||
946 | if (ret) { | ||
947 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
948 | goto fail; | ||
949 | } | ||
950 | |||
951 | resp = (struct ti_sci_msg_resp_get_clock_state *)xfer->xfer_buf; | ||
952 | |||
953 | if (!tis_sci_is_response_ack(resp)) { | ||
954 | ret = -ENODEV; | ||
955 | goto fail; | ||
956 | } | ||
957 | |||
958 | if (programmed_state) | ||
959 | *programmed_state = resp->programmed_state; | ||
960 | if (current_state) | ||
961 | *current_state = resp->current_state; | ||
962 | |||
963 | fail: | ||
964 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
965 | |||
966 | return ret; | ||
967 | } | ||
968 | |||
969 | /** | ||
970 | * ti_sci_cmd_get_clock() - Get control of a clock from TI SCI | ||
971 | * @handle: pointer to TI SCI handle | ||
972 | * @dev_id: Device identifier this request is for | ||
973 | * @clk_id: Clock identifier for the device for this request. | ||
974 | * Each device has it's own set of clock inputs. This indexes | ||
975 | * which clock input to modify. | ||
976 | * @needs_ssc: 'true' if Spread Spectrum clock is desired, else 'false' | ||
977 | * @can_change_freq: 'true' if frequency change is desired, else 'false' | ||
978 | * @enable_input_term: 'true' if input termination is desired, else 'false' | ||
979 | * | ||
980 | * Return: 0 if all went well, else returns appropriate error value. | ||
981 | */ | ||
982 | static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id, | ||
983 | u8 clk_id, bool needs_ssc, bool can_change_freq, | ||
984 | bool enable_input_term) | ||
985 | { | ||
986 | u32 flags = 0; | ||
987 | |||
988 | flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0; | ||
989 | flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0; | ||
990 | flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0; | ||
991 | |||
992 | return ti_sci_set_clock_state(handle, dev_id, clk_id, flags, | ||
993 | MSG_CLOCK_SW_STATE_REQ); | ||
994 | } | ||
995 | |||
996 | /** | ||
997 | * ti_sci_cmd_idle_clock() - Idle a clock which is in our control | ||
998 | * @handle: pointer to TI SCI handle | ||
999 | * @dev_id: Device identifier this request is for | ||
1000 | * @clk_id: Clock identifier for the device for this request. | ||
1001 | * Each device has it's own set of clock inputs. This indexes | ||
1002 | * which clock input to modify. | ||
1003 | * | ||
1004 | * NOTE: This clock must have been requested by get_clock previously. | ||
1005 | * | ||
1006 | * Return: 0 if all went well, else returns appropriate error value. | ||
1007 | */ | ||
1008 | static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle, | ||
1009 | u32 dev_id, u8 clk_id) | ||
1010 | { | ||
1011 | return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, | ||
1012 | MSG_CLOCK_SW_STATE_UNREQ); | ||
1013 | } | ||
1014 | |||
1015 | /** | ||
1016 | * ti_sci_cmd_put_clock() - Release a clock from our control back to TISCI | ||
1017 | * @handle: pointer to TI SCI handle | ||
1018 | * @dev_id: Device identifier this request is for | ||
1019 | * @clk_id: Clock identifier for the device for this request. | ||
1020 | * Each device has it's own set of clock inputs. This indexes | ||
1021 | * which clock input to modify. | ||
1022 | * | ||
1023 | * NOTE: This clock must have been requested by get_clock previously. | ||
1024 | * | ||
1025 | * Return: 0 if all went well, else returns appropriate error value. | ||
1026 | */ | ||
1027 | static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle, | ||
1028 | u32 dev_id, u8 clk_id) | ||
1029 | { | ||
1030 | return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, | ||
1031 | MSG_CLOCK_SW_STATE_AUTO); | ||
1032 | } | ||
1033 | |||
1034 | /** | ||
1035 | * ti_sci_cmd_clk_is_auto() - Is the clock being auto managed | ||
1036 | * @handle: pointer to TI SCI handle | ||
1037 | * @dev_id: Device identifier this request is for | ||
1038 | * @clk_id: Clock identifier for the device for this request. | ||
1039 | * Each device has it's own set of clock inputs. This indexes | ||
1040 | * which clock input to modify. | ||
1041 | * @req_state: state indicating if the clock is auto managed | ||
1042 | * | ||
1043 | * Return: 0 if all went well, else returns appropriate error value. | ||
1044 | */ | ||
1045 | static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle, | ||
1046 | u32 dev_id, u8 clk_id, bool *req_state) | ||
1047 | { | ||
1048 | u8 state = 0; | ||
1049 | int ret; | ||
1050 | |||
1051 | if (!req_state) | ||
1052 | return -EINVAL; | ||
1053 | |||
1054 | ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, &state, NULL); | ||
1055 | if (ret) | ||
1056 | return ret; | ||
1057 | |||
1058 | *req_state = (state == MSG_CLOCK_SW_STATE_AUTO); | ||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * ti_sci_cmd_clk_is_on() - Is the clock ON | ||
1064 | * @handle: pointer to TI SCI handle | ||
1065 | * @dev_id: Device identifier this request is for | ||
1066 | * @clk_id: Clock identifier for the device for this request. | ||
1067 | * Each device has it's own set of clock inputs. This indexes | ||
1068 | * which clock input to modify. | ||
1069 | * @req_state: state indicating if the clock is managed by us and enabled | ||
1070 | * @curr_state: state indicating if the clock is ready for operation | ||
1071 | * | ||
1072 | * Return: 0 if all went well, else returns appropriate error value. | ||
1073 | */ | ||
1074 | static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id, | ||
1075 | u8 clk_id, bool *req_state, bool *curr_state) | ||
1076 | { | ||
1077 | u8 c_state = 0, r_state = 0; | ||
1078 | int ret; | ||
1079 | |||
1080 | if (!req_state && !curr_state) | ||
1081 | return -EINVAL; | ||
1082 | |||
1083 | ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, | ||
1084 | &r_state, &c_state); | ||
1085 | if (ret) | ||
1086 | return ret; | ||
1087 | |||
1088 | if (req_state) | ||
1089 | *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ); | ||
1090 | if (curr_state) | ||
1091 | *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY); | ||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | /** | ||
1096 | * ti_sci_cmd_clk_is_off() - Is the clock OFF | ||
1097 | * @handle: pointer to TI SCI handle | ||
1098 | * @dev_id: Device identifier this request is for | ||
1099 | * @clk_id: Clock identifier for the device for this request. | ||
1100 | * Each device has it's own set of clock inputs. This indexes | ||
1101 | * which clock input to modify. | ||
1102 | * @req_state: state indicating if the clock is managed by us and disabled | ||
1103 | * @curr_state: state indicating if the clock is NOT ready for operation | ||
1104 | * | ||
1105 | * Return: 0 if all went well, else returns appropriate error value. | ||
1106 | */ | ||
1107 | static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id, | ||
1108 | u8 clk_id, bool *req_state, bool *curr_state) | ||
1109 | { | ||
1110 | u8 c_state = 0, r_state = 0; | ||
1111 | int ret; | ||
1112 | |||
1113 | if (!req_state && !curr_state) | ||
1114 | return -EINVAL; | ||
1115 | |||
1116 | ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, | ||
1117 | &r_state, &c_state); | ||
1118 | if (ret) | ||
1119 | return ret; | ||
1120 | |||
1121 | if (req_state) | ||
1122 | *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ); | ||
1123 | if (curr_state) | ||
1124 | *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY); | ||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | /** | ||
1129 | * ti_sci_cmd_clk_set_parent() - Set the clock source of a specific device clock | ||
1130 | * @handle: pointer to TI SCI handle | ||
1131 | * @dev_id: Device identifier this request is for | ||
1132 | * @clk_id: Clock identifier for the device for this request. | ||
1133 | * Each device has it's own set of clock inputs. This indexes | ||
1134 | * which clock input to modify. | ||
1135 | * @parent_id: Parent clock identifier to set | ||
1136 | * | ||
1137 | * Return: 0 if all went well, else returns appropriate error value. | ||
1138 | */ | ||
1139 | static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle, | ||
1140 | u32 dev_id, u8 clk_id, u8 parent_id) | ||
1141 | { | ||
1142 | struct ti_sci_info *info; | ||
1143 | struct ti_sci_msg_req_set_clock_parent *req; | ||
1144 | struct ti_sci_msg_hdr *resp; | ||
1145 | struct ti_sci_xfer *xfer; | ||
1146 | struct device *dev; | ||
1147 | int ret = 0; | ||
1148 | |||
1149 | if (IS_ERR(handle)) | ||
1150 | return PTR_ERR(handle); | ||
1151 | if (!handle) | ||
1152 | return -EINVAL; | ||
1153 | |||
1154 | info = handle_to_ti_sci_info(handle); | ||
1155 | dev = info->dev; | ||
1156 | |||
1157 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_PARENT, | ||
1158 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1159 | sizeof(*req), sizeof(*resp)); | ||
1160 | if (IS_ERR(xfer)) { | ||
1161 | ret = PTR_ERR(xfer); | ||
1162 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1163 | return ret; | ||
1164 | } | ||
1165 | req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf; | ||
1166 | req->dev_id = dev_id; | ||
1167 | req->clk_id = clk_id; | ||
1168 | req->parent_id = parent_id; | ||
1169 | |||
1170 | ret = ti_sci_do_xfer(info, xfer); | ||
1171 | if (ret) { | ||
1172 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1173 | goto fail; | ||
1174 | } | ||
1175 | |||
1176 | resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | ||
1177 | |||
1178 | ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; | ||
1179 | |||
1180 | fail: | ||
1181 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1182 | |||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
1186 | /** | ||
1187 | * ti_sci_cmd_clk_get_parent() - Get current parent clock source | ||
1188 | * @handle: pointer to TI SCI handle | ||
1189 | * @dev_id: Device identifier this request is for | ||
1190 | * @clk_id: Clock identifier for the device for this request. | ||
1191 | * Each device has it's own set of clock inputs. This indexes | ||
1192 | * which clock input to modify. | ||
1193 | * @parent_id: Current clock parent | ||
1194 | * | ||
1195 | * Return: 0 if all went well, else returns appropriate error value. | ||
1196 | */ | ||
1197 | static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle, | ||
1198 | u32 dev_id, u8 clk_id, u8 *parent_id) | ||
1199 | { | ||
1200 | struct ti_sci_info *info; | ||
1201 | struct ti_sci_msg_req_get_clock_parent *req; | ||
1202 | struct ti_sci_msg_resp_get_clock_parent *resp; | ||
1203 | struct ti_sci_xfer *xfer; | ||
1204 | struct device *dev; | ||
1205 | int ret = 0; | ||
1206 | |||
1207 | if (IS_ERR(handle)) | ||
1208 | return PTR_ERR(handle); | ||
1209 | if (!handle || !parent_id) | ||
1210 | return -EINVAL; | ||
1211 | |||
1212 | info = handle_to_ti_sci_info(handle); | ||
1213 | dev = info->dev; | ||
1214 | |||
1215 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_PARENT, | ||
1216 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1217 | sizeof(*req), sizeof(*resp)); | ||
1218 | if (IS_ERR(xfer)) { | ||
1219 | ret = PTR_ERR(xfer); | ||
1220 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1221 | return ret; | ||
1222 | } | ||
1223 | req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf; | ||
1224 | req->dev_id = dev_id; | ||
1225 | req->clk_id = clk_id; | ||
1226 | |||
1227 | ret = ti_sci_do_xfer(info, xfer); | ||
1228 | if (ret) { | ||
1229 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1230 | goto fail; | ||
1231 | } | ||
1232 | |||
1233 | resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf; | ||
1234 | |||
1235 | if (!tis_sci_is_response_ack(resp)) | ||
1236 | ret = -ENODEV; | ||
1237 | else | ||
1238 | *parent_id = resp->parent_id; | ||
1239 | |||
1240 | fail: | ||
1241 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1242 | |||
1243 | return ret; | ||
1244 | } | ||
1245 | |||
1246 | /** | ||
1247 | * ti_sci_cmd_clk_get_num_parents() - Get the number of parents of the current clock source | ||
1248 | * @handle: pointer to TI SCI handle | ||
1249 | * @dev_id: Device identifier this request is for | ||
1250 | * @clk_id: Clock identifier for the device for this request. | ||
1251 | * Each device has it's own set of clock inputs. This indexes | ||
1252 | * which clock input to modify. | ||
1253 | * @num_parents: Returns he number of parents to the current clock. | ||
1254 | * | ||
1255 | * Return: 0 if all went well, else returns appropriate error value. | ||
1256 | */ | ||
1257 | static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle, | ||
1258 | u32 dev_id, u8 clk_id, | ||
1259 | u8 *num_parents) | ||
1260 | { | ||
1261 | struct ti_sci_info *info; | ||
1262 | struct ti_sci_msg_req_get_clock_num_parents *req; | ||
1263 | struct ti_sci_msg_resp_get_clock_num_parents *resp; | ||
1264 | struct ti_sci_xfer *xfer; | ||
1265 | struct device *dev; | ||
1266 | int ret = 0; | ||
1267 | |||
1268 | if (IS_ERR(handle)) | ||
1269 | return PTR_ERR(handle); | ||
1270 | if (!handle || !num_parents) | ||
1271 | return -EINVAL; | ||
1272 | |||
1273 | info = handle_to_ti_sci_info(handle); | ||
1274 | dev = info->dev; | ||
1275 | |||
1276 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, | ||
1277 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1278 | sizeof(*req), sizeof(*resp)); | ||
1279 | if (IS_ERR(xfer)) { | ||
1280 | ret = PTR_ERR(xfer); | ||
1281 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1282 | return ret; | ||
1283 | } | ||
1284 | req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf; | ||
1285 | req->dev_id = dev_id; | ||
1286 | req->clk_id = clk_id; | ||
1287 | |||
1288 | ret = ti_sci_do_xfer(info, xfer); | ||
1289 | if (ret) { | ||
1290 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1291 | goto fail; | ||
1292 | } | ||
1293 | |||
1294 | resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf; | ||
1295 | |||
1296 | if (!tis_sci_is_response_ack(resp)) | ||
1297 | ret = -ENODEV; | ||
1298 | else | ||
1299 | *num_parents = resp->num_parents; | ||
1300 | |||
1301 | fail: | ||
1302 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1303 | |||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | /** | ||
1308 | * ti_sci_cmd_clk_get_match_freq() - Find a good match for frequency | ||
1309 | * @handle: pointer to TI SCI handle | ||
1310 | * @dev_id: Device identifier this request is for | ||
1311 | * @clk_id: Clock identifier for the device for this request. | ||
1312 | * Each device has it's own set of clock inputs. This indexes | ||
1313 | * which clock input to modify. | ||
1314 | * @min_freq: The minimum allowable frequency in Hz. This is the minimum | ||
1315 | * allowable programmed frequency and does not account for clock | ||
1316 | * tolerances and jitter. | ||
1317 | * @target_freq: The target clock frequency in Hz. A frequency will be | ||
1318 | * processed as close to this target frequency as possible. | ||
1319 | * @max_freq: The maximum allowable frequency in Hz. This is the maximum | ||
1320 | * allowable programmed frequency and does not account for clock | ||
1321 | * tolerances and jitter. | ||
1322 | * @match_freq: Frequency match in Hz response. | ||
1323 | * | ||
1324 | * Return: 0 if all went well, else returns appropriate error value. | ||
1325 | */ | ||
1326 | static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle, | ||
1327 | u32 dev_id, u8 clk_id, u64 min_freq, | ||
1328 | u64 target_freq, u64 max_freq, | ||
1329 | u64 *match_freq) | ||
1330 | { | ||
1331 | struct ti_sci_info *info; | ||
1332 | struct ti_sci_msg_req_query_clock_freq *req; | ||
1333 | struct ti_sci_msg_resp_query_clock_freq *resp; | ||
1334 | struct ti_sci_xfer *xfer; | ||
1335 | struct device *dev; | ||
1336 | int ret = 0; | ||
1337 | |||
1338 | if (IS_ERR(handle)) | ||
1339 | return PTR_ERR(handle); | ||
1340 | if (!handle || !match_freq) | ||
1341 | return -EINVAL; | ||
1342 | |||
1343 | info = handle_to_ti_sci_info(handle); | ||
1344 | dev = info->dev; | ||
1345 | |||
1346 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_QUERY_CLOCK_FREQ, | ||
1347 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1348 | sizeof(*req), sizeof(*resp)); | ||
1349 | if (IS_ERR(xfer)) { | ||
1350 | ret = PTR_ERR(xfer); | ||
1351 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1352 | return ret; | ||
1353 | } | ||
1354 | req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf; | ||
1355 | req->dev_id = dev_id; | ||
1356 | req->clk_id = clk_id; | ||
1357 | req->min_freq_hz = min_freq; | ||
1358 | req->target_freq_hz = target_freq; | ||
1359 | req->max_freq_hz = max_freq; | ||
1360 | |||
1361 | ret = ti_sci_do_xfer(info, xfer); | ||
1362 | if (ret) { | ||
1363 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1364 | goto fail; | ||
1365 | } | ||
1366 | |||
1367 | resp = (struct ti_sci_msg_resp_query_clock_freq *)xfer->xfer_buf; | ||
1368 | |||
1369 | if (!tis_sci_is_response_ack(resp)) | ||
1370 | ret = -ENODEV; | ||
1371 | else | ||
1372 | *match_freq = resp->freq_hz; | ||
1373 | |||
1374 | fail: | ||
1375 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1376 | |||
1377 | return ret; | ||
1378 | } | ||
1379 | |||
1380 | /** | ||
1381 | * ti_sci_cmd_clk_set_freq() - Set a frequency for clock | ||
1382 | * @handle: pointer to TI SCI handle | ||
1383 | * @dev_id: Device identifier this request is for | ||
1384 | * @clk_id: Clock identifier for the device for this request. | ||
1385 | * Each device has it's own set of clock inputs. This indexes | ||
1386 | * which clock input to modify. | ||
1387 | * @min_freq: The minimum allowable frequency in Hz. This is the minimum | ||
1388 | * allowable programmed frequency and does not account for clock | ||
1389 | * tolerances and jitter. | ||
1390 | * @target_freq: The target clock frequency in Hz. A frequency will be | ||
1391 | * processed as close to this target frequency as possible. | ||
1392 | * @max_freq: The maximum allowable frequency in Hz. This is the maximum | ||
1393 | * allowable programmed frequency and does not account for clock | ||
1394 | * tolerances and jitter. | ||
1395 | * | ||
1396 | * Return: 0 if all went well, else returns appropriate error value. | ||
1397 | */ | ||
1398 | static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle, | ||
1399 | u32 dev_id, u8 clk_id, u64 min_freq, | ||
1400 | u64 target_freq, u64 max_freq) | ||
1401 | { | ||
1402 | struct ti_sci_info *info; | ||
1403 | struct ti_sci_msg_req_set_clock_freq *req; | ||
1404 | struct ti_sci_msg_hdr *resp; | ||
1405 | struct ti_sci_xfer *xfer; | ||
1406 | struct device *dev; | ||
1407 | int ret = 0; | ||
1408 | |||
1409 | if (IS_ERR(handle)) | ||
1410 | return PTR_ERR(handle); | ||
1411 | if (!handle) | ||
1412 | return -EINVAL; | ||
1413 | |||
1414 | info = handle_to_ti_sci_info(handle); | ||
1415 | dev = info->dev; | ||
1416 | |||
1417 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_FREQ, | ||
1418 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1419 | sizeof(*req), sizeof(*resp)); | ||
1420 | if (IS_ERR(xfer)) { | ||
1421 | ret = PTR_ERR(xfer); | ||
1422 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1423 | return ret; | ||
1424 | } | ||
1425 | req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf; | ||
1426 | req->dev_id = dev_id; | ||
1427 | req->clk_id = clk_id; | ||
1428 | req->min_freq_hz = min_freq; | ||
1429 | req->target_freq_hz = target_freq; | ||
1430 | req->max_freq_hz = max_freq; | ||
1431 | |||
1432 | ret = ti_sci_do_xfer(info, xfer); | ||
1433 | if (ret) { | ||
1434 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1435 | goto fail; | ||
1436 | } | ||
1437 | |||
1438 | resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | ||
1439 | |||
1440 | ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; | ||
1441 | |||
1442 | fail: | ||
1443 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1444 | |||
1445 | return ret; | ||
1446 | } | ||
1447 | |||
1448 | /** | ||
1449 | * ti_sci_cmd_clk_get_freq() - Get current frequency | ||
1450 | * @handle: pointer to TI SCI handle | ||
1451 | * @dev_id: Device identifier this request is for | ||
1452 | * @clk_id: Clock identifier for the device for this request. | ||
1453 | * Each device has it's own set of clock inputs. This indexes | ||
1454 | * which clock input to modify. | ||
1455 | * @freq: Currently frequency in Hz | ||
1456 | * | ||
1457 | * Return: 0 if all went well, else returns appropriate error value. | ||
1458 | */ | ||
1459 | static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle, | ||
1460 | u32 dev_id, u8 clk_id, u64 *freq) | ||
1461 | { | ||
1462 | struct ti_sci_info *info; | ||
1463 | struct ti_sci_msg_req_get_clock_freq *req; | ||
1464 | struct ti_sci_msg_resp_get_clock_freq *resp; | ||
1465 | struct ti_sci_xfer *xfer; | ||
1466 | struct device *dev; | ||
1467 | int ret = 0; | ||
1468 | |||
1469 | if (IS_ERR(handle)) | ||
1470 | return PTR_ERR(handle); | ||
1471 | if (!handle || !freq) | ||
1472 | return -EINVAL; | ||
1473 | |||
1474 | info = handle_to_ti_sci_info(handle); | ||
1475 | dev = info->dev; | ||
1476 | |||
1477 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_FREQ, | ||
1478 | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | ||
1479 | sizeof(*req), sizeof(*resp)); | ||
1480 | if (IS_ERR(xfer)) { | ||
1481 | ret = PTR_ERR(xfer); | ||
1482 | dev_err(dev, "Message alloc failed(%d)\n", ret); | ||
1483 | return ret; | ||
1484 | } | ||
1485 | req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf; | ||
1486 | req->dev_id = dev_id; | ||
1487 | req->clk_id = clk_id; | ||
1488 | |||
1489 | ret = ti_sci_do_xfer(info, xfer); | ||
1490 | if (ret) { | ||
1491 | dev_err(dev, "Mbox send fail %d\n", ret); | ||
1492 | goto fail; | ||
1493 | } | ||
1494 | |||
1495 | resp = (struct ti_sci_msg_resp_get_clock_freq *)xfer->xfer_buf; | ||
1496 | |||
1497 | if (!tis_sci_is_response_ack(resp)) | ||
1498 | ret = -ENODEV; | ||
1499 | else | ||
1500 | *freq = resp->freq_hz; | ||
1501 | |||
1502 | fail: | ||
1503 | ti_sci_put_one_xfer(&info->minfo, xfer); | ||
1504 | |||
1505 | return ret; | ||
1506 | } | ||
1507 | |||
1508 | /** | ||
840 | * ti_sci_setup_ops() - Setup the operations structures | 1509 | * ti_sci_setup_ops() - Setup the operations structures |
841 | * @info: pointer to TISCI pointer | 1510 | * @info: pointer to TISCI pointer |
842 | */ | 1511 | */ |
@@ -844,6 +1513,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) | |||
844 | { | 1513 | { |
845 | struct ti_sci_ops *ops = &info->handle.ops; | 1514 | struct ti_sci_ops *ops = &info->handle.ops; |
846 | struct ti_sci_dev_ops *dops = &ops->dev_ops; | 1515 | struct ti_sci_dev_ops *dops = &ops->dev_ops; |
1516 | struct ti_sci_clk_ops *cops = &ops->clk_ops; | ||
847 | 1517 | ||
848 | dops->get_device = ti_sci_cmd_get_device; | 1518 | dops->get_device = ti_sci_cmd_get_device; |
849 | dops->idle_device = ti_sci_cmd_idle_device; | 1519 | dops->idle_device = ti_sci_cmd_idle_device; |
@@ -855,6 +1525,21 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) | |||
855 | dops->is_stop = ti_sci_cmd_dev_is_stop; | 1525 | dops->is_stop = ti_sci_cmd_dev_is_stop; |
856 | dops->is_on = ti_sci_cmd_dev_is_on; | 1526 | dops->is_on = ti_sci_cmd_dev_is_on; |
857 | dops->is_transitioning = ti_sci_cmd_dev_is_trans; | 1527 | dops->is_transitioning = ti_sci_cmd_dev_is_trans; |
1528 | |||
1529 | cops->get_clock = ti_sci_cmd_get_clock; | ||
1530 | cops->idle_clock = ti_sci_cmd_idle_clock; | ||
1531 | cops->put_clock = ti_sci_cmd_put_clock; | ||
1532 | cops->is_auto = ti_sci_cmd_clk_is_auto; | ||
1533 | cops->is_on = ti_sci_cmd_clk_is_on; | ||
1534 | cops->is_off = ti_sci_cmd_clk_is_off; | ||
1535 | |||
1536 | cops->set_parent = ti_sci_cmd_clk_set_parent; | ||
1537 | cops->get_parent = ti_sci_cmd_clk_get_parent; | ||
1538 | cops->get_num_parents = ti_sci_cmd_clk_get_num_parents; | ||
1539 | |||
1540 | cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq; | ||
1541 | cops->set_freq = ti_sci_cmd_clk_set_freq; | ||
1542 | cops->get_freq = ti_sci_cmd_clk_get_freq; | ||
858 | } | 1543 | } |
859 | 1544 | ||
860 | /** | 1545 | /** |
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index b5b0f9745933..d02615152f2c 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h | |||
@@ -51,6 +51,16 @@ | |||
51 | #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 | 51 | #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 |
52 | #define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 | 52 | #define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 |
53 | 53 | ||
54 | /* Clock requests */ | ||
55 | #define TI_SCI_MSG_SET_CLOCK_STATE 0x0100 | ||
56 | #define TI_SCI_MSG_GET_CLOCK_STATE 0x0101 | ||
57 | #define TI_SCI_MSG_SET_CLOCK_PARENT 0x0102 | ||
58 | #define TI_SCI_MSG_GET_CLOCK_PARENT 0x0103 | ||
59 | #define TI_SCI_MSG_GET_NUM_CLOCK_PARENTS 0x0104 | ||
60 | #define TI_SCI_MSG_SET_CLOCK_FREQ 0x010c | ||
61 | #define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d | ||
62 | #define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e | ||
63 | |||
54 | /** | 64 | /** |
55 | * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses | 65 | * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses |
56 | * @type: Type of messages: One of TI_SCI_MSG* values | 66 | * @type: Type of messages: One of TI_SCI_MSG* values |
@@ -172,4 +182,283 @@ struct ti_sci_msg_resp_get_device_state { | |||
172 | u8 current_state; | 182 | u8 current_state; |
173 | } __packed; | 183 | } __packed; |
174 | 184 | ||
185 | /** | ||
186 | * struct ti_sci_msg_req_set_clock_state - Request to setup a Clock state | ||
187 | * @hdr: Generic Header, Certain flags can be set specific to the clocks: | ||
188 | * MSG_FLAG_CLOCK_ALLOW_SSC: Allow this clock to be modified | ||
189 | * via spread spectrum clocking. | ||
190 | * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE: Allow this clock's | ||
191 | * frequency to be changed while it is running so long as it | ||
192 | * is within the min/max limits. | ||
193 | * MSG_FLAG_CLOCK_INPUT_TERM: Enable input termination, this | ||
194 | * is only applicable to clock inputs on the SoC pseudo-device. | ||
195 | * @dev_id: Device identifier this request is for | ||
196 | * @clk_id: Clock identifier for the device for this request. | ||
197 | * Each device has it's own set of clock inputs. This indexes | ||
198 | * which clock input to modify. | ||
199 | * @request_state: Request the state for the clock to be set to. | ||
200 | * MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock, | ||
201 | * it can be disabled, regardless of the state of the device | ||
202 | * MSG_CLOCK_SW_STATE_AUTO: Allow the System Controller to | ||
203 | * automatically manage the state of this clock. If the device | ||
204 | * is enabled, then the clock is enabled. If the device is set | ||
205 | * to off or retention, then the clock is internally set as not | ||
206 | * being required by the device.(default) | ||
207 | * MSG_CLOCK_SW_STATE_REQ: Configure the clock to be enabled, | ||
208 | * regardless of the state of the device. | ||
209 | * | ||
210 | * Normally, all required clocks are managed by TISCI entity, this is used | ||
211 | * only for specific control *IF* required. Auto managed state is | ||
212 | * MSG_CLOCK_SW_STATE_AUTO, in other states, TISCI entity assume remote | ||
213 | * will explicitly control. | ||
214 | * | ||
215 | * Request type is TI_SCI_MSG_SET_CLOCK_STATE, response is a generic | ||
216 | * ACK or NACK message. | ||
217 | */ | ||
218 | struct ti_sci_msg_req_set_clock_state { | ||
219 | /* Additional hdr->flags options */ | ||
220 | #define MSG_FLAG_CLOCK_ALLOW_SSC TISCI_MSG_FLAG(8) | ||
221 | #define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE TISCI_MSG_FLAG(9) | ||
222 | #define MSG_FLAG_CLOCK_INPUT_TERM TISCI_MSG_FLAG(10) | ||
223 | struct ti_sci_msg_hdr hdr; | ||
224 | u32 dev_id; | ||
225 | u8 clk_id; | ||
226 | #define MSG_CLOCK_SW_STATE_UNREQ 0 | ||
227 | #define MSG_CLOCK_SW_STATE_AUTO 1 | ||
228 | #define MSG_CLOCK_SW_STATE_REQ 2 | ||
229 | u8 request_state; | ||
230 | } __packed; | ||
231 | |||
232 | /** | ||
233 | * struct ti_sci_msg_req_get_clock_state - Request for clock state | ||
234 | * @hdr: Generic Header | ||
235 | * @dev_id: Device identifier this request is for | ||
236 | * @clk_id: Clock identifier for the device for this request. | ||
237 | * Each device has it's own set of clock inputs. This indexes | ||
238 | * which clock input to get state of. | ||
239 | * | ||
240 | * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state | ||
241 | * of the clock | ||
242 | */ | ||
243 | struct ti_sci_msg_req_get_clock_state { | ||
244 | struct ti_sci_msg_hdr hdr; | ||
245 | u32 dev_id; | ||
246 | u8 clk_id; | ||
247 | } __packed; | ||
248 | |||
249 | /** | ||
250 | * struct ti_sci_msg_resp_get_clock_state - Response to get clock state | ||
251 | * @hdr: Generic Header | ||
252 | * @programmed_state: Any programmed state of the clock. This is one of | ||
253 | * MSG_CLOCK_SW_STATE* values. | ||
254 | * @current_state: Current state of the clock. This is one of: | ||
255 | * MSG_CLOCK_HW_STATE_NOT_READY: Clock is not ready | ||
256 | * MSG_CLOCK_HW_STATE_READY: Clock is ready | ||
257 | * | ||
258 | * Response to TI_SCI_MSG_GET_CLOCK_STATE. | ||
259 | */ | ||
260 | struct ti_sci_msg_resp_get_clock_state { | ||
261 | struct ti_sci_msg_hdr hdr; | ||
262 | u8 programmed_state; | ||
263 | #define MSG_CLOCK_HW_STATE_NOT_READY 0 | ||
264 | #define MSG_CLOCK_HW_STATE_READY 1 | ||
265 | u8 current_state; | ||
266 | } __packed; | ||
267 | |||
268 | /** | ||
269 | * struct ti_sci_msg_req_set_clock_parent - Set the clock parent | ||
270 | * @hdr: Generic Header | ||
271 | * @dev_id: Device identifier this request is for | ||
272 | * @clk_id: Clock identifier for the device for this request. | ||
273 | * Each device has it's own set of clock inputs. This indexes | ||
274 | * which clock input to modify. | ||
275 | * @parent_id: The new clock parent is selectable by an index via this | ||
276 | * parameter. | ||
277 | * | ||
278 | * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic | ||
279 | * ACK / NACK message. | ||
280 | */ | ||
281 | struct ti_sci_msg_req_set_clock_parent { | ||
282 | struct ti_sci_msg_hdr hdr; | ||
283 | u32 dev_id; | ||
284 | u8 clk_id; | ||
285 | u8 parent_id; | ||
286 | } __packed; | ||
287 | |||
288 | /** | ||
289 | * struct ti_sci_msg_req_get_clock_parent - Get the clock parent | ||
290 | * @hdr: Generic Header | ||
291 | * @dev_id: Device identifier this request is for | ||
292 | * @clk_id: Clock identifier for the device for this request. | ||
293 | * Each device has it's own set of clock inputs. This indexes | ||
294 | * which clock input to get the parent for. | ||
295 | * | ||
296 | * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information | ||
297 | */ | ||
298 | struct ti_sci_msg_req_get_clock_parent { | ||
299 | struct ti_sci_msg_hdr hdr; | ||
300 | u32 dev_id; | ||
301 | u8 clk_id; | ||
302 | } __packed; | ||
303 | |||
304 | /** | ||
305 | * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent | ||
306 | * @hdr: Generic Header | ||
307 | * @parent_id: The current clock parent | ||
308 | * | ||
309 | * Response to TI_SCI_MSG_GET_CLOCK_PARENT. | ||
310 | */ | ||
311 | struct ti_sci_msg_resp_get_clock_parent { | ||
312 | struct ti_sci_msg_hdr hdr; | ||
313 | u8 parent_id; | ||
314 | } __packed; | ||
315 | |||
316 | /** | ||
317 | * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents | ||
318 | * @hdr: Generic header | ||
319 | * @dev_id: Device identifier this request is for | ||
320 | * @clk_id: Clock identifier for the device for this request. | ||
321 | * | ||
322 | * This request provides information about how many clock parent options | ||
323 | * are available for a given clock to a device. This is typically used | ||
324 | * for input clocks. | ||
325 | * | ||
326 | * Request type is TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, response is appropriate | ||
327 | * message, or NACK in case of inability to satisfy request. | ||
328 | */ | ||
329 | struct ti_sci_msg_req_get_clock_num_parents { | ||
330 | struct ti_sci_msg_hdr hdr; | ||
331 | u32 dev_id; | ||
332 | u8 clk_id; | ||
333 | } __packed; | ||
334 | |||
335 | /** | ||
336 | * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents | ||
337 | * @hdr: Generic header | ||
338 | * @num_parents: Number of clock parents | ||
339 | * | ||
340 | * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS | ||
341 | */ | ||
342 | struct ti_sci_msg_resp_get_clock_num_parents { | ||
343 | struct ti_sci_msg_hdr hdr; | ||
344 | u8 num_parents; | ||
345 | } __packed; | ||
346 | |||
347 | /** | ||
348 | * struct ti_sci_msg_req_query_clock_freq - Request to query a frequency | ||
349 | * @hdr: Generic Header | ||
350 | * @dev_id: Device identifier this request is for | ||
351 | * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum | ||
352 | * allowable programmed frequency and does not account for clock | ||
353 | * tolerances and jitter. | ||
354 | * @target_freq_hz: The target clock frequency. A frequency will be found | ||
355 | * as close to this target frequency as possible. | ||
356 | * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum | ||
357 | * allowable programmed frequency and does not account for clock | ||
358 | * tolerances and jitter. | ||
359 | * @clk_id: Clock identifier for the device for this request. | ||
360 | * | ||
361 | * NOTE: Normally clock frequency management is automatically done by TISCI | ||
362 | * entity. In case of specific requests, TISCI evaluates capability to achieve | ||
363 | * requested frequency within provided range and responds with | ||
364 | * result message. | ||
365 | * | ||
366 | * Request type is TI_SCI_MSG_QUERY_CLOCK_FREQ, response is appropriate message, | ||
367 | * or NACK in case of inability to satisfy request. | ||
368 | */ | ||
369 | struct ti_sci_msg_req_query_clock_freq { | ||
370 | struct ti_sci_msg_hdr hdr; | ||
371 | u32 dev_id; | ||
372 | u64 min_freq_hz; | ||
373 | u64 target_freq_hz; | ||
374 | u64 max_freq_hz; | ||
375 | u8 clk_id; | ||
376 | } __packed; | ||
377 | |||
378 | /** | ||
379 | * struct ti_sci_msg_resp_query_clock_freq - Response to a clock frequency query | ||
380 | * @hdr: Generic Header | ||
381 | * @freq_hz: Frequency that is the best match in Hz. | ||
382 | * | ||
383 | * Response to request type TI_SCI_MSG_QUERY_CLOCK_FREQ. NOTE: if the request | ||
384 | * cannot be satisfied, the message will be of type NACK. | ||
385 | */ | ||
386 | struct ti_sci_msg_resp_query_clock_freq { | ||
387 | struct ti_sci_msg_hdr hdr; | ||
388 | u64 freq_hz; | ||
389 | } __packed; | ||
390 | |||
391 | /** | ||
392 | * struct ti_sci_msg_req_set_clock_freq - Request to setup a clock frequency | ||
393 | * @hdr: Generic Header | ||
394 | * @dev_id: Device identifier this request is for | ||
395 | * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum | ||
396 | * allowable programmed frequency and does not account for clock | ||
397 | * tolerances and jitter. | ||
398 | * @target_freq_hz: The target clock frequency. The clock will be programmed | ||
399 | * at a rate as close to this target frequency as possible. | ||
400 | * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum | ||
401 | * allowable programmed frequency and does not account for clock | ||
402 | * tolerances and jitter. | ||
403 | * @clk_id: Clock identifier for the device for this request. | ||
404 | * | ||
405 | * NOTE: Normally clock frequency management is automatically done by TISCI | ||
406 | * entity. In case of specific requests, TISCI evaluates capability to achieve | ||
407 | * requested range and responds with success/failure message. | ||
408 | * | ||
409 | * This sets the desired frequency for a clock within an allowable | ||
410 | * range. This message will fail on an enabled clock unless | ||
411 | * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally, | ||
412 | * if other clocks have their frequency modified due to this message, | ||
413 | * they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled. | ||
414 | * | ||
415 | * Calling set frequency on a clock input to the SoC pseudo-device will | ||
416 | * inform the PMMC of that clock's frequency. Setting a frequency of | ||
417 | * zero will indicate the clock is disabled. | ||
418 | * | ||
419 | * Calling set frequency on clock outputs from the SoC pseudo-device will | ||
420 | * function similarly to setting the clock frequency on a device. | ||
421 | * | ||
422 | * Request type is TI_SCI_MSG_SET_CLOCK_FREQ, response is a generic ACK/NACK | ||
423 | * message. | ||
424 | */ | ||
425 | struct ti_sci_msg_req_set_clock_freq { | ||
426 | struct ti_sci_msg_hdr hdr; | ||
427 | u32 dev_id; | ||
428 | u64 min_freq_hz; | ||
429 | u64 target_freq_hz; | ||
430 | u64 max_freq_hz; | ||
431 | u8 clk_id; | ||
432 | } __packed; | ||
433 | |||
434 | /** | ||
435 | * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency | ||
436 | * @hdr: Generic Header | ||
437 | * @dev_id: Device identifier this request is for | ||
438 | * @clk_id: Clock identifier for the device for this request. | ||
439 | * | ||
440 | * NOTE: Normally clock frequency management is automatically done by TISCI | ||
441 | * entity. In some cases, clock frequencies are configured by host. | ||
442 | * | ||
443 | * Request type is TI_SCI_MSG_GET_CLOCK_FREQ, responded with clock frequency | ||
444 | * that the clock is currently at. | ||
445 | */ | ||
446 | struct ti_sci_msg_req_get_clock_freq { | ||
447 | struct ti_sci_msg_hdr hdr; | ||
448 | u32 dev_id; | ||
449 | u8 clk_id; | ||
450 | } __packed; | ||
451 | |||
452 | /** | ||
453 | * struct ti_sci_msg_resp_get_clock_freq - Response of clock frequency request | ||
454 | * @hdr: Generic Header | ||
455 | * @freq_hz: Frequency that the clock is currently on, in Hz. | ||
456 | * | ||
457 | * Response to request type TI_SCI_MSG_GET_CLOCK_FREQ. | ||
458 | */ | ||
459 | struct ti_sci_msg_resp_get_clock_freq { | ||
460 | struct ti_sci_msg_hdr hdr; | ||
461 | u64 freq_hz; | ||
462 | } __packed; | ||
463 | |||
175 | #endif /* __TI_SCI_H */ | 464 | #endif /* __TI_SCI_H */ |
diff --git a/include/linux/ti_sci_protocol.h b/include/linux/ti_sci_protocol.h index 4aa4c93dc78e..a7e25c651f3e 100644 --- a/include/linux/ti_sci_protocol.h +++ b/include/linux/ti_sci_protocol.h | |||
@@ -104,11 +104,89 @@ struct ti_sci_dev_ops { | |||
104 | }; | 104 | }; |
105 | 105 | ||
106 | /** | 106 | /** |
107 | * struct ti_sci_clk_ops - Clock control operations | ||
108 | * @get_clock: Request for activation of clock and manage by processor | ||
109 | * - needs_ssc: 'true' if Spread Spectrum clock is desired. | ||
110 | * - can_change_freq: 'true' if frequency change is desired. | ||
111 | * - enable_input_term: 'true' if input termination is desired. | ||
112 | * @idle_clock: Request for Idling a clock managed by processor | ||
113 | * @put_clock: Release the clock to be auto managed by TISCI | ||
114 | * @is_auto: Is the clock being auto managed | ||
115 | * - req_state: state indicating if the clock is auto managed | ||
116 | * @is_on: Is the clock ON | ||
117 | * - req_state: if the clock is requested to be forced ON | ||
118 | * - current_state: if the clock is currently ON | ||
119 | * @is_off: Is the clock OFF | ||
120 | * - req_state: if the clock is requested to be forced OFF | ||
121 | * - current_state: if the clock is currently Gated | ||
122 | * @set_parent: Set the clock source of a specific device clock | ||
123 | * - parent_id: Parent clock identifier to set. | ||
124 | * @get_parent: Get the current clock source of a specific device clock | ||
125 | * - parent_id: Parent clock identifier which is the parent. | ||
126 | * @get_num_parents: Get the number of parents of the current clock source | ||
127 | * - num_parents: returns the number of parent clocks. | ||
128 | * @get_best_match_freq: Find a best matching frequency for a frequency | ||
129 | * range. | ||
130 | * - match_freq: Best matching frequency in Hz. | ||
131 | * @set_freq: Set the Clock frequency | ||
132 | * @get_freq: Get the Clock frequency | ||
133 | * - current_freq: Frequency in Hz that the clock is at. | ||
134 | * | ||
135 | * NOTE: for all these functions, the following parameters are generic in | ||
136 | * nature: | ||
137 | * -handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle | ||
138 | * -did: Device identifier this request is for | ||
139 | * -cid: Clock identifier for the device for this request. | ||
140 | * Each device has it's own set of clock inputs. This indexes | ||
141 | * which clock input to modify. | ||
142 | * -min_freq: The minimum allowable frequency in Hz. This is the minimum | ||
143 | * allowable programmed frequency and does not account for clock | ||
144 | * tolerances and jitter. | ||
145 | * -target_freq: The target clock frequency in Hz. A frequency will be | ||
146 | * processed as close to this target frequency as possible. | ||
147 | * -max_freq: The maximum allowable frequency in Hz. This is the maximum | ||
148 | * allowable programmed frequency and does not account for clock | ||
149 | * tolerances and jitter. | ||
150 | * | ||
151 | * Request for the clock - NOTE: the client MUST maintain integrity of | ||
152 | * usage count by balancing get_clock with put_clock. No refcounting is | ||
153 | * managed by driver for that purpose. | ||
154 | */ | ||
155 | struct ti_sci_clk_ops { | ||
156 | int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
157 | bool needs_ssc, bool can_change_freq, | ||
158 | bool enable_input_term); | ||
159 | int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid); | ||
160 | int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid); | ||
161 | int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
162 | bool *req_state); | ||
163 | int (*is_on)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
164 | bool *req_state, bool *current_state); | ||
165 | int (*is_off)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
166 | bool *req_state, bool *current_state); | ||
167 | int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
168 | u8 parent_id); | ||
169 | int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
170 | u8 *parent_id); | ||
171 | int (*get_num_parents)(const struct ti_sci_handle *handle, u32 did, | ||
172 | u8 cid, u8 *num_parents); | ||
173 | int (*get_best_match_freq)(const struct ti_sci_handle *handle, u32 did, | ||
174 | u8 cid, u64 min_freq, u64 target_freq, | ||
175 | u64 max_freq, u64 *match_freq); | ||
176 | int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
177 | u64 min_freq, u64 target_freq, u64 max_freq); | ||
178 | int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid, | ||
179 | u64 *current_freq); | ||
180 | }; | ||
181 | |||
182 | /** | ||
107 | * struct ti_sci_ops - Function support for TI SCI | 183 | * struct ti_sci_ops - Function support for TI SCI |
108 | * @dev_ops: Device specific operations | 184 | * @dev_ops: Device specific operations |
185 | * @clk_ops: Clock specific operations | ||
109 | */ | 186 | */ |
110 | struct ti_sci_ops { | 187 | struct ti_sci_ops { |
111 | struct ti_sci_dev_ops dev_ops; | 188 | struct ti_sci_dev_ops dev_ops; |
189 | struct ti_sci_clk_ops clk_ops; | ||
112 | }; | 190 | }; |
113 | 191 | ||
114 | /** | 192 | /** |