diff --git a/hw/platform/ioc.c b/hw/platform/ioc.c index 8a2b1b804..c12aeb0ab 100644 --- a/hw/platform/ioc.c +++ b/hw/platform/ioc.c @@ -968,6 +968,7 @@ ioc_rx_thread(void *arg) memset(&packet, 0, sizeof(packet)); packet.cfg = &ioc->rx_config; + packet.boot_reason = ioc_boot_reason; for (;;) { pthread_mutex_lock(&ioc->rx_mtx); while (SIMPLEQ_EMPTY(&ioc->rx_qhead)) { @@ -1019,6 +1020,7 @@ ioc_tx_thread(void *arg) memset(&packet, 0, sizeof(packet)); packet.cfg = &ioc->tx_config; + packet.boot_reason = ioc_boot_reason; for (;;) { pthread_mutex_lock(&ioc->tx_mtx); while (SIMPLEQ_EMPTY(&ioc->tx_qhead)) { diff --git a/hw/platform/ioc_cbc.c b/hw/platform/ioc_cbc.c index ed56fb9c7..a15c6e0b4 100644 --- a/hw/platform/ioc_cbc.c +++ b/hw/platform/ioc_cbc.c @@ -346,6 +346,40 @@ cbc_send_pkt(struct cbc_pkt *pkt) DPRINTF("ioc xmit failed on channel id=%d\n\r", id); } +/* + * Update heartbeat state. + */ +static void +cbc_update_heartbeat(struct cbc_pkt *pkt, uint8_t cmd, uint8_t sus_action) +{ + uint8_t stat; + + (void) sus_action; + + /* + * If heartbeat state switches(active/inactive), update the new state + * value based on heartbeat commands. + * The default state is inactive. + */ + if (cmd == CBC_HB_ACTIVE || cmd == CBC_HB_STANDBY || + cmd == CBC_HB_INITIAL) + stat = 1; + else + stat = 0; + + /* Default heartbeat state is zero, that means not active */ + if (stat != pkt->hb_state) { + /* + * Route the cbc request to the tx thread + * and request type is SOC state update + */ + pkt->qtype = CBC_QUEUE_T_TX; + pkt->req->rtype = CBC_REQ_T_SOC; + pkt->req->buf[0] = stat; + pkt->hb_state = stat; + } +} + /* * Update wakeup reason value and notify UOS immediately. * Some events can change the wakeup reason include periodic wakeup reason @@ -355,6 +389,37 @@ cbc_send_pkt(struct cbc_pkt *pkt) static void cbc_update_wakeup_reason(struct cbc_pkt *pkt, uint32_t reason) { + uint8_t *payload; + + /* TODO: VMM requests S3/S5 do not implement yet */ + if (pkt->soc_active) { + pkt->boot_reason = 0; + reason |= CBC_WK_RSN_SOC; + } else + reason &= ~CBC_WK_RSN_SOC; + reason &= CBC_WK_RSN_ALL; + + if (pkt->boot_reason != 0) + reason = pkt->boot_reason; + + pkt->reason = reason; + + /* Wakeup reason only has three bytes in CBC payload */ + payload = pkt->req->buf + CBC_PAYLOAD_POS; + payload[0] = reason; + payload[1] = reason >> 8; + payload[2] = reason >> 16; + + /* For CBC address layer header packing */ + pkt->req->id = IOC_NATIVE_LFCC; + + /* Fill service header */ + pkt->req->buf[CBC_SRV_POS] = CBC_SC_WK_RSN; + pkt->req->srv_len = 4; + pkt->req->link_len = 0; + + /* Send the CBC packet */ + cbc_send_pkt(pkt); } /* @@ -364,6 +429,25 @@ cbc_update_wakeup_reason(struct cbc_pkt *pkt, uint32_t reason) static void cbc_process_lifecycle(struct cbc_pkt *pkt) { + uint8_t cmd; + uint8_t *payload; + uint32_t reason; + + cmd = pkt->req->buf[CBC_SRV_POS]; + payload = pkt->req->buf + CBC_PAYLOAD_POS; + switch (cmd) { + case CBC_SC_WK_RSN: + reason = payload[0] | (payload[1] << 8) | (payload[2] << 16); + cbc_update_wakeup_reason(pkt, reason); + break; + case CBC_SC_HB: + cbc_update_heartbeat(pkt, payload[0], payload[1]); + break; + default: + DPRINTF("ioc lifecycle command=%d can not be handled\r\n", + cmd); + break; + } } /* diff --git a/include/ioc.h b/include/ioc.h index f428ef36b..815b530b6 100644 --- a/include/ioc.h +++ b/include/ioc.h @@ -662,6 +662,7 @@ struct cbc_pkt { uint8_t soc_active; /* Record soc state */ uint8_t hb_state; /* Record Heartbeat state */ uint32_t reason; /* Record current wakeup reason */ + uint32_t boot_reason; /* Record boot up wakeup reason */ struct cbc_request *req; /* CBC packet data */ struct cbc_config *cfg; /* CBC and whitelist configurations */ enum cbc_queue_type qtype; /* Routes cbc_request to queue */