Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2015, The Linux Foundation. All rights reserved. |
| 2 | * |
| 3 | * Redistribution and use in source and binary forms, with or without |
| 4 | * modification, are permitted provided that the following conditions are |
| 5 | * met: |
| 6 | * * Redistributions of source code must retain the above copyright |
| 7 | * notice, this list of conditions and the following disclaimer. |
| 8 | * * Redistributions in binary form must reproduce the above |
| 9 | * copyright notice, this list of conditions and the following |
| 10 | * disclaimer in the documentation and/or other materials provided |
| 11 | * with the distribution. |
| 12 | * * Neither the name of The Linux Fundation, Inc. nor the names of its |
| 13 | * contributors may be used to endorse or promote products derived |
| 14 | * from this software without specific prior written permission. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 23 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| 25 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| 26 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | * |
| 28 | */ |
| 29 | |
| 30 | #include <rpm-glink.h> |
| 31 | #include <smd.h> |
| 32 | #include <glink.h> |
| 33 | #include <glink_rpm.h> |
| 34 | #include <xport_rpm.h> |
| 35 | #include <stdint.h> |
| 36 | #include <sys/types.h> |
| 37 | #include <arch/defines.h> |
| 38 | #include <debug.h> |
| 39 | #include <stdlib.h> |
| 40 | #include <platform/timer.h> |
| 41 | #include <platform/interrupts.h> |
| 42 | #include <platform/clock.h> |
| 43 | #include <platform/iomap.h> |
| 44 | #include <platform/irqs.h> |
| 45 | #include <pm8x41.h> |
| 46 | #include <kernel/event.h> |
| 47 | |
| 48 | #define RPM_REQ_MAGIC 0x00716572 |
| 49 | #define RPM_CMD_MAGIC 0x00646d63 |
| 50 | #define REQ_MSG_LENGTH 0x14 |
| 51 | #define CMD_MSG_LENGTH 0x08 |
| 52 | #define ACK_MSG_LENGTH 0x0C |
| 53 | |
| 54 | glink_handle_type rpm_glink_port, ssr_glink_port; |
| 55 | static uint32_t msg_id; |
Sridhar Parasuram | bd9c518 | 2015-05-22 17:06:40 -0700 | [diff] [blame] | 56 | static event_t wait_for_rpm_init; |
| 57 | static event_t wait_for_ssr_init; |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 58 | static event_t wait_for_data; |
| 59 | |
| 60 | extern glink_err_type glink_wait_link_down(glink_handle_type handle); |
| 61 | |
| 62 | glink_err_type rpm_glink_send_data(uint32_t *data, uint32_t len, msg_type type) |
| 63 | { |
| 64 | rpm_req req; |
| 65 | rpm_cmd cmd; |
| 66 | glink_err_type send_err = 0; |
| 67 | uint32_t len_to_rpm = 0; |
| 68 | void *rpm_data = NULL; |
| 69 | event_init(&wait_for_data, false, EVENT_FLAG_AUTOUNSIGNAL); |
| 70 | |
| 71 | switch(type) |
| 72 | { |
| 73 | case RPM_REQUEST_TYPE: |
| 74 | req.hdr.type = RPM_REQ_MAGIC; |
| 75 | req.hdr.len = len + REQ_MSG_LENGTH;//20 |
| 76 | req.req_hdr.id = ++msg_id; |
| 77 | req.req_hdr.set = 0; |
| 78 | req.req_hdr.resourceType = data[RESOURCETYPE]; |
| 79 | req.req_hdr.resourceId = data[RESOURCEID]; |
| 80 | req.req_hdr.dataLength = len; |
| 81 | |
| 82 | fill_kvp_object(&req.data, data, len); |
| 83 | len_to_rpm = req.req_hdr.dataLength + 0x28; |
| 84 | |
| 85 | rpm_data = (void*) malloc(len_to_rpm); |
| 86 | ASSERT(rpm_data); |
| 87 | memset(rpm_data, 0, len_to_rpm); |
| 88 | memcpy(rpm_data, &req.hdr, sizeof(rpm_gen_hdr)); |
| 89 | memcpy(rpm_data + sizeof(rpm_gen_hdr), &req.req_hdr, sizeof(rpm_req_hdr)); |
| 90 | memcpy(rpm_data + sizeof(rpm_gen_hdr)+ sizeof(rpm_req_hdr), req.data, len); |
| 91 | |
| 92 | // Send Data Request to RPM |
| 93 | send_err = glink_tx(rpm_glink_port, NULL, (const void *)rpm_data, len_to_rpm, 0); |
| 94 | if (send_err) |
| 95 | { |
Sridhar Parasuram | 06fdde4 | 2015-05-22 10:37:36 -0700 | [diff] [blame] | 96 | dprintf(CRITICAL, "%s:%d, Glink tx error: 0x%x\n", __func__, __LINE__, send_err); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 97 | free(rpm_data); |
| 98 | free_kvp_object(&req.data); |
| 99 | break; |
| 100 | } |
| 101 | #ifdef DEBUG_GLINK |
| 102 | dprintf(INFO, "%s:%d, Wait till we receive response from RPM\n", __func__, __LINE__); |
| 103 | #endif |
| 104 | event_wait(&wait_for_data); |
| 105 | free(rpm_data); |
| 106 | free_kvp_object(&req.data); |
| 107 | break; |
| 108 | case RPM_CMD_TYPE: |
| 109 | cmd.hdr.type = RPM_CMD_MAGIC; |
| 110 | cmd.hdr.len = CMD_MSG_LENGTH;//0x8; |
| 111 | len_to_rpm = sizeof(rpm_cmd); |
| 112 | |
| 113 | fill_kvp_object(&cmd.data, data, len); |
| 114 | send_err = glink_tx(rpm_glink_port, NULL, (const void *)&cmd, len_to_rpm, 0); |
| 115 | if (send_err) |
Sridhar Parasuram | 06fdde4 | 2015-05-22 10:37:36 -0700 | [diff] [blame] | 116 | dprintf(CRITICAL, "%s:%d, Glink tx error: 0x%x\n", __func__, __LINE__, send_err); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 117 | free_kvp_object(&cmd.data); |
| 118 | break; |
| 119 | default: |
| 120 | dprintf(CRITICAL, "Invalid RPM Request\n"); |
| 121 | break; |
| 122 | } |
| 123 | |
| 124 | return send_err; |
| 125 | } |
| 126 | |
| 127 | uint32_t rpm_glink_recv_data(char *rx_buffer, uint32_t* len) |
| 128 | { |
| 129 | rpm_ack_msg *resp; |
| 130 | msg_type type = 0; |
| 131 | uint32_t ret = 0; |
| 132 | /* As per the current design rpm response does not exceed 20 bytes */ |
| 133 | if (rx_buffer == NULL) |
| 134 | { |
| 135 | dprintf(CRITICAL, "Invalid pointer to data received from RPM\n"); |
| 136 | return 99; |
| 137 | } |
| 138 | resp = (rpm_ack_msg *)rx_buffer; |
| 139 | |
| 140 | arch_invalidate_cache_range((addr_t)resp, sizeof(rpm_gen_hdr)); |
| 141 | |
| 142 | if(resp->hdr.type == RPM_CMD_MAGIC) |
| 143 | { |
| 144 | type = RPM_CMD_TYPE; |
| 145 | } |
| 146 | else if(resp->hdr.type == RPM_REQ_MAGIC) |
| 147 | { |
| 148 | type = RPM_REQUEST_TYPE; |
| 149 | } |
| 150 | |
| 151 | if (type == RPM_CMD_TYPE && resp->hdr.len == ACK_MSG_LENGTH) |
| 152 | { |
| 153 | dprintf(SPEW, "Received SUCCESS CMD ACK\n"); |
| 154 | } |
| 155 | else if (type == RPM_REQUEST_TYPE && resp->hdr.len == ACK_MSG_LENGTH) |
| 156 | { |
| 157 | dprintf(SPEW, "Received SUCCESS REQ ACK \n"); |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | ret = 1; |
| 162 | dprintf(CRITICAL, "Received ERROR ACK \n"); |
| 163 | } |
| 164 | |
| 165 | if(!ret) |
| 166 | { |
| 167 | ret = sizeof(rpm_gen_hdr) + sizeof(kvp_data); |
| 168 | } |
| 169 | #ifdef DEBUG_GLINK |
| 170 | dprintf(INFO, "%s:%d Return value %u\n", __func__, __LINE__, ret); |
| 171 | #endif |
| 172 | return ret; |
| 173 | } |
| 174 | |
| 175 | void rpm_vector_glink_ssr_isr(glink_handle_type port, void *unused_open_data, void *unused_pkt_priv, |
| 176 | void *buffer, size_t size, size_t intent_used, |
| 177 | glink_buffer_provider_fn vprovider, glink_buffer_provider_fn pprovider) |
| 178 | { |
| 179 | char rx_buffer[12]; |
| 180 | char *return_buffer = NULL; |
| 181 | uint32_t ret = 0; |
| 182 | uint32_t offset = 0; |
| 183 | size_t return_size = 0; |
| 184 | |
| 185 | #ifdef DEBUG_GLINK |
| 186 | dprintf(INFO, "RPM Vector GLINK SSR ISR\n"); |
| 187 | #endif |
| 188 | if (size == 0) |
| 189 | { |
| 190 | dprintf(CRITICAL, "Invalid size of RPM response\n"); |
| 191 | ASSERT(0); |
| 192 | } |
| 193 | if (size > sizeof(rx_buffer)) |
| 194 | { |
| 195 | dprintf(CRITICAL, "Need larger RPM rx buffer. Size of Local Buffer: %u\tSize of RX Buffer: %u\n", size, sizeof(rx_buffer)); |
| 196 | ASSERT(0); |
| 197 | } |
| 198 | do |
| 199 | { |
| 200 | return_buffer = vprovider(buffer, offset, &return_size); |
| 201 | if(return_buffer) |
| 202 | { |
| 203 | memcpy(rx_buffer+offset,return_buffer, return_size); |
| 204 | offset += return_size; |
| 205 | } |
| 206 | } while(return_buffer); |
| 207 | ret = rpm_glink_recv_data(rx_buffer,(uint32_t *)&size); |
| 208 | if(ret) |
| 209 | { |
| 210 | dprintf(CRITICAL, "Return value from recv_data: %x\n", ret); |
| 211 | } |
| 212 | // Release the mutex |
| 213 | #ifdef DEBUG_GLINK |
| 214 | dprintf(INFO, "Received Data from RPM\n"); |
| 215 | #endif |
| 216 | event_signal(&wait_for_data, false); |
| 217 | } |
| 218 | |
| 219 | void rpm_vector_glink_isr(glink_handle_type port, void *unused_open_data, void *unused_pkt_priv, |
| 220 | void *buffer, size_t size, size_t intent_used, |
| 221 | glink_buffer_provider_fn vprovider, glink_buffer_provider_fn pprovider) |
| 222 | { |
| 223 | char rx_buffer[64]; |
| 224 | char *return_buffer = NULL; |
| 225 | uint32_t ret = 0; |
| 226 | uint32_t offset = 0; |
| 227 | size_t return_size = 0; |
| 228 | #ifdef DEBUG_GLINK |
| 229 | dprintf(INFO, "RPM Vector GLINK ISR\n"); |
| 230 | #endif |
| 231 | if (size == 0) |
| 232 | { |
| 233 | dprintf(CRITICAL, "Invalid size of RPM response\n"); |
| 234 | ASSERT(0); |
| 235 | } |
| 236 | if (size > sizeof(rx_buffer)) |
| 237 | { |
| 238 | dprintf(CRITICAL, "Need larger RPM rx buffer. Size of Local Buffer: %u\tSize of RX Buffer: %u\n", size, sizeof(rx_buffer)); |
| 239 | ASSERT(0); |
| 240 | } |
| 241 | do |
| 242 | { |
| 243 | return_buffer = vprovider(buffer, offset, &return_size); |
| 244 | if(return_buffer) |
| 245 | { |
| 246 | memcpy(rx_buffer+offset,return_buffer, return_size); |
| 247 | offset += return_size; |
| 248 | } |
| 249 | } while(return_buffer); |
| 250 | ret = rpm_glink_recv_data(rx_buffer, (uint32_t *)&size); |
| 251 | if(ret) |
| 252 | { |
| 253 | dprintf(CRITICAL, "Return value from recv_data: %x\n", ret); |
| 254 | } |
| 255 | // Release the mutex |
| 256 | #ifdef DEBUG_GLINK |
| 257 | dprintf(INFO, "Received Data from RPM\n"); |
| 258 | #endif |
| 259 | event_signal(&wait_for_data, false); |
| 260 | } |
| 261 | |
| 262 | void rpm_glink_notify_state_isr(glink_handle_type handle, void *data, glink_channel_event_type event) |
| 263 | { |
| 264 | if(event == GLINK_CONNECTED) |
| 265 | { |
Sridhar Parasuram | bd9c518 | 2015-05-22 17:06:40 -0700 | [diff] [blame] | 266 | event_signal(&wait_for_rpm_init, false); |
| 267 | dprintf(INFO, "Glink Connection between APPS and RPM established\n"); |
| 268 | return; |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | void rpm_glink_notify_state_ssr_isr(glink_handle_type handle, void *data, glink_channel_event_type event) |
| 273 | { |
| 274 | if(event == GLINK_CONNECTED) |
| 275 | { |
| 276 | event_signal(&wait_for_ssr_init, false); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 277 | dprintf(INFO, "Glink Connection between APPS and RPM established\n"); |
| 278 | return; |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | void rpm_glink_tx_done_isr(void) |
| 283 | { |
| 284 | //empty function for tx_done cb. Nothing required here for now since we are always in |
| 285 | //"single-threaded" operation of sending GLink requests |
| 286 | return; |
| 287 | } |
| 288 | |
| 289 | void rpm_glink_open(glink_link_info_type *link_info, void* priv) |
| 290 | { |
| 291 | glink_err_type ret; |
| 292 | glink_open_config_type glink_open_cfg = {0}, glink_ssr_open_cfg = {0}; |
| 293 | |
| 294 | // Open channel for tx |
| 295 | glink_open_cfg.name = "rpm_requests"; |
| 296 | glink_open_cfg.remote_ss = link_info->remote_ss; |
| 297 | glink_open_cfg.notify_rx = NULL; |
| 298 | glink_open_cfg.notify_rxv = (glink_rxv_notification_cb)rpm_vector_glink_isr; |
| 299 | glink_open_cfg.notify_tx_done = (glink_tx_notification_cb)rpm_glink_tx_done_isr; |
| 300 | glink_open_cfg.notify_state = (glink_state_notification_cb)rpm_glink_notify_state_isr; |
| 301 | glink_open_cfg.priv = NULL; |
| 302 | ret = glink_open(&glink_open_cfg, &rpm_glink_port); |
| 303 | if (ret == GLINK_STATUS_SUCCESS) |
| 304 | dprintf(INFO, "Opening RPM Glink Port success\n"); |
| 305 | else |
| 306 | { |
| 307 | dprintf(CRITICAL, "Opening RPM Glink Port failure %d\n", ret); |
| 308 | ASSERT(0); |
| 309 | } |
| 310 | |
| 311 | // Open Channel for tear down |
| 312 | glink_ssr_open_cfg.name = "glink_ssr"; |
| 313 | glink_ssr_open_cfg.remote_ss = link_info->remote_ss; |
| 314 | glink_ssr_open_cfg.notify_rx = NULL; |
| 315 | glink_ssr_open_cfg.notify_rxv = (glink_rxv_notification_cb)rpm_vector_glink_ssr_isr; |
| 316 | glink_ssr_open_cfg.notify_tx_done = (glink_tx_notification_cb)rpm_glink_tx_done_isr; |
Sridhar Parasuram | bd9c518 | 2015-05-22 17:06:40 -0700 | [diff] [blame] | 317 | glink_ssr_open_cfg.notify_state = (glink_state_notification_cb)rpm_glink_notify_state_ssr_isr; |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 318 | glink_ssr_open_cfg.priv = NULL; |
| 319 | |
| 320 | ret = glink_open(&glink_ssr_open_cfg, &ssr_glink_port); |
| 321 | if (ret == GLINK_STATUS_SUCCESS) |
| 322 | dprintf(INFO, "Opening SSR Glink Port success\n"); |
| 323 | else |
| 324 | { |
| 325 | dprintf(CRITICAL, "Opening SSR Glink Port failure %d\n", ret); |
| 326 | ASSERT(0); |
| 327 | } |
| 328 | |
| 329 | } |
| 330 | |
| 331 | void rpm_glink_init() |
| 332 | { |
| 333 | glink_err_type ret; |
| 334 | glink_link_id_type link_id; |
Sridhar Parasuram | bd9c518 | 2015-05-22 17:06:40 -0700 | [diff] [blame] | 335 | event_init(&wait_for_rpm_init, false, EVENT_FLAG_AUTOUNSIGNAL); |
| 336 | event_init(&wait_for_ssr_init, false, EVENT_FLAG_AUTOUNSIGNAL); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 337 | |
| 338 | dprintf(INFO, "RPM GLink Init\n"); |
| 339 | // Initialize RPM transport |
| 340 | ret = xport_rpm_init(NULL); |
| 341 | if (ret == GLINK_STATUS_SUCCESS) |
| 342 | { |
| 343 | unmask_interrupt(GLINK_IPC_IRQ); |
| 344 | GLINK_LINK_ID_STRUCT_INIT(link_id); |
| 345 | link_id.remote_ss = "rpm"; |
| 346 | link_id.link_notifier = (glink_link_state_notif_cb)rpm_glink_open; |
| 347 | glink_register_link_state_cb(&link_id, NULL); |
| 348 | } |
| 349 | else |
| 350 | { |
Sridhar Parasuram | 06fdde4 | 2015-05-22 10:37:36 -0700 | [diff] [blame] | 351 | dprintf(CRITICAL, "RPM Glink Init Failure 0x%x\n", ret); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 352 | ASSERT(0); |
| 353 | } |
Sridhar Parasuram | bd9c518 | 2015-05-22 17:06:40 -0700 | [diff] [blame] | 354 | event_wait(&wait_for_rpm_init); |
| 355 | event_wait(&wait_for_ssr_init); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | void rpm_glink_uninit() |
| 359 | { |
| 360 | rpm_ssr_req req; |
| 361 | glink_err_type ret; |
| 362 | uint32_t len_to_rpm, loop = 100000; |
| 363 | |
| 364 | // update ssr request |
| 365 | req.version = 0; |
| 366 | req.cmd = 0; |
| 367 | req.seqnumber = 0; |
| 368 | memset(req.name, 0, sizeof(req.name)); |
| 369 | strncpy(req.name, "apss", 4); |
| 370 | req.namelength = strlen(req.name); |
| 371 | len_to_rpm = sizeof(rpm_ssr_req); |
| 372 | dprintf(INFO, "RPM GLINK UnInit\n"); |
| 373 | ret = glink_tx(ssr_glink_port, NULL, (const void *)&req, len_to_rpm, 0); |
| 374 | |
| 375 | if (ret) |
| 376 | { |
Sridhar Parasuram | 06fdde4 | 2015-05-22 10:37:36 -0700 | [diff] [blame] | 377 | dprintf(CRITICAL, "Glink SSR Channel: Tx for link tear down request failure with error code: 0x%x\n", ret); |
Sridhar Parasuram | a4e4fc8 | 2015-02-17 14:36:53 -0800 | [diff] [blame] | 378 | ASSERT(0); |
| 379 | } |
| 380 | |
| 381 | #ifdef DEBUG_GLINK |
| 382 | dprintf(INFO, "%s:%d, Wait till we receive response from RPM\n", __func__, __LINE__); |
| 383 | #endif |
| 384 | // loop till the FIFO indices are cleared |
| 385 | while((ret = glink_wait_link_down(ssr_glink_port)) && loop) |
| 386 | { |
| 387 | loop--; |
| 388 | mdelay(1); |
| 389 | continue; |
| 390 | } |
| 391 | if (!loop) |
| 392 | { |
| 393 | dprintf(INFO, "%s:%d, Tearing down Glink SSR Channel Timed out\n", __func__, __LINE__); |
| 394 | ASSERT(0); |
| 395 | } |
| 396 | } |