| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- /* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <rtthread.h>
- #include <rthw.h>
- #include <stdio.h>
- #include "sysctl_pwr.h"
- #include "drv_hardlock.h"
- #include "ioremap.h"
- #include "board.h"
- volatile sysctl_pwr_s* sysctl_pwr = (volatile sysctl_pwr_s*)PWR_BASE_ADDR;
- /*****************************************************************************************
- * SET POWER DOMAIN'S TIME
- * powerdomain:power domain
- * timtype: idleReq_to_idleAck, idleAck_to_idle.....
- * tim_value: ack_to_tim, idle_to_tim......
- *****************************************************************************************/
- /* ack timeout value, lpi idleReq to idleAck */
- bool sysctl_pwr_set_ack_to_tim(volatile uint32_t *reg, uint32_t ack_to_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (ack_to_tim > 0x1F))
- return false;
- else
- {
- *ret &= 0xffffffe0;
- *reg = (*ret) | (ack_to_tim << 0);
- return true;
- }
- }
- /* idle timeout value, lpi idleAck to idle */
- bool sysctl_pwr_set_idle_to_tim(volatile uint32_t *reg, uint32_t idle_to_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (idle_to_tim > 0x1F))
- return false;
- else
- {
- *ret &= 0xffffe0ff;
- *reg = (*ret) | (idle_to_tim << 8);
- return true;
- }
- }
- /* NOC power controller in idle min time, idle to idelReq(inactive) */
- bool sysctl_pwr_set_idle_hd_tim(volatile uint32_t *reg, uint32_t idle_hd_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (idle_hd_tim > 0x3F))
- return false;
- else
- {
- *ret &= 0xffc0ffff;
- *reg = (*ret) | (idle_hd_tim << 16);
- return true;
- }
- }
- /*
- * After turning ISO on/off, you need to wait for a while to ensure that the
- * isolation cells in the power domain are actually enabled/disabled.
- */
- bool sysctl_pwr_set_iso_su_tim(volatile uint32_t *reg, uint32_t iso_su_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (iso_su_tim > 0xF))
- return false;
- else
- {
- *ret &= 0xfffffff0;
- *reg = (*ret) | (iso_su_tim << 0);
- return true;
- }
- }
- /*
- * After powering off a power domain, it takes some time to exit the
- * power-off state.
- */
- bool sysctl_pwr_set_pd_hd_tim(volatile uint32_t *reg, uint32_t pd_hd_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (pd_hd_tim > 0xFF))
- return false;
- else
- {
- *ret &= 0xfffff00f;
- *reg = (*ret) | (pd_hd_tim << 4);
- return true;
- }
- }
- /*
- * After restoring the power supply of a power domain (bringup), you need to
- * wait for a period of time to ensure that the power supply of the power domain
- * is fully restored.
- */
- bool sysctl_pwr_set_pwr_su_tim(volatile uint32_t *reg, uint32_t pwr_su_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (pwr_su_tim > 0xFF))
- return false;
- else
- {
- *ret &= 0xfff00fff;
- *reg = (*ret) | (pwr_su_tim << 12);
- return true;
- }
- }
- /* set cpu1 wait for interrupt time */
- bool sysctl_pwr_set_wfi_tim(volatile uint32_t *reg, uint32_t wfi_tim)
- {
- volatile uint32_t *ret = reg;
- if((NULL == reg) || (wfi_tim > 0xFFF))
- return false;
- else
- {
- *ret &= 0x000fffff;
- *reg = (*ret) | (wfi_tim << 20);
- return true;
- }
- }
- bool sysctl_pwr_set_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t tim_value)
- {
- volatile uint32_t *pwr_reg = NULL;
- volatile uint32_t *lpi_reg = NULL;
- volatile uint32_t *wfi_reg = NULL;
- if((powerdomain >= SYSCTL_PD_MAX) || (timtype >= SYSCTL_PWR_MAX_TIM))
- return false;
- switch(powerdomain)
- {
- case SYSCTL_PD_CPU1:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_lpi_tim;
- wfi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
- break;
- }
- case SYSCTL_PD_AI:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->ai_lpi_tim;
- break;
- }
- case SYSCTL_PD_DISP:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->disp_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_tim;
- break;
- }
- case SYSCTL_PD_VPU:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_tim;
- break;
- }
- case SYSCTL_PD_DPU:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->dpu_lpi_tim;
- break;
- }
- default:
- return false;
- }
- switch(timtype)
- {
- case SYSCTL_PWR_ACK_TO_TIM:
- return sysctl_pwr_set_ack_to_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_IDLE_TO_TIM:
- return sysctl_pwr_set_idle_to_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_IDLE_HD_TIM:
- return sysctl_pwr_set_idle_hd_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_ISO_SU_TIM:
- return sysctl_pwr_set_iso_su_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_PD_HD_TIM:
- return sysctl_pwr_set_pd_hd_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_SU_TIM:
- return sysctl_pwr_set_pwr_su_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_WFI_TIM:
- return sysctl_pwr_set_wfi_tim(wfi_reg,tim_value);
- default:
- return false;
- }
- }
- /*****************************************************************************************
- * GET POWER DOMAIN'S TIME
- * powerdomain:power domain
- * timtype: idleReq_to_idleAck, idleAck_to_idle.....
- * tim_value: ack_to_tim, idle_to_tim......
- *****************************************************************************************/
- /* ack timeout value, lpi idleReq to idleAck */
- bool sysctl_pwr_get_ack_to_tim(volatile uint32_t *reg, uint32_t *ack_to_tim)
- {
- if((NULL == reg) || (NULL == ack_to_tim))
- return false;
- *ack_to_tim = ((*reg) >> 0) & 0x1F;
- return true;
- }
- /* idle timeout value, lpi idleAck to idle */
- bool sysctl_pwr_get_idle_to_tim(volatile uint32_t *reg, uint32_t *idle_to_tim)
- {
- if((NULL == reg) || (NULL == idle_to_tim))
- return false;
- *idle_to_tim = ((*reg) >> 8) & 0x1F;
- return true;
- }
- /* NOC power controller in idle min time, idle to idelReq(inactive) */
- bool sysctl_pwr_get_idle_hd_tim(volatile uint32_t *reg, uint32_t *idle_hd_tim)
- {
- if((NULL == reg) || (NULL == idle_hd_tim))
- return false;
- *idle_hd_tim = ((*reg) >> 16) & 0x3F;
- return true;
- }
- /*
- * After turning ISO on/off, you need to wait for a while to ensure that the
- * isolation cells in the power domain are actually enabled/disabled.
- */
- bool sysctl_pwr_get_iso_su_tim(volatile uint32_t *reg, uint32_t *iso_su_tim)
- {
- if((NULL == reg) || (NULL == iso_su_tim))
- return false;
- *iso_su_tim = ((*reg) >> 0) & 0xF;
- return true;
- }
- /*
- * After powering off a power domain, it takes some time to exit the power-off
- * state.
- */
- bool sysctl_pwr_get_pd_hd_tim(volatile uint32_t *reg, uint32_t *pd_hd_tim)
- {
- if((NULL == reg) || (NULL == pd_hd_tim))
- return false;
- *pd_hd_tim = ((*reg) >> 4) & 0xFF;
- return true;
- }
- /*
- * After restoring the power supply of a power domain (bringup), you need to
- * wait for a period of time to ensure that the power supply of the power domain
- * is fully restored.
- */
- bool sysctl_pwr_get_pwr_su_tim(volatile uint32_t *reg, uint32_t *pwr_su_tim)
- {
- if((NULL == reg) || (NULL == pwr_su_tim))
- return false;
- *pwr_su_tim = ((*reg) >> 12) & 0xFF;
- return true;
- }
- /* cpu1 wait for interrupt time */
- bool sysctl_pwr_get_wfi_tim(volatile uint32_t *reg, uint32_t *wfi_tim)
- {
- if((NULL == reg) || (NULL == wfi_tim))
- return false;
- *wfi_tim = (*reg >> 20) & 0xFFF;
- return true;
- }
- bool sysctl_pwr_get_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t *tim_value)
- {
- volatile uint32_t *pwr_reg = NULL;
- volatile uint32_t *lpi_reg = NULL;
- volatile uint32_t *wfi_reg = NULL;
- if((powerdomain >= SYSCTL_PD_MAX) || (timtype >= SYSCTL_PWR_MAX_TIM))
- return false;
- switch(powerdomain)
- {
- case SYSCTL_PD_CPU1:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_lpi_tim;
- wfi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
- break;
- }
- case SYSCTL_PD_AI:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->ai_lpi_tim;
- break;
- }
- case SYSCTL_PD_DISP:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->disp_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_tim;
- break;
- }
- case SYSCTL_PD_VPU:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_tim;
- break;
- }
- case SYSCTL_PD_DPU:
- {
- pwr_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_tim;
- lpi_reg = (volatile uint32_t *)&sysctl_pwr->dpu_lpi_tim;
- break;
- }
- default:
- return false;
- }
- switch(timtype)
- {
- case SYSCTL_PWR_ACK_TO_TIM:
- return sysctl_pwr_get_ack_to_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_IDLE_TO_TIM:
- return sysctl_pwr_get_idle_to_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_IDLE_HD_TIM:
- return sysctl_pwr_get_idle_hd_tim(pwr_reg, tim_value);
- case SYSCTL_PWR_ISO_SU_TIM:
- return sysctl_pwr_get_iso_su_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_PD_HD_TIM:
- return sysctl_pwr_get_pd_hd_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_SU_TIM:
- return sysctl_pwr_get_pwr_su_tim(lpi_reg, tim_value);
- case SYSCTL_PWR_WFI_TIM:
- return sysctl_pwr_get_wfi_tim(wfi_reg,tim_value);
- default:
- return false;
- }
- }
- /*****************************************************************************************
- * CPU1 KEEP RESET IN POWEROFF MODE
- * powerdomain: power domain
- * enable: poweron, keep reset; poweroff, remove reset
- *****************************************************************************************/
- /* It will not be powered off when not working and can be in a reset state */
- bool sysctl_pwr_set_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool enable)
- {
- volatile uint32_t ret;
- if(SYSCTL_PD_CPU1 == powerdomain)
- {
- ret = sysctl_pwr->cpu1_pwr_lpi_ctl;
- ret &= 0xfff7fff7;
- if(true == enable)
- {
- sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((1 << 3) | (1 << 19));
- }
- else
- {
- sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((0 << 3) | (1 << 19));
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- bool sysctl_pwr_get_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool *enable)
- {
- if(SYSCTL_PD_CPU1 == powerdomain)
- {
- if(sysctl_pwr->cpu1_pwr_lpi_ctl & (1 << 3))
- *enable = true;
- else
- *enable = false;
- return true;
- }
- else
- {
- return false;
- }
- }
- /*****************************************************************************************
- * CPU1 AUTO POWERUP OR POWERDOWN
- * powerdomain: power domain
- * enable: poweron, enable power control unit auto control mode; poweroff, disable auto
- *****************************************************************************************/
- /*
- * In MAIX3, CPU0 and CPU1 power domains support automatic power on and off
- * management.
- */
- bool sysctl_pwr_set_auto_pwr(sysctl_pwr_domain_e powerdomain, bool enable)
- {
- volatile uint32_t ret;
- if(SYSCTL_PD_CPU1 == powerdomain)
- {
- ret = sysctl_pwr->cpu1_pwr_lpi_ctl;
- ret &= 0xfffbfffb;
- if(true == enable)
- {
- sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((1 << 2) | (1 << 18));
- }
- else
- {
- sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((0 << 2) | (1 << 18));
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- bool sysctl_pwr_get_auto_pwr(sysctl_pwr_domain_e powerdomain, bool *enable)
- {
- if(SYSCTL_PD_CPU1 == powerdomain)
- {
- if(sysctl_pwr->cpu1_pwr_lpi_ctl & (1 << 2))
- *enable = true;
- else
- *enable = false;
- return true;
- }
- else
- {
- return false;
- }
- }
- /*****************************************************************************************
- * POWER DOMAIN REPAIR
- * powerdomain: power domain
- *****************************************************************************************/
- /* When powering up, set the power domain to repair */
- bool sysctl_pwr_set_repair_enable(sysctl_pwr_domain_e powerdomain)
- {
- switch(powerdomain)
- {
- case SYSCTL_PD_AI:
- sysctl_pwr->ai_pwr_lpi_ctl |= (1 << 4) | (1 << 20);
- return true;
- default:
- return false;
- }
- }
- bool sysctl_pwr_check_repair_done(sysctl_pwr_domain_e powerdomain)
- {
- switch(powerdomain)
- {
- case SYSCTL_PD_AI:
- return (sysctl_pwr->repair_status & (1 << 1)) ? true:false;
- case SYSCTL_PD_MAX:
- return (sysctl_pwr->repair_status & (1 << 2)) ? true:false;
- default:
- return false;
- }
- }
- /*****************************************************************************************
- * NOC POWER CONTROLLER
- * powerdomain: power domain
- * enable: true, connect noc, exit idle mode; false, disconnect noc, go idle mode.
- *****************************************************************************************/
- /*
- * Set different power domains to disconnect/connect to NOC and enter/leave
- * idle state.
- */
- bool sysctl_pwr_set_lpi(sysctl_pwr_domain_e powerdomain, bool enable)
- {
- switch(powerdomain)
- {
- case SYSCTL_PD_CPU1:
- {
- sysctl_pwr->cpu1_pwr_lpi_ctl |= (true == enable) ? ((1 << 5) | (1 << 21)) : ((1 << 4) | (1 << 20));
- /* usleep(500); */
- rt_thread_delay(1);
- if(true == enable)
- return (sysctl_pwr->cpu1_pwr_lpi_state & (1 << 3)) ? true:false;
- else
- return (sysctl_pwr->cpu1_pwr_lpi_state & (1 << 2)) ? true:false;
- }
- case SYSCTL_PD_AI:
- {
- sysctl_pwr->ai_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
- /* usleep(500); */
- rt_thread_delay(1);
- if(true == enable)
- return (sysctl_pwr->ai_pwr_lpi_state & (1 << 3)) ? true:false;
- else
- return (sysctl_pwr->ai_pwr_lpi_state & (1 << 2)) ? true:false;
- }
- case SYSCTL_PD_DISP:
- {
- sysctl_pwr->disp_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
- /* usleep(500); */
- rt_thread_delay(1);
- if(true == enable)
- return (sysctl_pwr->disp_lpi_state & (1 << 3)) ? true:false;
- else
- return (sysctl_pwr->disp_lpi_state & (1 << 2)) ? true:false;
- }
- case SYSCTL_PD_VPU:
- {
- sysctl_pwr->vpu_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
- /* usleep(500); */
- rt_thread_delay(1);
- if(true == enable)
- return (sysctl_pwr->vpu_lpi_state & (1 << 3)) ? true:false;
- else
- return (sysctl_pwr->vpu_lpi_state & (1 << 2)) ? true:false;
- }
- case SYSCTL_PD_DPU:
- {
- sysctl_pwr->dpu_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
- /* usleep(500); */
- rt_thread_delay(1);
- if(true == enable)
- return (sysctl_pwr->dpu_pwr_lpi_state & (1 << 3)) ? true:false;
- else
- return (sysctl_pwr->dpu_pwr_lpi_state & (1 << 2)) ? true:false;
- }
- default:
- return false;
- }
- }
- /*****************************************************************************************
- * POWER DOMAIN ON OR OFF
- * powerdomain: power domain
- * enable: true for powerup, false for poweroff.
- *****************************************************************************************/
- bool sysctl_pwr_set_pwr_reg(volatile uint32_t *regctl, volatile uint32_t *regsta, bool enable)
- {
- /* enable==true, power on; enable==false, power off */
- uint32_t mask;
- mask = enable ? 0x2 : 0x1;
- if (*regsta & mask)
- return true;
- *regctl = (0x30000 | mask);
- for (int i = 0; i < 100; i++)
- {
- if (*regsta & mask)
- return true;
- for (int j = 0; j < 5000; j++);
- }
- return false;
- }
- bool sysctl_pwr_set_power(sysctl_pwr_domain_e powerdomain, bool enable)
- {
- volatile uint32_t *pwr_ctl_reg = NULL;
- volatile uint32_t *pwr_sta_reg = NULL;
- switch(powerdomain)
- {
- case SYSCTL_PD_CPU1:
- {
- pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_lpi_ctl;
- pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_lpi_state;
- break;
- }
- case SYSCTL_PD_AI:
- {
- pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_lpi_ctl;
- pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_lpi_state;
- break;
- }
- case SYSCTL_PD_DISP:
- {
- pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_ctl;
- pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_state;
- break;
- }
- case SYSCTL_PD_VPU:
- {
- pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_lpi_ctl;
- pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_state;
- break;
- }
- case SYSCTL_PD_DPU:
- {
- pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_lpi_ctl;
- pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_lpi_state;
- break;
- }
- default:
- return false;
- }
- /* repair powerdomain */
- /* only powerup need repair */
- if(true == enable)
- {
- (void)sysctl_pwr_set_repair_enable(powerdomain);
- }
- return sysctl_pwr_set_pwr_reg(pwr_ctl_reg, pwr_sta_reg, enable);
- }
- bool sysctl_pwr_set_power_multi(sysctl_pwr_domain_e powerdomain, bool enable)
- {
- bool ret = true;
- rt_base_t level;
- static uint32_t ref_count[SYSCTL_PD_MAX];
- /*
- 1. enable step for non-DISP power domains:
- a. disable interrupt
- b. judge ref_count, if == 0, execute sysctl_pwr_set_pwr_reg
- c. ref_count++, limit UINT32_MAX
- d. enable interrupt
- 2. disable step for non-DISP power domains:
- a. disable interrupt
- b. judge ref_count, if == 0, go step d
- c. ref_count--, judge ref_count, if == 0, execute sysctl_pwr_set_pwr_reg
- d. enable interrupt
- 3. enable step for DISP power domains:
- a. disable interrupt
- b. judge ref_count, if == 0, execute
- b.1 get HARDLOCK_DISP
- b.2 get HARDLOCK_DISP_CPU1
- b.3 execute sysctl_pwr_set_pwr_reg
- b.4 put HARDLOCK_DISP
- c. ref_count++, limit UINT32_MAX
- d. enable interrupt
- 4. disable step for DISP power domains:
- a. disable interrupt
- b. judge ref_count, if == 0, go step e
- c. ref_count--, judge ref_count, if == 0, execute
- c.1 get HARDLOCK_DISP
- c.2 qeury HARDLOCK_DISP_CPU0, if no get, go step c.4
- c.3 put HARDLOCK_DISP_CPU0, execute sysctl_pwr_set_pwr_reg
- c.4 put HARDLOCK_DISP_CPU1
- c.5 put HARDLOCK_DISP
- d. enable interrupt
- */
- level = rt_hw_interrupt_disable();
- if (enable == true)
- {
- if (ref_count[powerdomain] == 0)
- {
- if (powerdomain == SYSCTL_PD_DISP)
- {
- while (kd_hardlock_lock(HARDLOCK_DISP));
- kd_hardlock_lock(HARDLOCK_DISP_CPU1);
- ret = sysctl_pwr_set_power(powerdomain, enable);
- kd_hardlock_unlock(HARDLOCK_DISP);
- } else {
- ret = sysctl_pwr_set_power(powerdomain, enable);
- }
- }
- ref_count[powerdomain]++;
- if (ref_count[powerdomain] == UINT32_MAX)
- rt_kprintf("error: enable too many times\n");
- } else if (ref_count[powerdomain])
- {
- ref_count[powerdomain]--;
- if (ref_count[powerdomain] == 0)
- {
- if (powerdomain == SYSCTL_PD_DISP)
- {
- while (kd_hardlock_lock(HARDLOCK_DISP));
- if (kd_hardlock_lock(HARDLOCK_DISP_CPU0) == 0)
- {
- kd_hardlock_unlock(HARDLOCK_DISP_CPU0);
- ret = sysctl_pwr_set_power(powerdomain, enable);
- }
- kd_hardlock_unlock(HARDLOCK_DISP_CPU1);
- kd_hardlock_unlock(HARDLOCK_DISP);
- } else {
- ret = sysctl_pwr_set_power(powerdomain, enable);
- }
- }
- }
- rt_hw_interrupt_enable(level);
- return ret;
- }
- /* Power Domain Power-up */
- bool sysctl_pwr_up(sysctl_pwr_domain_e powerdomain)
- {
- return sysctl_pwr_set_power_multi(powerdomain, true);
- }
- /* Power off a power domain */
- bool sysctl_pwr_off(sysctl_pwr_domain_e powerdomain)
- {
- return sysctl_pwr_set_power_multi(powerdomain, false);
- }
- int rt_hw_sysctl_pwr_init(void)
- {
- sysctl_pwr = rt_ioremap((void*)PWR_BASE_ADDR, PWR_IO_SIZE);
- if(!sysctl_pwr)
- {
- rt_kprintf("sysctl_pwr ioremap error\n");
- return -1;
- }
- return 0;
- }
- INIT_BOARD_EXPORT(rt_hw_sysctl_pwr_init);
|